@bojackduy/opencode-loopd 1.9.2 → 1.9.3

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.
Files changed (3) hide show
  1. package/dist/server.js +174 -11
  2. package/dist/tui.js +307 -225
  3. package/package.json +4 -4
package/dist/server.js CHANGED
@@ -1,4 +1,16 @@
1
1
  // @bun
2
+ var __esm = (fn, res, err) => () => {
3
+ if (fn)
4
+ try {
5
+ res = fn(fn = 0);
6
+ } catch (e) {
7
+ err = [e];
8
+ }
9
+ if (err)
10
+ throw err[0];
11
+ return res;
12
+ };
13
+
2
14
  // src/domain/runtime.ts
3
15
  function createRuntimeState(goalID) {
4
16
  const now = new Date().toISOString();
@@ -113,14 +125,10 @@ function removeToolCall(rt, callID) {
113
125
  }
114
126
  var PARENT_NOTIFY_DEDUPE_MS = 60000;
115
127
 
116
- // src/application/control-worker.ts
117
- import { randomUUID } from "crypto";
118
-
119
128
  // src/infrastructure/state-repository.ts
120
129
  import { promises as fs } from "fs";
121
130
  import path from "path";
122
131
  import os from "os";
123
- var CURRENT_VERSION = 6;
124
132
  function emptyState() {
125
133
  return { version: CURRENT_VERSION, revision: 0, goals: [], runtimes: [], commandLedger: [] };
126
134
  }
@@ -140,7 +148,6 @@ function lockDir(directory) {
140
148
  function lockFile(directory, key) {
141
149
  return path.join(lockDir(directory), `${key}.lock`);
142
150
  }
143
- var LOCK_STALE_MS = 1e4;
144
151
  async function acquireLock(directory, key, operation) {
145
152
  const dir = lockDir(directory);
146
153
  await fs.mkdir(dir, { recursive: true });
@@ -476,6 +483,15 @@ async function peekGoalInbox(directory, goalID) {
476
483
  function delay(ms) {
477
484
  return new Promise((resolve) => setTimeout(resolve, ms));
478
485
  }
486
+ var CURRENT_VERSION = 6, LOCK_STALE_MS = 1e4;
487
+ var init_state_repository = () => {};
488
+
489
+ // src/server/plugin.ts
490
+ import { define } from "@opencode-ai/plugin/v2/promise";
491
+
492
+ // src/application/control-worker.ts
493
+ init_state_repository();
494
+ import { randomUUID } from "crypto";
479
495
 
480
496
  // src/application/goal-policy.ts
481
497
  function resolveGoalCreationConfig(input) {
@@ -932,6 +948,7 @@ function createControlWorker(options) {
932
948
  }
933
949
 
934
950
  // src/application/loop-engine.ts
951
+ init_state_repository();
935
952
  import { randomUUID as randomUUID2 } from "crypto";
936
953
 
937
954
  // src/domain/goal.ts
@@ -1871,6 +1888,7 @@ function createLoopEngine(options) {
1871
1888
 
1872
1889
  // src/application/goal-service.ts
1873
1890
  import { randomUUID as randomUUID3 } from "crypto";
1891
+ init_state_repository();
1874
1892
  import * as path2 from "path";
1875
1893
  import { promises as fs2 } from "fs";
1876
1894
 
@@ -2975,6 +2993,7 @@ function createGoalService(host) {
2975
2993
  }
2976
2994
 
2977
2995
  // src/application/schedule-worker.ts
2996
+ init_state_repository();
2978
2997
  import { randomUUID as randomUUID4 } from "crypto";
2979
2998
  function createScheduleWorker(options) {
2980
2999
  const { directory, goalService } = options;
@@ -3089,6 +3108,7 @@ function createScheduleWorker(options) {
3089
3108
  }
3090
3109
 
3091
3110
  // src/server/goal-tools.ts
3111
+ init_state_repository();
3092
3112
  import { randomUUID as randomUUID5 } from "crypto";
3093
3113
  import { tool } from "@opencode-ai/plugin/tool";
3094
3114
  // src/domain/verification.ts
@@ -3666,6 +3686,7 @@ async function runCompletionChecks(checks, cwd) {
3666
3686
  }
3667
3687
 
3668
3688
  // src/server/owner-tools.ts
3689
+ init_state_repository();
3669
3690
  import { tool as tool2 } from "@opencode-ai/plugin/tool";
3670
3691
  import { promises as fs3 } from "fs";
3671
3692
  function withTimeout2(promise, ms) {
@@ -3893,7 +3914,7 @@ function ownerTools(options) {
3893
3914
  }
3894
3915
  }),
3895
3916
  send_goal_input: tool2({
3896
- description: "Send an inbox message to the worker (injected as ## USER INSTRUCTIONS on next turn). Use to answer `question`, redirect, or refine scope. Does NOT itself re-prompt \u2014 the engine re-prompts on next idle/maintenance; use nudge_goal if the worker is stuck with no activity.",
3917
+ description: "Send bare words to the worker as their own turn (no steering wrapper). Delivers immediately if the goal is active, otherwise queues for the next active turn. Use to answer `question`, redirect, or nudge with a short message.",
3897
3918
  args: {
3898
3919
  goal_id: tool2.schema.string().optional().describe("Goal ID. Omit to target the first active goal."),
3899
3920
  message: tool2.schema.string().describe("Message to send to the worker.")
@@ -3908,14 +3929,14 @@ function ownerTools(options) {
3908
3929
  output: JSON.stringify({ ok: false, message: "No matching active goal for this session." })
3909
3930
  };
3910
3931
  }
3911
- await appendGoalInbox(directory, goal.id, "user", args.message);
3932
+ const result = await goalService.sendUserMessage(directory, goal.id, args.message);
3912
3933
  return {
3913
- title: "Message sent",
3934
+ title: result.ok ? "Message sent" : "Send failed",
3914
3935
  output: JSON.stringify({
3915
- ok: true,
3936
+ ok: result.ok,
3916
3937
  goalID: goal.id,
3917
3938
  goalName: goal.name,
3918
- message: `Message delivered to "${goal.name}". It will appear in the worker's next turn.`
3939
+ message: result.message
3919
3940
  })
3920
3941
  };
3921
3942
  }
@@ -4048,6 +4069,141 @@ function ownerTools(options) {
4048
4069
  }
4049
4070
  }
4050
4071
  }),
4072
+ abort_goal_worker: tool2({
4073
+ description: "Abort the worker session only (N / :abort in TUI). Keeps goal+transcript+session browsable, clears the run lease. Use for compaction-spin or stuck runs. Status unchanged; active goals resume next turn in the same session.",
4074
+ args: {
4075
+ goal_id: tool2.schema.string().optional().describe("Goal ID. Omit to abort the first active goal.")
4076
+ },
4077
+ execute: async (args, context) => {
4078
+ const state = await readState(directory);
4079
+ const ownerID = context?.sessionID;
4080
+ const goal = args.goal_id ? state.goals.find((g) => g.id === args.goal_id && g.ownerSessionID === ownerID) : state.goals.find((g) => g.ownerSessionID === ownerID && g.status !== "complete");
4081
+ if (!goal) {
4082
+ return {
4083
+ title: "No goal found",
4084
+ output: JSON.stringify({ ok: false, message: "No matching active goal for this session." })
4085
+ };
4086
+ }
4087
+ try {
4088
+ const result = await goalService.abortWorker(directory, goal.id);
4089
+ return {
4090
+ title: result.ok ? "Worker aborted" : "Abort failed",
4091
+ output: JSON.stringify({ ...result, goalID: goal.id, goalName: goal.name })
4092
+ };
4093
+ } catch (error) {
4094
+ return {
4095
+ title: "Abort failed",
4096
+ output: JSON.stringify({
4097
+ ok: false,
4098
+ goalName: goal.name,
4099
+ message: error instanceof Error ? error.message : String(error)
4100
+ })
4101
+ };
4102
+ }
4103
+ }
4104
+ }),
4105
+ force_complete_goal: tool2({
4106
+ description: "Force-complete a goal with summary/evidence, bypassing checks (:force in TUI). Use when the worker produced the right artifact but checks are stale or you have verified manually.",
4107
+ args: {
4108
+ goal_id: tool2.schema.string().optional().describe("Goal ID. Omit to target the first non-complete goal."),
4109
+ summary: tool2.schema.string().describe("What was completed."),
4110
+ evidence: tool2.schema.string().describe("Concrete evidence of completion.")
4111
+ },
4112
+ execute: async (args, context) => {
4113
+ const state = await readState(directory);
4114
+ const ownerID = context?.sessionID;
4115
+ const goal = args.goal_id ? state.goals.find((g) => g.id === args.goal_id && g.ownerSessionID === ownerID) : state.goals.find((g) => g.ownerSessionID === ownerID && g.status !== "complete");
4116
+ if (!goal) {
4117
+ return {
4118
+ title: "No goal found",
4119
+ output: JSON.stringify({ ok: false, message: "No matching active goal for this session." })
4120
+ };
4121
+ }
4122
+ await Promise.resolve().then(() => init_state_repository());
4123
+ await Promise.resolve();
4124
+ const { randomUUID } = await import("crypto");
4125
+ const st = await readState(directory);
4126
+ const g = st.goals.find((x) => x.id === goal.id);
4127
+ if (!g)
4128
+ return { title: "No goal", output: JSON.stringify({ ok: false, message: "Goal not found." }) };
4129
+ if (g.status === "complete") {
4130
+ return { title: "Already complete", output: JSON.stringify({ ok: true, message: `Goal "${g.name}" already complete.` }) };
4131
+ }
4132
+ g.status = "complete";
4133
+ g.updatedAt = new Date().toISOString();
4134
+ g.completionEvidence = { summary: args.summary, evidence: args.evidence, at: new Date().toISOString() };
4135
+ const rt = st.runtimes.find((r) => r.goalID === goal.id);
4136
+ if (rt) {
4137
+ Object.assign(rt, releaseLease(rt));
4138
+ rt.activeRunID = undefined;
4139
+ rt.lastError = undefined;
4140
+ rt.updatedAt = new Date().toISOString();
4141
+ }
4142
+ await writeState(directory, st);
4143
+ await appendEvent(directory, {
4144
+ version: 1,
4145
+ eventID: randomUUID(),
4146
+ goalID: goal.id,
4147
+ type: "goal.completed",
4148
+ summary: args.summary,
4149
+ evidence: args.evidence,
4150
+ timestamp: new Date().toISOString(),
4151
+ revision: st.revision
4152
+ });
4153
+ return { title: "Goal force-completed", output: JSON.stringify({ ok: true, goalID: goal.id, goalName: g.name }) };
4154
+ }
4155
+ }),
4156
+ force_block_goal: tool2({
4157
+ description: "Force-block a goal with reason/needed (:block in TUI). Use when the goal is stuck on an external blocker and should stop retrying.",
4158
+ args: {
4159
+ goal_id: tool2.schema.string().optional().describe("Goal ID. Omit to target the first non-complete goal."),
4160
+ reason: tool2.schema.string().describe("Why the goal is blocked."),
4161
+ needed: tool2.schema.string().describe("What is needed to unblock.")
4162
+ },
4163
+ execute: async (args, context) => {
4164
+ const state = await readState(directory);
4165
+ const ownerID = context?.sessionID;
4166
+ const goal = args.goal_id ? state.goals.find((g) => g.id === args.goal_id && g.ownerSessionID === ownerID) : state.goals.find((g) => g.ownerSessionID === ownerID && g.status !== "complete");
4167
+ if (!goal) {
4168
+ return {
4169
+ title: "No goal found",
4170
+ output: JSON.stringify({ ok: false, message: "No matching active goal for this session." })
4171
+ };
4172
+ }
4173
+ await Promise.resolve().then(() => init_state_repository());
4174
+ await Promise.resolve();
4175
+ const { randomUUID } = await import("crypto");
4176
+ const st = await readState(directory);
4177
+ const g = st.goals.find((x) => x.id === goal.id);
4178
+ if (!g)
4179
+ return { title: "No goal", output: JSON.stringify({ ok: false, message: "Goal not found." }) };
4180
+ if (g.status === "blocked") {
4181
+ return { title: "Already blocked", output: JSON.stringify({ ok: true, message: `Goal "${g.name}" already blocked.` }) };
4182
+ }
4183
+ g.status = "blocked";
4184
+ g.updatedAt = new Date().toISOString();
4185
+ g.blocker = { reason: args.reason, needed: args.needed, at: new Date().toISOString() };
4186
+ const rt = st.runtimes.find((r) => r.goalID === goal.id);
4187
+ if (rt) {
4188
+ Object.assign(rt, releaseLease(rt));
4189
+ rt.activeRunID = undefined;
4190
+ rt.lastError = undefined;
4191
+ rt.updatedAt = new Date().toISOString();
4192
+ }
4193
+ await writeState(directory, st);
4194
+ await appendEvent(directory, {
4195
+ version: 1,
4196
+ eventID: randomUUID(),
4197
+ goalID: goal.id,
4198
+ type: "goal.blocked",
4199
+ reason: args.reason,
4200
+ needed: args.needed,
4201
+ timestamp: new Date().toISOString(),
4202
+ revision: st.revision
4203
+ });
4204
+ return { title: "Goal blocked", output: JSON.stringify({ ok: true, goalID: goal.id, goalName: g.name }) };
4205
+ }
4206
+ }),
4051
4207
  clear_goal: tool2({
4052
4208
  description: "Clear a goal: aborts worker and removes goal+runtime+ledger (cannot be undone). Use when the goal is no longer needed or to free a stuck writer slot after inspection.",
4053
4209
  args: {
@@ -4088,7 +4244,9 @@ function ownerTools(options) {
4088
4244
  })
4089
4245
  };
4090
4246
  }
4247
+
4091
4248
  // src/server/plugin.ts
4249
+ init_state_repository();
4092
4250
  var PLUGIN_ID = "opencode-loopd.server";
4093
4251
  var server = async ({ client, directory }, pluginOptions) => {
4094
4252
  const defaults = parsePluginDefaults(pluginOptions);
@@ -4232,9 +4390,14 @@ function parsePluginDefaults(options) {
4232
4390
  defaultChecks: checks.length > 0 ? checks : undefined
4233
4391
  };
4234
4392
  }
4393
+ var v2 = define({
4394
+ id: PLUGIN_ID,
4395
+ async setup() {}
4396
+ });
4235
4397
  var plugin_default = {
4236
4398
  id: PLUGIN_ID,
4237
- server
4399
+ server,
4400
+ setup: v2.setup
4238
4401
  };
4239
4402
  export {
4240
4403
  plugin_default as default
package/dist/tui.js CHANGED
@@ -643,6 +643,7 @@ function LoopDashboard(props) {
643
643
  const [clock, setClock] = createSignal(Date.now());
644
644
  const [agentIndex, setAgentIndex] = createSignal({});
645
645
  let inputEl;
646
+ let listScrollRef;
646
647
  let focusTimer;
647
648
  const client = createControlClient(props.directory);
648
649
  const popMode = props.api.mode.push("loopd.dashboard");
@@ -1084,6 +1085,7 @@ function LoopDashboard(props) {
1084
1085
  returnToNormalMode();
1085
1086
  }
1086
1087
  const activeGoals = () => state()?.goals.filter((g) => showCompleted() || g.status !== "complete") || [];
1088
+ const listHeight = () => Math.min(activeGoals().length, 10);
1087
1089
  const runningCount = () => state()?.runtimes.filter((runtime) => runtime.phase === "running").length || 0;
1088
1090
  const runningFrame = () => ["|", "/", "-", "\\"][Math.floor(clock() / 500) % 4];
1089
1091
  function handleBugReport() {
@@ -1097,8 +1099,20 @@ function LoopDashboard(props) {
1097
1099
  setStatusText(res.status === "opened" ? "Opening bug report in browser\u2026" : `Could not open browser: ${res.reason} \u2014 ${url}`);
1098
1100
  }
1099
1101
  createEffect(() => setSelectedGoal(activeGoals()[selected()] || null));
1102
+ function rowIdFor(goalID) {
1103
+ return `loopd-goal-${goalID}`;
1104
+ }
1105
+ createEffect(() => {
1106
+ const goals = activeGoals();
1107
+ const goal = goals[selected()];
1108
+ if (!goal || !listScrollRef)
1109
+ return;
1110
+ try {
1111
+ listScrollRef.scrollChildIntoView(rowIdFor(goal.id));
1112
+ } catch {}
1113
+ });
1100
1114
  return (() => {
1101
- var _el$ = _$createElement("box"), _el$2 = _$createElement("box"), _el$3 = _$createElement("box"), _el$4 = _$createElement("text"), _el$5 = _$createElement("span"), _el$7 = _$createElement("span"), _el$9 = _$createElement("span"), _el$0 = _$createTextNode(` `), _el$1 = _$createTextNode(` `), _el$10 = _$createElement("span"), _el$12 = _$createElement("span"), _el$13 = _$createElement("span"), _el$15 = _$createElement("span"), _el$17 = _$createElement("span"), _el$18 = _$createTextNode(` `), _el$19 = _$createTextNode(` running`), _el$20 = _$createElement("span"), _el$22 = _$createElement("span"), _el$24 = _$createElement("span"), _el$25 = _$createElement("span"), _el$27 = _$createElement("box"), _el$28 = _$createElement("text"), _el$29 = _$createElement("span"), _el$31 = _$createElement("box"), _el$36 = _$createElement("box"), _el$43 = _$createElement("box"), _el$44 = _$createElement("text"), _el$45 = _$createElement("span"), _el$46 = _$createElement("input");
1115
+ var _el$ = _$createElement("box"), _el$2 = _$createElement("box"), _el$3 = _$createElement("box"), _el$4 = _$createElement("text"), _el$5 = _$createElement("span"), _el$7 = _$createElement("span"), _el$9 = _$createElement("span"), _el$0 = _$createTextNode(` `), _el$1 = _$createTextNode(` `), _el$10 = _$createElement("span"), _el$12 = _$createElement("span"), _el$13 = _$createElement("span"), _el$15 = _$createElement("span"), _el$17 = _$createElement("span"), _el$18 = _$createTextNode(` `), _el$19 = _$createTextNode(` running`), _el$20 = _$createElement("span"), _el$22 = _$createElement("span"), _el$24 = _$createElement("span"), _el$25 = _$createElement("span"), _el$27 = _$createElement("box"), _el$28 = _$createElement("text"), _el$29 = _$createElement("span"), _el$31 = _$createElement("box"), _el$43 = _$createElement("box"), _el$44 = _$createElement("text"), _el$45 = _$createElement("span"), _el$46 = _$createElement("input");
1102
1116
  _$insertNode(_el$, _el$2);
1103
1117
  _$setProp(_el$, "flexDirection", "column");
1104
1118
  _$setProp(_el$, "width", "100%");
@@ -1170,9 +1184,8 @@ function LoopDashboard(props) {
1170
1184
  fg: "white",
1171
1185
  bold: true
1172
1186
  });
1173
- _$insertNode(_el$31, _el$36);
1174
1187
  _$setProp(_el$31, "flexDirection", "column");
1175
- _$setProp(_el$31, "flexGrow", 1);
1188
+ _$setProp(_el$31, "flexShrink", 1);
1176
1189
  _$setProp(_el$31, "minHeight", 0);
1177
1190
  _$setProp(_el$31, "overflow", "hidden");
1178
1191
  _$insert(_el$31, _$createComponent(Show, {
@@ -1341,13 +1354,8 @@ function LoopDashboard(props) {
1341
1354
  _$effect((_$p) => _$setProp(_el$32, "backgroundColor", theme().background, _$p));
1342
1355
  return _el$32;
1343
1356
  }
1344
- }), _el$36);
1345
- _$setProp(_el$36, "flexDirection", "column");
1346
- _$setProp(_el$36, "flexGrow", 1);
1347
- _$setProp(_el$36, "padding", 1);
1348
- _$setProp(_el$36, "minHeight", 0);
1349
- _$setProp(_el$36, "overflow", "hidden");
1350
- _$insert(_el$36, _$createComponent(Show, {
1357
+ }), null);
1358
+ _$insert(_el$31, _$createComponent(Show, {
1351
1359
  get when() {
1352
1360
  return activeGoals().length > 0;
1353
1361
  },
@@ -1358,6 +1366,7 @@ function LoopDashboard(props) {
1358
1366
  _$insertNode(_el$67, _el$75);
1359
1367
  _$setProp(_el$67, "flexDirection", "column");
1360
1368
  _$setProp(_el$67, "gap", 1);
1369
+ _$setProp(_el$67, "padding", 1);
1361
1370
  _$insertNode(_el$68, _el$69);
1362
1371
  _$insertNode(_el$68, _el$71);
1363
1372
  _$insertNode(_el$68, _el$73);
@@ -1427,7 +1436,11 @@ function LoopDashboard(props) {
1427
1436
  })();
1428
1437
  },
1429
1438
  get children() {
1430
- return _$createComponent(For, {
1439
+ var _el$36 = _$createElement("scrollbox");
1440
+ _$use((el) => {
1441
+ listScrollRef = el;
1442
+ }, _el$36);
1443
+ _$insert(_el$36, _$createComponent(For, {
1431
1444
  get each() {
1432
1445
  return activeGoals();
1433
1446
  },
@@ -1454,6 +1467,8 @@ function LoopDashboard(props) {
1454
1467
  _$insertNode(_el$91, _el$92);
1455
1468
  _$insertNode(_el$91, _el$93);
1456
1469
  _$insertNode(_el$91, _el$95);
1470
+ _$setProp(_el$91, "wrapMode", "none");
1471
+ _$setProp(_el$91, "truncate", true);
1457
1472
  _$insert(_el$92, (() => {
1458
1473
  var _c$2 = _$memo(() => !!isActive());
1459
1474
  return () => _c$2() ? `\u25B6 ${statusIcon(goal.status)} ${goal.name}` : ` ${statusIcon(goal.status)} ${goal.name}`;
@@ -1591,32 +1606,36 @@ function LoopDashboard(props) {
1591
1606
  })();
1592
1607
  })(), null);
1593
1608
  _$effect((_p$) => {
1594
- var _v$32 = isActive() ? theme().backgroundElement : undefined, _v$33 = {
1609
+ var _v$32 = rowIdFor(goal.id), _v$33 = isActive() ? theme().backgroundElement : undefined, _v$34 = {
1595
1610
  fg: statusColor(goal.status, theme()),
1596
1611
  bold: isActive()
1597
- }, _v$34 = {
1598
- fg: theme().textMuted
1599
1612
  }, _v$35 = {
1613
+ fg: theme().textMuted
1614
+ }, _v$36 = {
1600
1615
  fg: statusColor(goal.status, theme()),
1601
1616
  bold: true
1602
1617
  };
1603
- _v$32 !== _p$.e && (_p$.e = _$setProp(_el$90, "backgroundColor", _v$32, _p$.e));
1604
- _v$33 !== _p$.t && (_p$.t = _$setProp(_el$92, "style", _v$33, _p$.t));
1605
- _v$34 !== _p$.a && (_p$.a = _$setProp(_el$93, "style", _v$34, _p$.a));
1606
- _v$35 !== _p$.o && (_p$.o = _$setProp(_el$95, "style", _v$35, _p$.o));
1618
+ _v$32 !== _p$.e && (_p$.e = _$setProp(_el$90, "id", _v$32, _p$.e));
1619
+ _v$33 !== _p$.t && (_p$.t = _$setProp(_el$90, "backgroundColor", _v$33, _p$.t));
1620
+ _v$34 !== _p$.a && (_p$.a = _$setProp(_el$92, "style", _v$34, _p$.a));
1621
+ _v$35 !== _p$.o && (_p$.o = _$setProp(_el$93, "style", _v$35, _p$.o));
1622
+ _v$36 !== _p$.i && (_p$.i = _$setProp(_el$95, "style", _v$36, _p$.i));
1607
1623
  return _p$;
1608
1624
  }, {
1609
1625
  e: undefined,
1610
1626
  t: undefined,
1611
1627
  a: undefined,
1612
- o: undefined
1628
+ o: undefined,
1629
+ i: undefined
1613
1630
  });
1614
1631
  return _el$90;
1615
1632
  })();
1616
1633
  }
1617
- });
1634
+ }));
1635
+ _$effect((_$p) => _$setProp(_el$36, "height", listHeight(), _$p));
1636
+ return _el$36;
1618
1637
  }
1619
- }));
1638
+ }), null);
1620
1639
  _$insert(_el$31, _$createComponent(Show, {
1621
1640
  get when() {
1622
1641
  return selectedGoal();
@@ -1627,7 +1646,7 @@ function LoopDashboard(props) {
1627
1646
  const blk = () => goal().blocker;
1628
1647
  return (() => {
1629
1648
  var _el$121 = _$createElement("box"), _el$122 = _$createElement("text"), _el$123 = _$createElement("span"), _el$124 = _$createTextNode(` `), _el$125 = _$createElement("span"), _el$126 = _$createTextNode(` `), _el$127 = _$createTextNode(`
1630
- `), _el$128 = _$createElement("span");
1649
+ `), _el$128 = _$createElement("span"), _el$130 = _$createElement("span");
1631
1650
  _$insertNode(_el$121, _el$122);
1632
1651
  _$setProp(_el$121, "flexDirection", "column");
1633
1652
  _$setProp(_el$121, "border", true);
@@ -1638,6 +1657,7 @@ function LoopDashboard(props) {
1638
1657
  _$insertNode(_el$122, _el$125);
1639
1658
  _$insertNode(_el$122, _el$127);
1640
1659
  _$insertNode(_el$122, _el$128);
1660
+ _$insertNode(_el$122, _el$130);
1641
1661
  _$insertNode(_el$123, _el$124);
1642
1662
  _$insert(_el$123, () => statusIcon(goal().status), _el$124);
1643
1663
  _$insert(_el$123, () => goal().name, null);
@@ -1646,53 +1666,53 @@ function LoopDashboard(props) {
1646
1666
  _$insert(_el$122, (() => {
1647
1667
  var _c$10 = _$memo(() => !!rt());
1648
1668
  return () => _c$10() && [(() => {
1649
- var _el$129 = _$createElement("span");
1650
- _$insertNode(_el$129, _$createTextNode(` \u2502 `));
1651
- _$effect((_$p) => _$setProp(_el$129, "style", {
1669
+ var _el$131 = _$createElement("span");
1670
+ _$insertNode(_el$131, _$createTextNode(` \u2502 `));
1671
+ _$effect((_$p) => _$setProp(_el$131, "style", {
1652
1672
  fg: theme().textMuted
1653
1673
  }, _$p));
1654
- return _el$129;
1674
+ return _el$131;
1655
1675
  })(), (() => {
1656
- var _el$131 = _$createElement("span"), _el$132 = _$createTextNode(` `);
1657
- _$insertNode(_el$131, _el$132);
1658
- _$insert(_el$131, () => phaseIcon(rt().phase), _el$132);
1659
- _$insert(_el$131, () => rt().phase, null);
1660
- _$effect((_$p) => _$setProp(_el$131, "style", {
1676
+ var _el$133 = _$createElement("span"), _el$134 = _$createTextNode(` `);
1677
+ _$insertNode(_el$133, _el$134);
1678
+ _$insert(_el$133, () => phaseIcon(rt().phase), _el$134);
1679
+ _$insert(_el$133, () => rt().phase, null);
1680
+ _$effect((_$p) => _$setProp(_el$133, "style", {
1661
1681
  fg: phaseColor(rt().phase, theme()),
1662
1682
  bold: true
1663
1683
  }, _$p));
1664
- return _el$131;
1684
+ return _el$133;
1665
1685
  })(), (() => {
1666
- var _el$133 = _$createElement("span"), _el$134 = _$createTextNode(` run `), _el$135 = _$createTextNode(` (budget `), _el$136 = _$createTextNode(`)`);
1667
- _$insertNode(_el$133, _el$134);
1668
- _$insertNode(_el$133, _el$135);
1669
- _$insertNode(_el$133, _el$136);
1670
- _$insert(_el$133, () => rt().runCount, _el$135);
1671
- _$insert(_el$133, () => rt().budgetTurnCount, _el$136);
1672
- _$effect((_$p) => _$setProp(_el$133, "style", {
1686
+ var _el$135 = _$createElement("span"), _el$136 = _$createTextNode(` run `), _el$137 = _$createTextNode(` (budget `), _el$138 = _$createTextNode(`)`);
1687
+ _$insertNode(_el$135, _el$136);
1688
+ _$insertNode(_el$135, _el$137);
1689
+ _$insertNode(_el$135, _el$138);
1690
+ _$insert(_el$135, () => rt().runCount, _el$137);
1691
+ _$insert(_el$135, () => rt().budgetTurnCount, _el$138);
1692
+ _$effect((_$p) => _$setProp(_el$135, "style", {
1673
1693
  fg: theme().textMuted
1674
1694
  }, _$p));
1675
- return _el$133;
1695
+ return _el$135;
1676
1696
  })()];
1677
1697
  })(), _el$127);
1678
1698
  _$insert(_el$122, (() => {
1679
1699
  var _c$11 = _$memo(() => !!rt()?.workerAbortedAt);
1680
1700
  return () => _c$11() && [(() => {
1681
- var _el$137 = _$createElement("span");
1682
- _$insertNode(_el$137, _$createTextNode(` \u2502 \u26A0 worker aborted `));
1683
- _$effect((_$p) => _$setProp(_el$137, "style", {
1701
+ var _el$139 = _$createElement("span");
1702
+ _$insertNode(_el$139, _$createTextNode(` \u2502 \u26A0 worker aborted `));
1703
+ _$effect((_$p) => _$setProp(_el$139, "style", {
1684
1704
  fg: theme().warning,
1685
1705
  bold: true
1686
1706
  }, _$p));
1687
- return _el$137;
1707
+ return _el$139;
1688
1708
  })(), (() => {
1689
- var _el$139 = _$createElement("span"), _el$140 = _$createTextNode(` \u2014 session kept, next turn reuses it`);
1690
- _$insertNode(_el$139, _el$140);
1691
- _$insert(_el$139, () => ageLabel(rt().workerAbortedAt, clock()), _el$140);
1692
- _$effect((_$p) => _$setProp(_el$139, "style", {
1709
+ var _el$141 = _$createElement("span"), _el$142 = _$createTextNode(` \u2014 session kept, next turn reuses it`);
1710
+ _$insertNode(_el$141, _el$142);
1711
+ _$insert(_el$141, () => ageLabel(rt().workerAbortedAt, clock()), _el$142);
1712
+ _$effect((_$p) => _$setProp(_el$141, "style", {
1693
1713
  fg: theme().textMuted
1694
1714
  }, _$p));
1695
- return _el$139;
1715
+ return _el$141;
1696
1716
  })()];
1697
1717
  })(), _el$127);
1698
1718
  _$insert(_el$122, () => {
@@ -1702,333 +1722,395 @@ function LoopDashboard(props) {
1702
1722
  const slash = model?.indexOf("/") ?? -1;
1703
1723
  return [`
1704
1724
  `, (() => {
1705
- var _el$141 = _$createElement("span");
1706
- _$insertNode(_el$141, _$createTextNode(`\uD83E\uDD16 `));
1707
- _$effect((_$p) => _$setProp(_el$141, "style", {
1725
+ var _el$143 = _$createElement("span");
1726
+ _$insertNode(_el$143, _$createTextNode(`\uD83E\uDD16 `));
1727
+ _$effect((_$p) => _$setProp(_el$143, "style", {
1708
1728
  fg: theme().textMuted
1709
1729
  }, _$p));
1710
- return _el$141;
1730
+ return _el$143;
1731
+ })(), (() => {
1732
+ var _el$145 = _$createElement("span");
1733
+ _$insertNode(_el$145, _$createTextNode(`Agent: `));
1734
+ _$effect((_$p) => _$setProp(_el$145, "style", {
1735
+ fg: theme().primary,
1736
+ bold: true
1737
+ }, _$p));
1738
+ return _el$145;
1711
1739
  })(), agentName ? [(() => {
1712
- var _el$153 = _$createElement("span");
1713
- _$insert(_el$153, agentName);
1714
- _$effect((_$p) => _$setProp(_el$153, "style", {
1740
+ var _el$161 = _$createElement("span");
1741
+ _$insert(_el$161, agentName);
1742
+ _$effect((_$p) => _$setProp(_el$161, "style", {
1715
1743
  fg: agentColor(meta?.color, theme()),
1716
1744
  bold: true
1717
1745
  }, _$p));
1718
- return _el$153;
1746
+ return _el$161;
1719
1747
  })(), _$memo(() => _$memo(() => !!meta?.mode)() && (() => {
1720
- var _el$154 = _$createElement("span"), _el$155 = _$createTextNode(` (`), _el$156 = _$createTextNode(`)`);
1721
- _$insertNode(_el$154, _el$155);
1722
- _$insertNode(_el$154, _el$156);
1723
- _$insert(_el$154, () => meta.mode, _el$156);
1724
- _$effect((_$p) => _$setProp(_el$154, "style", {
1748
+ var _el$162 = _$createElement("span"), _el$163 = _$createTextNode(` (`), _el$164 = _$createTextNode(`)`);
1749
+ _$insertNode(_el$162, _el$163);
1750
+ _$insertNode(_el$162, _el$164);
1751
+ _$insert(_el$162, () => meta.mode, _el$164);
1752
+ _$effect((_$p) => _$setProp(_el$162, "style", {
1725
1753
  fg: theme().textMuted
1726
1754
  }, _$p));
1727
- return _el$154;
1755
+ return _el$162;
1728
1756
  })())] : (() => {
1729
- var _el$157 = _$createElement("span");
1730
- _$insertNode(_el$157, _$createTextNode(`parent default`));
1731
- _$effect((_$p) => _$setProp(_el$157, "style", {
1757
+ var _el$165 = _$createElement("span");
1758
+ _$insertNode(_el$165, _$createTextNode(`parent default`));
1759
+ _$effect((_$p) => _$setProp(_el$165, "style", {
1732
1760
  fg: theme().textMuted
1733
1761
  }, _$p));
1734
- return _el$157;
1762
+ return _el$165;
1735
1763
  })(), (() => {
1736
- var _el$143 = _$createElement("span");
1737
- _$insertNode(_el$143, _$createTextNode(` \u2502 \uD83E\uDDE0 `));
1738
- _$effect((_$p) => _$setProp(_el$143, "style", {
1764
+ var _el$147 = _$createElement("span");
1765
+ _$insertNode(_el$147, _$createTextNode(` \u2502 \uD83E\uDDE0 `));
1766
+ _$effect((_$p) => _$setProp(_el$147, "style", {
1739
1767
  fg: theme().textMuted
1740
1768
  }, _$p));
1741
- return _el$143;
1769
+ return _el$147;
1770
+ })(), (() => {
1771
+ var _el$149 = _$createElement("span");
1772
+ _$insertNode(_el$149, _$createTextNode(`Model: `));
1773
+ _$effect((_$p) => _$setProp(_el$149, "style", {
1774
+ fg: theme().primary,
1775
+ bold: true
1776
+ }, _$p));
1777
+ return _el$149;
1742
1778
  })(), model && slash > 0 ? [(() => {
1743
- var _el$159 = _$createElement("span"), _el$160 = _$createTextNode(`/`);
1744
- _$insertNode(_el$159, _el$160);
1745
- _$insert(_el$159, () => model.slice(0, slash), _el$160);
1746
- _$effect((_$p) => _$setProp(_el$159, "style", {
1779
+ var _el$167 = _$createElement("span"), _el$168 = _$createTextNode(`/`);
1780
+ _$insertNode(_el$167, _el$168);
1781
+ _$insert(_el$167, () => model.slice(0, slash), _el$168);
1782
+ _$effect((_$p) => _$setProp(_el$167, "style", {
1747
1783
  fg: theme().textMuted
1748
1784
  }, _$p));
1749
- return _el$159;
1785
+ return _el$167;
1750
1786
  })(), (() => {
1751
- var _el$161 = _$createElement("span");
1752
- _$insert(_el$161, () => model.slice(slash + 1));
1753
- _$effect((_$p) => _$setProp(_el$161, "style", {
1787
+ var _el$169 = _$createElement("span");
1788
+ _$insert(_el$169, () => model.slice(slash + 1));
1789
+ _$effect((_$p) => _$setProp(_el$169, "style", {
1754
1790
  fg: theme().info,
1755
1791
  bold: true
1756
1792
  }, _$p));
1757
- return _el$161;
1793
+ return _el$169;
1758
1794
  })()] : (() => {
1759
- var _el$162 = _$createElement("span");
1760
- _$insertNode(_el$162, _$createTextNode(`session default`));
1761
- _$effect((_$p) => _$setProp(_el$162, "style", {
1795
+ var _el$170 = _$createElement("span");
1796
+ _$insertNode(_el$170, _$createTextNode(`session default`));
1797
+ _$effect((_$p) => _$setProp(_el$170, "style", {
1762
1798
  fg: theme().textMuted
1763
1799
  }, _$p));
1764
- return _el$162;
1800
+ return _el$170;
1765
1801
  })(), (() => {
1766
- var _el$145 = _$createElement("span");
1767
- _$insertNode(_el$145, _$createTextNode(` \u2502 \uD83D\uDCB0 `));
1768
- _$effect((_$p) => _$setProp(_el$145, "style", {
1802
+ var _el$151 = _$createElement("span");
1803
+ _$insertNode(_el$151, _$createTextNode(` \u2502 \uD83D\uDCB0 `));
1804
+ _$effect((_$p) => _$setProp(_el$151, "style", {
1769
1805
  fg: theme().textMuted
1770
1806
  }, _$p));
1771
- return _el$145;
1807
+ return _el$151;
1772
1808
  })(), (() => {
1773
- var _el$147 = _$createElement("span");
1774
- _$insert(_el$147, () => formatTokens(goal().tokensUsed));
1775
- _$effect((_$p) => _$setProp(_el$147, "style", {
1809
+ var _el$153 = _$createElement("span");
1810
+ _$insertNode(_el$153, _$createTextNode(`Spent: `));
1811
+ _$effect((_$p) => _$setProp(_el$153, "style", {
1812
+ fg: theme().primary,
1813
+ bold: true
1814
+ }, _$p));
1815
+ return _el$153;
1816
+ })(), (() => {
1817
+ var _el$155 = _$createElement("span");
1818
+ _$insert(_el$155, () => formatTokens(goal().tokensUsed));
1819
+ _$effect((_$p) => _$setProp(_el$155, "style", {
1776
1820
  fg: theme().warning,
1777
1821
  bold: true
1778
1822
  }, _$p));
1779
- return _el$147;
1823
+ return _el$155;
1780
1824
  })(), (() => {
1781
- var _el$148 = _$createElement("span");
1782
- _$insertNode(_el$148, _$createTextNode(` tokens \xB7 `));
1783
- _$effect((_$p) => _$setProp(_el$148, "style", {
1825
+ var _el$156 = _$createElement("span");
1826
+ _$insertNode(_el$156, _$createTextNode(` tokens \xB7 `));
1827
+ _$effect((_$p) => _$setProp(_el$156, "style", {
1784
1828
  fg: theme().textMuted
1785
1829
  }, _$p));
1786
- return _el$148;
1830
+ return _el$156;
1787
1831
  })(), (() => {
1788
- var _el$150 = _$createElement("span");
1789
- _$insert(_el$150, () => formatCost(goal().costUsed));
1790
- _$effect((_$p) => _$setProp(_el$150, "style", {
1832
+ var _el$158 = _$createElement("span");
1833
+ _$insert(_el$158, () => formatCost(goal().costUsed));
1834
+ _$effect((_$p) => _$setProp(_el$158, "style", {
1791
1835
  fg: theme().success,
1792
1836
  bold: true
1793
1837
  }, _$p));
1794
- return _el$150;
1838
+ return _el$158;
1795
1839
  })(), (() => {
1796
- var _el$151 = _$createElement("span"), _el$152 = _$createTextNode(` \xB7 `);
1797
- _$insertNode(_el$151, _el$152);
1798
- _$insert(_el$151, () => formatDuration(goal().timeUsedSeconds), null);
1799
- _$effect((_$p) => _$setProp(_el$151, "style", {
1840
+ var _el$159 = _$createElement("span"), _el$160 = _$createTextNode(` \xB7 `);
1841
+ _$insertNode(_el$159, _el$160);
1842
+ _$insert(_el$159, () => formatDuration(goal().timeUsedSeconds), null);
1843
+ _$effect((_$p) => _$setProp(_el$159, "style", {
1800
1844
  fg: theme().textMuted
1801
1845
  }, _$p));
1802
- return _el$151;
1846
+ return _el$159;
1803
1847
  })()];
1804
1848
  }, _el$127);
1805
- _$insert(_el$128, () => goal().objective.slice(0, 160));
1849
+ _$insertNode(_el$128, _$createTextNode(`\uD83C\uDFAF Target: `));
1850
+ _$insert(_el$130, () => goal().objective.slice(0, 160));
1806
1851
  _$insert(_el$122, (() => {
1807
1852
  var _c$12 = _$memo(() => !!lp());
1808
1853
  return () => _c$12() && [(() => {
1809
- var _el$164 = _$createElement("span"), _el$165 = _$createTextNode(`
1854
+ var _el$172 = _$createElement("span"), _el$173 = _$createTextNode(`
1810
1855
  \u2714 `);
1811
- _$insertNode(_el$164, _el$165);
1812
- _$effect((_$p) => _$setProp(_el$164, "style", {
1856
+ _$insertNode(_el$172, _el$173);
1857
+ _$effect((_$p) => _$setProp(_el$172, "style", {
1813
1858
  fg: theme().success
1814
1859
  }, _$p));
1815
- return _el$164;
1860
+ return _el$172;
1816
1861
  })(), (() => {
1817
- var _el$167 = _$createElement("span");
1818
- _$insert(_el$167, () => lp().summary.slice(0, 100));
1819
- _$effect((_$p) => _$setProp(_el$167, "style", {
1862
+ var _el$175 = _$createElement("span");
1863
+ _$insertNode(_el$175, _$createTextNode(`Progress: `));
1864
+ _$effect((_$p) => _$setProp(_el$175, "style", {
1865
+ fg: theme().success,
1866
+ bold: true
1867
+ }, _$p));
1868
+ return _el$175;
1869
+ })(), (() => {
1870
+ var _el$177 = _$createElement("span");
1871
+ _$insert(_el$177, () => lp().summary.slice(0, 100));
1872
+ _$effect((_$p) => _$setProp(_el$177, "style", {
1820
1873
  fg: theme().text
1821
1874
  }, _$p));
1822
- return _el$167;
1875
+ return _el$177;
1823
1876
  })(), (() => {
1824
- var _el$168 = _$createElement("span"), _el$169 = _$createTextNode(` \u2192 `);
1825
- _$insertNode(_el$168, _el$169);
1826
- _$insert(_el$168, () => lp().next?.slice(0, 60) || "", null);
1827
- _$effect((_$p) => _$setProp(_el$168, "style", {
1877
+ var _el$178 = _$createElement("span"), _el$179 = _$createTextNode(` \u2192 `);
1878
+ _$insertNode(_el$178, _el$179);
1879
+ _$insert(_el$178, () => lp().next?.slice(0, 60) || "", null);
1880
+ _$effect((_$p) => _$setProp(_el$178, "style", {
1828
1881
  fg: theme().textMuted
1829
1882
  }, _$p));
1830
- return _el$168;
1883
+ return _el$178;
1831
1884
  })()];
1832
1885
  })(), null);
1833
1886
  _$insert(_el$122, (() => {
1834
1887
  var _c$13 = _$memo(() => !!blk());
1835
1888
  return () => _c$13() && [(() => {
1836
- var _el$170 = _$createElement("span"), _el$171 = _$createTextNode(`
1837
- \u2716 blocked: `);
1838
- _$insertNode(_el$170, _el$171);
1839
- _$effect((_$p) => _$setProp(_el$170, "style", {
1889
+ var _el$180 = _$createElement("span"), _el$181 = _$createTextNode(`
1890
+ \u2716 Blocked: `);
1891
+ _$insertNode(_el$180, _el$181);
1892
+ _$effect((_$p) => _$setProp(_el$180, "style", {
1840
1893
  fg: theme().error,
1841
1894
  bold: true
1842
1895
  }, _$p));
1843
- return _el$170;
1896
+ return _el$180;
1844
1897
  })(), (() => {
1845
- var _el$173 = _$createElement("span");
1846
- _$insert(_el$173, () => blk().reason.slice(0, 140));
1847
- _$effect((_$p) => _$setProp(_el$173, "style", {
1898
+ var _el$183 = _$createElement("span");
1899
+ _$insert(_el$183, () => blk().reason.slice(0, 140));
1900
+ _$effect((_$p) => _$setProp(_el$183, "style", {
1848
1901
  fg: theme().error
1849
1902
  }, _$p));
1850
- return _el$173;
1903
+ return _el$183;
1851
1904
  })(), (() => {
1852
- var _el$174 = _$createElement("span"), _el$175 = _$createTextNode(` \u2014 `);
1853
- _$insertNode(_el$174, _el$175);
1854
- _$insert(_el$174, () => blk().needed.slice(0, 60), null);
1855
- _$effect((_$p) => _$setProp(_el$174, "style", {
1905
+ var _el$184 = _$createElement("span"), _el$185 = _$createTextNode(` \u2014 `);
1906
+ _$insertNode(_el$184, _el$185);
1907
+ _$insert(_el$184, () => blk().needed.slice(0, 60), null);
1908
+ _$effect((_$p) => _$setProp(_el$184, "style", {
1856
1909
  fg: theme().textMuted
1857
1910
  }, _$p));
1858
- return _el$174;
1911
+ return _el$184;
1859
1912
  })()];
1860
1913
  })(), null);
1861
1914
  _$insert(_el$122, (() => {
1862
1915
  var _c$14 = _$memo(() => !!goal().config.artifactDir);
1863
1916
  return () => _c$14() && [(() => {
1864
- var _el$176 = _$createElement("span"), _el$177 = _$createTextNode(`
1917
+ var _el$186 = _$createElement("span"), _el$187 = _$createTextNode(`
1865
1918
  \uD83D\uDCC1 `);
1866
- _$insertNode(_el$176, _el$177);
1867
- _$effect((_$p) => _$setProp(_el$176, "style", {
1919
+ _$insertNode(_el$186, _el$187);
1920
+ _$effect((_$p) => _$setProp(_el$186, "style", {
1868
1921
  fg: theme().accent
1869
1922
  }, _$p));
1870
- return _el$176;
1923
+ return _el$186;
1871
1924
  })(), (() => {
1872
- var _el$179 = _$createElement("span");
1873
- _$insert(_el$179, () => String(goal().config.artifactDir).replace(String(props.directory), "."));
1874
- _$effect((_$p) => _$setProp(_el$179, "style", {
1925
+ var _el$189 = _$createElement("span");
1926
+ _$insertNode(_el$189, _$createTextNode(`Artifacts: `));
1927
+ _$effect((_$p) => _$setProp(_el$189, "style", {
1928
+ fg: theme().accent,
1929
+ bold: true
1930
+ }, _$p));
1931
+ return _el$189;
1932
+ })(), (() => {
1933
+ var _el$191 = _$createElement("span");
1934
+ _$insert(_el$191, () => String(goal().config.artifactDir).replace(String(props.directory), "."));
1935
+ _$effect((_$p) => _$setProp(_el$191, "style", {
1875
1936
  fg: theme().textMuted
1876
1937
  }, _$p));
1877
- return _el$179;
1938
+ return _el$191;
1878
1939
  })()];
1879
1940
  })(), null);
1880
1941
  _$insert(_el$122, (() => {
1881
1942
  var _c$15 = _$memo(() => (goal().config.checks?.length ?? 0) > 0);
1882
1943
  return () => _c$15() ? [(() => {
1883
- var _el$180 = _$createElement("span"), _el$181 = _$createTextNode(`
1884
- \u25A3 checks: `);
1885
- _$insertNode(_el$180, _el$181);
1886
- _$effect((_$p) => _$setProp(_el$180, "style", {
1944
+ var _el$192 = _$createElement("span"), _el$193 = _$createTextNode(`
1945
+ \u25A3 `);
1946
+ _$insertNode(_el$192, _el$193);
1947
+ _$effect((_$p) => _$setProp(_el$192, "style", {
1887
1948
  fg: theme().warning
1888
1949
  }, _$p));
1889
- return _el$180;
1950
+ return _el$192;
1890
1951
  })(), (() => {
1891
- var _el$183 = _$createElement("span");
1892
- _$insert(_el$183, () => goal().config.checks.join(", ").slice(0, 100));
1893
- _$effect((_$p) => _$setProp(_el$183, "style", {
1952
+ var _el$195 = _$createElement("span");
1953
+ _$insertNode(_el$195, _$createTextNode(`Checks: `));
1954
+ _$effect((_$p) => _$setProp(_el$195, "style", {
1955
+ fg: theme().warning,
1956
+ bold: true
1957
+ }, _$p));
1958
+ return _el$195;
1959
+ })(), (() => {
1960
+ var _el$197 = _$createElement("span");
1961
+ _$insert(_el$197, () => goal().config.checks.join(", ").slice(0, 100));
1962
+ _$effect((_$p) => _$setProp(_el$197, "style", {
1894
1963
  fg: theme().textMuted
1895
1964
  }, _$p));
1896
- return _el$183;
1965
+ return _el$197;
1897
1966
  })()] : null;
1898
1967
  })(), null);
1899
1968
  _$insert(_el$122, (() => {
1900
1969
  var _c$16 = _$memo(() => rt()?.evaluatorRejectionCount > 0);
1901
1970
  return () => _c$16() && [(() => {
1902
- var _el$184 = _$createElement("span"), _el$185 = _$createTextNode(`
1971
+ var _el$198 = _$createElement("span"), _el$199 = _$createTextNode(`
1903
1972
  \u26A0 rejections: `);
1904
- _$insertNode(_el$184, _el$185);
1905
- _$effect((_$p) => _$setProp(_el$184, "style", {
1973
+ _$insertNode(_el$198, _el$199);
1974
+ _$effect((_$p) => _$setProp(_el$198, "style", {
1906
1975
  fg: theme().warning
1907
1976
  }, _$p));
1908
- return _el$184;
1977
+ return _el$198;
1909
1978
  })(), (() => {
1910
- var _el$187 = _$createElement("span"), _el$188 = _$createTextNode(` \u2014 `);
1911
- _$insertNode(_el$187, _el$188);
1912
- _$insert(_el$187, () => String(rt().evaluatorRejectionCount), _el$188);
1913
- _$insert(_el$187, () => String(rt().lastRejectionDetails || "").slice(0, 80), null);
1914
- _$effect((_$p) => _$setProp(_el$187, "style", {
1979
+ var _el$201 = _$createElement("span"), _el$202 = _$createTextNode(` \u2014 `);
1980
+ _$insertNode(_el$201, _el$202);
1981
+ _$insert(_el$201, () => String(rt().evaluatorRejectionCount), _el$202);
1982
+ _$insert(_el$201, () => String(rt().lastRejectionDetails || "").slice(0, 80), null);
1983
+ _$effect((_$p) => _$setProp(_el$201, "style", {
1915
1984
  fg: theme().warning
1916
1985
  }, _$p));
1917
- return _el$187;
1986
+ return _el$201;
1918
1987
  })()];
1919
1988
  })(), null);
1920
1989
  _$insert(_el$122, (() => {
1921
1990
  var _c$17 = _$memo(() => rt()?.unknownStatusCount > 0);
1922
1991
  return () => _c$17() && [(() => {
1923
- var _el$189 = _$createElement("span"), _el$190 = _$createTextNode(`
1992
+ var _el$203 = _$createElement("span"), _el$204 = _$createTextNode(`
1924
1993
  \u26A0\uFE0F unreachable: `);
1925
- _$insertNode(_el$189, _el$190);
1926
- _$effect((_$p) => _$setProp(_el$189, "style", {
1994
+ _$insertNode(_el$203, _el$204);
1995
+ _$effect((_$p) => _$setProp(_el$203, "style", {
1927
1996
  fg: theme().error
1928
1997
  }, _$p));
1929
- return _el$189;
1998
+ return _el$203;
1930
1999
  })(), (() => {
1931
- var _el$192 = _$createElement("span"), _el$193 = _$createTextNode(`/3`);
1932
- _$insertNode(_el$192, _el$193);
1933
- _$insert(_el$192, () => String(rt().unknownStatusCount), _el$193);
1934
- _$effect((_$p) => _$setProp(_el$192, "style", {
2000
+ var _el$206 = _$createElement("span"), _el$207 = _$createTextNode(`/3`);
2001
+ _$insertNode(_el$206, _el$207);
2002
+ _$insert(_el$206, () => String(rt().unknownStatusCount), _el$207);
2003
+ _$effect((_$p) => _$setProp(_el$206, "style", {
1935
2004
  fg: theme().error
1936
2005
  }, _$p));
1937
- return _el$192;
2006
+ return _el$206;
1938
2007
  })(), (() => {
1939
- var _el$194 = _$createElement("span");
1940
- _$insertNode(_el$194, _$createTextNode(` \u2014 nudge to recover`));
1941
- _$effect((_$p) => _$setProp(_el$194, "style", {
2008
+ var _el$208 = _$createElement("span");
2009
+ _$insertNode(_el$208, _$createTextNode(` \u2014 nudge to recover`));
2010
+ _$effect((_$p) => _$setProp(_el$208, "style", {
1942
2011
  fg: theme().textMuted
1943
2012
  }, _$p));
1944
- return _el$194;
2013
+ return _el$208;
1945
2014
  })()];
1946
2015
  })(), null);
1947
2016
  _$insert(_el$122, (() => {
1948
2017
  var _c$18 = _$memo(() => !!rt()?.retryAfter);
1949
2018
  return () => _c$18() && [(() => {
1950
- var _el$196 = _$createElement("span"), _el$197 = _$createTextNode(`
2019
+ var _el$210 = _$createElement("span"), _el$211 = _$createTextNode(`
1951
2020
  \u21BB retry in: `);
1952
- _$insertNode(_el$196, _el$197);
1953
- _$effect((_$p) => _$setProp(_el$196, "style", {
2021
+ _$insertNode(_el$210, _el$211);
2022
+ _$effect((_$p) => _$setProp(_el$210, "style", {
1954
2023
  fg: theme().accent
1955
2024
  }, _$p));
1956
- return _el$196;
2025
+ return _el$210;
1957
2026
  })(), (() => {
1958
- var _el$199 = _$createElement("span");
1959
- _$insert(_el$199, () => countdownLabel(rt().retryAfter, clock()));
1960
- _$effect((_$p) => _$setProp(_el$199, "style", {
2027
+ var _el$213 = _$createElement("span");
2028
+ _$insert(_el$213, () => countdownLabel(rt().retryAfter, clock()));
2029
+ _$effect((_$p) => _$setProp(_el$213, "style", {
1961
2030
  fg: theme().accent
1962
2031
  }, _$p));
1963
- return _el$199;
2032
+ return _el$213;
1964
2033
  })()];
1965
2034
  })(), null);
1966
2035
  _$insert(_el$122, (() => {
1967
2036
  var _c$19 = _$memo(() => !!rt()?.nextRunAt);
1968
2037
  return () => _c$19() && [(() => {
1969
- var _el$200 = _$createElement("span"), _el$201 = _$createTextNode(`
2038
+ var _el$214 = _$createElement("span"), _el$215 = _$createTextNode(`
1970
2039
  \u23F0 next run: `);
1971
- _$insertNode(_el$200, _el$201);
1972
- _$effect((_$p) => _$setProp(_el$200, "style", {
2040
+ _$insertNode(_el$214, _el$215);
2041
+ _$effect((_$p) => _$setProp(_el$214, "style", {
1973
2042
  fg: theme().accent
1974
2043
  }, _$p));
1975
- return _el$200;
2044
+ return _el$214;
1976
2045
  })(), (() => {
1977
- var _el$203 = _$createElement("span");
1978
- _$insert(_el$203, () => countdownLabel(rt().nextRunAt, clock()));
1979
- _$effect((_$p) => _$setProp(_el$203, "style", {
2046
+ var _el$217 = _$createElement("span");
2047
+ _$insert(_el$217, () => countdownLabel(rt().nextRunAt, clock()));
2048
+ _$effect((_$p) => _$setProp(_el$217, "style", {
1980
2049
  fg: theme().accent
1981
2050
  }, _$p));
1982
- return _el$203;
2051
+ return _el$217;
1983
2052
  })(), (() => {
1984
- var _el$204 = _$createElement("span"), _el$205 = _$createTextNode(` (`), _el$206 = _$createTextNode(` runs)`);
1985
- _$insertNode(_el$204, _el$205);
1986
- _$insertNode(_el$204, _el$206);
1987
- _$insert(_el$204, () => String(rt().scheduleRunCount || 0), _el$206);
1988
- _$effect((_$p) => _$setProp(_el$204, "style", {
2053
+ var _el$218 = _$createElement("span"), _el$219 = _$createTextNode(` (`), _el$220 = _$createTextNode(` runs)`);
2054
+ _$insertNode(_el$218, _el$219);
2055
+ _$insertNode(_el$218, _el$220);
2056
+ _$insert(_el$218, () => String(rt().scheduleRunCount || 0), _el$220);
2057
+ _$effect((_$p) => _$setProp(_el$218, "style", {
1989
2058
  fg: theme().textMuted
1990
2059
  }, _$p));
1991
- return _el$204;
2060
+ return _el$218;
1992
2061
  })()];
1993
2062
  })(), null);
1994
2063
  _$insert(_el$122, (() => {
1995
2064
  var _c$20 = _$memo(() => !!rt()?.lastError);
1996
2065
  return () => _c$20() && [(() => {
1997
- var _el$207 = _$createElement("span"), _el$208 = _$createTextNode(`
2066
+ var _el$221 = _$createElement("span"), _el$222 = _$createTextNode(`
1998
2067
  \u26A0 `);
1999
- _$insertNode(_el$207, _el$208);
2000
- _$effect((_$p) => _$setProp(_el$207, "style", {
2068
+ _$insertNode(_el$221, _el$222);
2069
+ _$effect((_$p) => _$setProp(_el$221, "style", {
2001
2070
  fg: theme().error
2002
2071
  }, _$p));
2003
- return _el$207;
2072
+ return _el$221;
2004
2073
  })(), (() => {
2005
- var _el$210 = _$createElement("span");
2006
- _$insert(_el$210, () => rt().lastError.slice(0, 120));
2007
- _$effect((_$p) => _$setProp(_el$210, "style", {
2074
+ var _el$224 = _$createElement("span");
2075
+ _$insertNode(_el$224, _$createTextNode(`Error: `));
2076
+ _$effect((_$p) => _$setProp(_el$224, "style", {
2077
+ fg: theme().error,
2078
+ bold: true
2079
+ }, _$p));
2080
+ return _el$224;
2081
+ })(), (() => {
2082
+ var _el$226 = _$createElement("span");
2083
+ _$insert(_el$226, () => rt().lastError.slice(0, 120));
2084
+ _$effect((_$p) => _$setProp(_el$226, "style", {
2008
2085
  fg: theme().error
2009
2086
  }, _$p));
2010
- return _el$210;
2087
+ return _el$226;
2011
2088
  })()];
2012
2089
  })(), null);
2013
2090
  _$effect((_p$) => {
2014
- var _v$36 = borderColorForStatus(goal().status, theme()), _v$37 = {
2091
+ var _v$37 = borderColorForStatus(goal().status, theme()), _v$38 = {
2015
2092
  fg: statusColor(goal().status, theme()),
2016
2093
  bold: true
2017
- }, _v$38 = {
2018
- fg: statusColor(goal().status, theme())
2019
2094
  }, _v$39 = {
2095
+ fg: statusColor(goal().status, theme())
2096
+ }, _v$40 = {
2097
+ fg: theme().primary,
2098
+ bold: true
2099
+ }, _v$41 = {
2020
2100
  fg: theme().text
2021
2101
  };
2022
- _v$36 !== _p$.e && (_p$.e = _$setProp(_el$121, "borderColor", _v$36, _p$.e));
2023
- _v$37 !== _p$.t && (_p$.t = _$setProp(_el$123, "style", _v$37, _p$.t));
2024
- _v$38 !== _p$.a && (_p$.a = _$setProp(_el$125, "style", _v$38, _p$.a));
2025
- _v$39 !== _p$.o && (_p$.o = _$setProp(_el$128, "style", _v$39, _p$.o));
2102
+ _v$37 !== _p$.e && (_p$.e = _$setProp(_el$121, "borderColor", _v$37, _p$.e));
2103
+ _v$38 !== _p$.t && (_p$.t = _$setProp(_el$123, "style", _v$38, _p$.t));
2104
+ _v$39 !== _p$.a && (_p$.a = _$setProp(_el$125, "style", _v$39, _p$.a));
2105
+ _v$40 !== _p$.o && (_p$.o = _$setProp(_el$128, "style", _v$40, _p$.o));
2106
+ _v$41 !== _p$.i && (_p$.i = _$setProp(_el$130, "style", _v$41, _p$.i));
2026
2107
  return _p$;
2027
2108
  }, {
2028
2109
  e: undefined,
2029
2110
  t: undefined,
2030
2111
  a: undefined,
2031
- o: undefined
2112
+ o: undefined,
2113
+ i: undefined
2032
2114
  });
2033
2115
  return _el$121;
2034
2116
  })();
@@ -2057,29 +2139,29 @@ function LoopDashboard(props) {
2057
2139
  },
2058
2140
  children: (ev) => [`
2059
2141
  `, (() => {
2060
- var _el$211 = _$createElement("span");
2061
- _$insert(_el$211, () => String(ev.type));
2062
- _$effect((_$p) => _$setProp(_el$211, "style", {
2142
+ var _el$227 = _$createElement("span");
2143
+ _$insert(_el$227, () => String(ev.type));
2144
+ _$effect((_$p) => _$setProp(_el$227, "style", {
2063
2145
  fg: eventColor(String(ev.type), theme()),
2064
2146
  bold: true
2065
2147
  }, _$p));
2066
- return _el$211;
2148
+ return _el$227;
2067
2149
  })(), (() => {
2068
- var _el$212 = _$createElement("span"), _el$213 = _$createTextNode(` `);
2069
- _$insertNode(_el$212, _el$213);
2070
- _$insert(_el$212, () => ev.goalID?.slice(0, 8), null);
2071
- _$effect((_$p) => _$setProp(_el$212, "style", {
2150
+ var _el$228 = _$createElement("span"), _el$229 = _$createTextNode(` `);
2151
+ _$insertNode(_el$228, _el$229);
2152
+ _$insert(_el$228, () => ev.goalID?.slice(0, 8), null);
2153
+ _$effect((_$p) => _$setProp(_el$228, "style", {
2072
2154
  fg: theme().textMuted
2073
2155
  }, _$p));
2074
- return _el$212;
2156
+ return _el$228;
2075
2157
  })(), _$memo(() => _$memo(() => !!ev.summary)() && (() => {
2076
- var _el$214 = _$createElement("span"), _el$215 = _$createTextNode(` \u2014 `);
2077
- _$insertNode(_el$214, _el$215);
2078
- _$insert(_el$214, () => String(ev.summary).slice(0, 60), null);
2079
- _$effect((_$p) => _$setProp(_el$214, "style", {
2158
+ var _el$230 = _$createElement("span"), _el$231 = _$createTextNode(` \u2014 `);
2159
+ _$insertNode(_el$230, _el$231);
2160
+ _$insert(_el$230, () => String(ev.summary).slice(0, 60), null);
2161
+ _$effect((_$p) => _$setProp(_el$230, "style", {
2080
2162
  fg: theme().text
2081
2163
  }, _$p));
2082
- return _el$214;
2164
+ return _el$230;
2083
2165
  })())]
2084
2166
  }), null);
2085
2167
  _$effect((_p$) => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@bojackduy/opencode-loopd",
4
- "version": "1.9.2",
4
+ "version": "1.9.3",
5
5
  "description": "Codex-inspired background goal engine for OpenCode — autonomous subagents, engine-driven loop, child worker sessions and modal TUI dashboard. Like Claude Code loop for OpenCode.",
6
6
  "type": "module",
7
7
  "license": "AGPL-3.0-or-later",
@@ -62,7 +62,7 @@
62
62
  },
63
63
  "scripts": {
64
64
  "typecheck": "tsc --noEmit",
65
- "build:server": "bun build src/server/plugin.ts --outfile dist/server.js --target bun --external @opencode-ai/plugin --external @opencode-ai/plugin/tool",
65
+ "build:server": "bun build src/server/plugin.ts --outfile dist/server.js --target bun --external @opencode-ai/plugin --external @opencode-ai/plugin/tool --external @opencode-ai/plugin/v2/promise",
66
66
  "build:tui": "bun scripts/build-tui.ts",
67
67
  "build": "bun run build:server && bun run build:tui",
68
68
  "clean": "rm -rf dist",
@@ -73,13 +73,13 @@
73
73
  "release:major": "bun run typecheck && bun test && npm version major -m \"chore: release %s\" && git push && git push origin $(git describe --tags --abbrev=0)"
74
74
  },
75
75
  "peerDependencies": {
76
- "@opencode-ai/plugin": ">=1.4.0 <2",
76
+ "@opencode-ai/plugin": ">=1.4.0 <3",
77
77
  "@opentui/core": "*",
78
78
  "@opentui/solid": "*",
79
79
  "solid-js": "*"
80
80
  },
81
81
  "devDependencies": {
82
- "@opencode-ai/plugin": "^1.18.15",
82
+ "@opencode-ai/plugin": "^1.18.30",
83
83
  "@opentui/core": "^0.4.1",
84
84
  "@opentui/solid": "^0.4.1",
85
85
  "@types/bun": "^1.3.14",