@prevalentware/opencode-goal-plugin 0.1.9 → 0.1.10

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/tui.tsx +16 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prevalentware/opencode-goal-plugin",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "Codex-style long-running goal mode for OpenCode.",
5
5
  "keywords": [
6
6
  "opencode",
package/src/tui.tsx CHANGED
@@ -1,6 +1,6 @@
1
1
  /** @jsxImportSource @opentui/solid */
2
2
  import type { TuiPlugin, TuiPluginApi, TuiPluginModule } from "@opencode-ai/plugin/tui"
3
- import { createMemo, Show } from "solid-js"
3
+ import { createMemo, createSignal, onCleanup, Show } from "solid-js"
4
4
 
5
5
  type GoalSnapshot = {
6
6
  sessionID: string
@@ -125,6 +125,17 @@ function formatDurationBadge(seconds: number) {
125
125
  return formatDuration(seconds)
126
126
  }
127
127
 
128
+ function currentEpochSeconds() {
129
+ return Math.floor(Date.now() / 1000)
130
+ }
131
+
132
+ export function liveTimeUsedSeconds(goal: GoalSnapshot, nowSeconds = currentEpochSeconds()) {
133
+ const baseSeconds = Math.max(0, Math.floor(goal.timeUsedSeconds))
134
+ if (visibleStatus(goal.status) !== "active") return baseSeconds
135
+ if (typeof goal.sampledAt !== "number") return baseSeconds
136
+ return baseSeconds + Math.max(0, Math.floor(nowSeconds - goal.sampledAt))
137
+ }
138
+
128
139
  function isRecord(value: unknown): value is Record<string, unknown> {
129
140
  return typeof value === "object" && value !== null
130
141
  }
@@ -200,6 +211,9 @@ function formatGoal(goal: GoalSnapshot | null) {
200
211
 
201
212
  function GoalSidebar(props: { api: TuiPluginApi; sessionID: string }) {
202
213
  const theme = () => props.api.theme.current
214
+ const [nowSeconds, setNowSeconds] = createSignal(currentEpochSeconds())
215
+ const timer = setInterval(() => setNowSeconds(currentEpochSeconds()), 1000)
216
+ onCleanup(() => clearInterval(timer))
203
217
  const state = createMemo(() => {
204
218
  props.api.state.session.messages(props.sessionID)
205
219
  return goalStateFromSession(props.api, props.sessionID)
@@ -207,7 +221,7 @@ function GoalSidebar(props: { api: TuiPluginApi; sessionID: string }) {
207
221
  const goal = createMemo(() => state().goal)
208
222
  const elapsed = createMemo(() => {
209
223
  const value = goal()
210
- return value?.timeUsedSeconds ?? 0
224
+ return value ? liveTimeUsedSeconds(value, nowSeconds()) : 0
211
225
  })
212
226
  const objective = createMemo(() => {
213
227
  const value = goal()?.objective ?? ""