@bojackduy/opencode-loopd 1.13.0 → 1.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/tui.js CHANGED
@@ -642,7 +642,7 @@ var GOAL_STATUS_META = {
642
642
  var PHASE_META = {
643
643
  idle: { short: "Idle", hint: "between turns" },
644
644
  queued: { short: "Queued", hint: "waiting to start" },
645
- running: { short: "Running", hint: "worker acting now" },
645
+ running: { short: "Reserved", hint: "turn reserved; activity unconfirmed" },
646
646
  compacting: { short: "Compacting", hint: "summarizing context" },
647
647
  waiting_retry: { short: "Retrying", hint: "backing off" },
648
648
  stopping: { short: "Stopping", hint: "abort in flight" }
@@ -653,9 +653,30 @@ function goalStatusLabel(status) {
653
653
  function phaseLabel(phase) {
654
654
  return PHASE_META[phase] ?? { short: phase, hint: "" };
655
655
  }
656
- function describeGoalState(status, phase) {
656
+ function workerActivityLabel(runtime, now = Date.now()) {
657
+ if (runtime.phase !== "running")
658
+ return { ...phaseLabel(runtime.phase), acting: false };
659
+ const expires = runtime.leaseExpiresAt ? Date.parse(runtime.leaseExpiresAt) : NaN;
660
+ if (Number.isFinite(expires) && expires <= now)
661
+ return { short: "Stale", hint: "lease expired; activity unconfirmed (not proof of worker exit)", acting: false };
662
+ if (!Number.isFinite(expires) || (runtime.unknownStatusCount ?? 0) > 0)
663
+ return { short: "Unconfirmed", hint: "worker status unavailable; do not assume the prompt failed", acting: false };
664
+ if (runtime.activeAssistantCompletedAt)
665
+ return { short: "Finishing", hint: "response completed; waiting for turn reconciliation", acting: false };
666
+ if (runtime.activePromptObservedAt && runtime.lastWorkerStatus !== "idle" && runtime.lastWorkerStatus !== "retry" && (runtime.activeAssistantMessageID || runtime.activeToolCallIDs?.length)) {
667
+ return { short: "Running", hint: "correlated assistant or tool activity observed", acting: true };
668
+ }
669
+ if (runtime.activePromptObservedAt)
670
+ return { short: "Prompt seen", hint: "prompt observed; response activity not confirmed", acting: false };
671
+ if (runtime.activePromptAcceptedAt)
672
+ return { short: "Awaiting", hint: "host accepted prompt; transcript activity not confirmed", acting: false };
673
+ if (runtime.activePromptDispatchAt)
674
+ return { short: "Sending", hint: "dispatch requested; awaiting host acceptance", acting: false };
675
+ return { short: "Requested", hint: "run reserved; no dispatch evidence yet", acting: false };
676
+ }
677
+ function describeGoalState(status, phase, now = Date.now()) {
657
678
  const goal = goalStatusLabel(status);
658
- const activity = phase ? phaseLabel(phase) : undefined;
679
+ const activity = phase ? typeof phase === "string" ? phaseLabel(phase) : workerActivityLabel(phase, now) : undefined;
659
680
  const workerClause = activity ? `worker is ${activity.hint || activity.short.toLowerCase()}` : "worker state unknown";
660
681
  if (status === "active")
661
682
  return `Loopd owns this; ${workerClause}.`;
@@ -2019,7 +2040,7 @@ function LoopDashboard(props) {
2019
2040
  returnToNormalMode();
2020
2041
  }
2021
2042
  const activeGoals = () => state()?.goals.filter((g) => showCompleted() || g.status !== "complete") || [];
2022
- const runningCount = () => state()?.runtimes.filter((runtime) => runtime.phase === "running").length || 0;
2043
+ const runningCount = () => state()?.runtimes.filter((runtime) => workerActivityLabel(runtime, clock()).acting).length || 0;
2023
2044
  const runningFrame = () => ["|", "/", "-", "\\"][Math.floor(clock() / 500) % 4];
2024
2045
  function handleBugReport() {
2025
2046
  const goal = selectedGoal();
@@ -2040,7 +2061,7 @@ function LoopDashboard(props) {
2040
2061
  return `loopd-goal-${goalID}`;
2041
2062
  }
2042
2063
  return (() => {
2043
- var _el$4 = _$createElement("box"), _el$5 = _$createElement("box"), _el$6 = _$createElement("box"), _el$7 = _$createElement("text"), _el$8 = _$createElement("span"), _el$0 = _$createElement("span"), _el$10 = _$createElement("span"), _el$11 = _$createTextNode(` `), _el$12 = _$createTextNode(` `), _el$13 = _$createElement("span"), _el$15 = _$createElement("span"), _el$16 = _$createElement("span"), _el$18 = _$createElement("span"), _el$20 = _$createElement("span"), _el$21 = _$createTextNode(` `), _el$22 = _$createTextNode(` acting now`), _el$23 = _$createElement("span"), _el$25 = _$createElement("span"), _el$26 = _$createElement("span"), _el$28 = _$createElement("span"), _el$30 = _$createElement("span"), _el$32 = _$createElement("span"), _el$34 = _$createElement("span"), _el$36 = _$createElement("span"), _el$38 = _$createElement("box"), _el$39 = _$createElement("text"), _el$40 = _$createElement("span"), _el$42 = _$createElement("box"), _el$56 = _$createElement("box"), _el$57 = _$createElement("text"), _el$58 = _$createElement("span"), _el$59 = _$createElement("input");
2064
+ var _el$4 = _$createElement("box"), _el$5 = _$createElement("box"), _el$6 = _$createElement("box"), _el$7 = _$createElement("text"), _el$8 = _$createElement("span"), _el$0 = _$createElement("span"), _el$10 = _$createElement("span"), _el$11 = _$createTextNode(` `), _el$12 = _$createTextNode(` `), _el$13 = _$createElement("span"), _el$15 = _$createElement("span"), _el$16 = _$createElement("span"), _el$18 = _$createElement("span"), _el$20 = _$createElement("span"), _el$21 = _$createTextNode(` `), _el$22 = _$createTextNode(` observed active`), _el$23 = _$createElement("span"), _el$25 = _$createElement("span"), _el$26 = _$createElement("span"), _el$28 = _$createElement("span"), _el$30 = _$createElement("span"), _el$32 = _$createElement("span"), _el$34 = _$createElement("span"), _el$36 = _$createElement("span"), _el$38 = _$createElement("box"), _el$39 = _$createElement("text"), _el$40 = _$createElement("span"), _el$42 = _$createElement("box"), _el$56 = _$createElement("box"), _el$57 = _$createElement("text"), _el$58 = _$createElement("span"), _el$59 = _$createElement("input");
2044
2065
  _$insertNode(_el$4, _el$5);
2045
2066
  _$setProp(_el$4, "flexDirection", "column");
2046
2067
  _$setProp(_el$4, "width", "100%");
@@ -2414,6 +2435,7 @@ function LoopDashboard(props) {
2414
2435
  },
2415
2436
  children: (goal, i) => {
2416
2437
  const runtime = () => state()?.runtimes.find((r) => r.goalID === goal.id);
2438
+ const activity = () => runtime() ? workerActivityLabel(runtime(), clock()) : undefined;
2417
2439
  const isActive = () => i() === selected();
2418
2440
  const maxTurns = goal.config?.maxTurns;
2419
2441
  const turnColor = () => {
@@ -2478,13 +2500,13 @@ function LoopDashboard(props) {
2478
2500
  var _el$111 = _$createElement("span"), _el$112 = _$createTextNode(` `);
2479
2501
  _$insertNode(_el$111, _el$112);
2480
2502
  _$insert(_el$111, (() => {
2481
- var _c$3 = _$memo(() => runtime().phase === "running");
2482
- return () => _c$3() ? runningFrame() : phaseIcon(runtime().phase);
2503
+ var _c$3 = _$memo(() => !!activity()?.acting);
2504
+ return () => _c$3() ? runningFrame() : _$memo(() => runtime().phase === "running")() ? "\u25F7" : phaseIcon(runtime().phase);
2483
2505
  })(), _el$112);
2484
- _$insert(_el$111, () => phaseLabel(runtime().phase).short.toUpperCase(), null);
2506
+ _$insert(_el$111, () => activity().short.toUpperCase(), null);
2485
2507
  _$effect((_$p) => _$setProp(_el$111, "style", {
2486
- fg: turnColor(),
2487
- bold: runtime().phase === "running"
2508
+ fg: activity()?.acting ? turnColor() : theme().textMuted,
2509
+ bold: activity()?.acting
2488
2510
  }, _$p));
2489
2511
  return _el$111;
2490
2512
  })(), (() => {
@@ -2603,6 +2625,7 @@ function LoopDashboard(props) {
2603
2625
  },
2604
2626
  children: (goal) => {
2605
2627
  const rt = () => state()?.runtimes.find((r) => r.goalID === goal().id);
2628
+ const activity = () => rt() ? workerActivityLabel(rt(), clock()) : undefined;
2606
2629
  const lp = () => goal().lastProgress;
2607
2630
  const blk = () => goal().blocker;
2608
2631
  return (() => {
@@ -2650,11 +2673,14 @@ function LoopDashboard(props) {
2650
2673
  var _el$164 = _$createElement("span"), _el$165 = _$createTextNode(` `), _el$166 = _$createTextNode(` \u2014 `);
2651
2674
  _$insertNode(_el$164, _el$165);
2652
2675
  _$insertNode(_el$164, _el$166);
2653
- _$insert(_el$164, () => phaseIcon(rt().phase), _el$165);
2654
- _$insert(_el$164, () => phaseLabel(rt().phase).short, _el$166);
2655
- _$insert(_el$164, () => phaseLabel(rt().phase).hint, null);
2676
+ _$insert(_el$164, (() => {
2677
+ var _c$18 = _$memo(() => !!activity()?.acting);
2678
+ return () => _c$18() ? runningFrame() : _$memo(() => rt().phase === "running")() ? "\u25F7" : phaseIcon(rt().phase);
2679
+ })(), _el$165);
2680
+ _$insert(_el$164, () => activity().short, _el$166);
2681
+ _$insert(_el$164, () => activity().hint, null);
2656
2682
  _$effect((_$p) => _$setProp(_el$164, "style", {
2657
- fg: phaseColor(rt().phase, theme()),
2683
+ fg: activity()?.acting ? phaseColor(rt().phase, theme()) : theme().textMuted,
2658
2684
  bold: true
2659
2685
  }, _$p));
2660
2686
  return _el$164;
@@ -2671,7 +2697,7 @@ function LoopDashboard(props) {
2671
2697
  return _el$167;
2672
2698
  })()];
2673
2699
  })(), _el$149);
2674
- _$insert(_el$150, () => describeGoalState(goal().status, rt()?.phase));
2700
+ _$insert(_el$150, () => describeGoalState(goal().status, rt(), clock()));
2675
2701
  _$insert(_el$142, (() => {
2676
2702
  var _c$5 = _$memo(() => !!rt()?.workerAbortedAt);
2677
2703
  return () => _c$5() && [(() => {
@@ -2972,8 +2998,8 @@ function LoopDashboard(props) {
2972
2998
  })(), (() => {
2973
2999
  var _el$237 = _$createElement("span");
2974
3000
  _$insert(_el$237, (() => {
2975
- var _c$18 = _$memo(() => goal().workerTopology === "v2-native-child");
2976
- return () => _c$18() ? "native child" : goal().workerTopology === "v2-root-fallback" ? "root fallback" : "v1 child";
3001
+ var _c$19 = _$memo(() => goal().workerTopology === "v2-native-child");
3002
+ return () => _c$19() ? "native child" : goal().workerTopology === "v2-root-fallback" ? "root fallback" : "v1 child";
2977
3003
  })());
2978
3004
  _$effect((_$p) => _$setProp(_el$237, "style", {
2979
3005
  fg: theme().text
@@ -3317,15 +3343,15 @@ Write scope: `);
3317
3343
  _$insertNode(_el$299, _el$300);
3318
3344
  _$insertNode(_el$299, _el$301);
3319
3345
  _$insert(_el$299, (() => {
3320
- var _c$19 = _$memo(() => hiddenFinishedCommands() > 0);
3321
- return () => _c$19() ? ` \u2014 ${hiddenFinishedCommands()} finished hidden` : "";
3346
+ var _c$20 = _$memo(() => hiddenFinishedCommands() > 0);
3347
+ return () => _c$20() ? ` \u2014 ${hiddenFinishedCommands()} finished hidden` : "";
3322
3348
  })(), _el$301);
3323
3349
  _$insertNode(_el$302, _$createTextNode(`:new &lt;command&gt;`));
3324
3350
  _$insertNode(_el$304, _el$305);
3325
3351
  _$insert(_el$304, () => hiddenFinishedCommands() > 0 ? ", or " : "; ", null);
3326
3352
  _$insert(_el$298, (() => {
3327
- var _c$20 = _$memo(() => hiddenFinishedCommands() > 0);
3328
- return () => _c$20() && (() => {
3353
+ var _c$21 = _$memo(() => hiddenFinishedCommands() > 0);
3354
+ return () => _c$21() && (() => {
3329
3355
  var _el$321 = _$createElement("span"), _el$322 = _$createElement("span"), _el$324 = _$createElement("span");
3330
3356
  _$insertNode(_el$321, _el$322);
3331
3357
  _$insertNode(_el$321, _el$324);
@@ -3435,8 +3461,8 @@ Write scope: `);
3435
3461
  return [(() => {
3436
3462
  var _el$326 = _$createElement("span");
3437
3463
  _$insert(_el$326, (() => {
3438
- var _c$21 = _$memo(() => !!isActive());
3439
- return () => _c$21() ? `\u25B6 ${cmd.title}` : ` ${commandStatusIcon(cmd.status)} ${cmd.title}`;
3464
+ var _c$22 = _$memo(() => !!isActive());
3465
+ return () => _c$22() ? `\u25B6 ${cmd.title}` : ` ${commandStatusIcon(cmd.status)} ${cmd.title}`;
3440
3466
  })());
3441
3467
  _$effect((_$p) => _$setProp(_el$326, "style", {
3442
3468
  fg: commandStatusColor(cmd.status, theme()),
@@ -3571,8 +3597,8 @@ Write scope: `);
3571
3597
  _$insertNode(_el$354, _$createTextNode(`\u2B22 Spawn: `));
3572
3598
  _$insert(_el$356, () => cmd().command);
3573
3599
  _$insert(_el$346, (() => {
3574
- var _c$22 = _$memo(() => cmd().args.length > 0);
3575
- return () => _c$22() && (() => {
3600
+ var _c$23 = _$memo(() => cmd().args.length > 0);
3601
+ return () => _c$23() && (() => {
3576
3602
  var _el$375 = _$createElement("span"), _el$376 = _$createTextNode(` `);
3577
3603
  _$insertNode(_el$375, _el$376);
3578
3604
  _$insert(_el$375, () => cmd().args.join(" "), null);
@@ -3586,8 +3612,8 @@ Write scope: `);
3586
3612
  _$insertNode(_el$360, _$createTextNode(`Cwd: `));
3587
3613
  _$insert(_el$362, () => cmd().cwd.replace(String(props.directory), "."));
3588
3614
  _$insert(_el$346, (() => {
3589
- var _c$23 = _$memo(() => !!cmd().goalID);
3590
- return () => _c$23() && [(() => {
3615
+ var _c$24 = _$memo(() => !!cmd().goalID);
3616
+ return () => _c$24() && [(() => {
3591
3617
  var _el$377 = _$createElement("span");
3592
3618
  _$insertNode(_el$377, _$createTextNode(` \u2502 \uD83D\uDD17 linked goal `));
3593
3619
  _$effect((_$p) => _$setProp(_el$377, "style", {
@@ -3608,8 +3634,8 @@ Write scope: `);
3608
3634
  _$insertNode(_el$368, _el$369);
3609
3635
  _$insert(_el$368, () => cmd().outputBytes, _el$369);
3610
3636
  _$insert(_el$346, (() => {
3611
- var _c$24 = _$memo(() => !!cmd().truncated);
3612
- return () => _c$24() && (() => {
3637
+ var _c$25 = _$memo(() => !!cmd().truncated);
3638
+ return () => _c$25() && (() => {
3613
3639
  var _el$380 = _$createElement("span");
3614
3640
  _$insertNode(_el$380, _$createTextNode(` \xB7 \u26A0 truncated`));
3615
3641
  _$effect((_$p) => _$setProp(_el$380, "style", {
@@ -3622,8 +3648,8 @@ Write scope: `);
3622
3648
  _$insertNode(_el$370, _el$371);
3623
3649
  _$insert(_el$370, () => ageLabel(cmd().updatedAt, clock()), null);
3624
3650
  _$insert(_el$346, (() => {
3625
- var _c$25 = _$memo(() => !!cmd().lastError);
3626
- return () => _c$25() && [(() => {
3651
+ var _c$26 = _$memo(() => !!cmd().lastError);
3652
+ return () => _c$26() && [(() => {
3627
3653
  var _el$382 = _$createElement("span"), _el$383 = _$createTextNode(`
3628
3654
  \u26A0 Error: `);
3629
3655
  _$insertNode(_el$382, _el$383);
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.13.0",
4
+ "version": "1.13.1",
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",