opencode-ultracode 0.1.0

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.
@@ -0,0 +1,189 @@
1
+ // Shared types between the server plugin (engine) and the TUI plugin (views).
2
+ // The state file written by the server is the single source of truth the TUI polls.
3
+
4
+ import { createHash } from "node:crypto"
5
+ import { tmpdir } from "node:os"
6
+ import { basename } from "node:path"
7
+
8
+ export type RunStatus =
9
+ | "pending"
10
+ | "running"
11
+ | "paused"
12
+ | "completed"
13
+ | "failed"
14
+ | "stopped"
15
+
16
+ export type AgentStatus =
17
+ | "queued"
18
+ | "running"
19
+ | "completed"
20
+ | "failed"
21
+ | "cancelled"
22
+
23
+ export interface PhaseDef {
24
+ title: string
25
+ detail?: string
26
+ model?: string
27
+ }
28
+
29
+ export interface PhaseState extends PhaseDef {
30
+ /** 1-based progress index shown in the left pane */
31
+ index: number
32
+ /** agent ids that belong to this phase, in spawn order */
33
+ agentIds: string[]
34
+ /** how many of those agents reached a terminal state */
35
+ done: number
36
+ }
37
+
38
+ export interface AgentActivity {
39
+ /** "tool" (default) for tool calls, "think" for a reasoning/thinking block */
40
+ kind?: "tool" | "think"
41
+ /** host tool-call id (when the host sends one) — used to match updates */
42
+ callId?: string
43
+ /** tool name, e.g. "StructuredOutput" or "bash"; "think" for reasoning entries */
44
+ tool: string
45
+ /** short title / first words of the call */
46
+ title: string
47
+ /** preview of the result (truncated) */
48
+ preview?: string
49
+ startedAt: number
50
+ endedAt?: number
51
+ }
52
+
53
+ export interface AgentState {
54
+ id: string
55
+ /** display label, e.g. "tip:design" */
56
+ label: string
57
+ /** phase title this agent runs under */
58
+ phase: string
59
+ phaseIndex: number
60
+ status: AgentStatus
61
+ /** resolved model, e.g. "anthropic/claude-sonnet-4" or "qwen3.8" */
62
+ model: string
63
+ /**
64
+ * BILLED tokens: sum over every API call this agent made of
65
+ * input+output+reasoning+cache read/write. Each call re-sends the whole
66
+ * context, so this grows quadratically with tool-call count and is much
67
+ * larger than the context size. Matches `cost`.
68
+ */
69
+ tokens: number
70
+ /**
71
+ * CONTEXT size: prompt tokens (input + cache read/write) of the LATEST API
72
+ * call, i.e. how big the agent's context actually is right now.
73
+ */
74
+ contextTokens: number
75
+ outputTokens: number
76
+ cost: number
77
+ toolCalls: number
78
+ activity: AgentActivity[]
79
+ prompt: string
80
+ outcome?: unknown
81
+ /** raw final text (truncated for display) */
82
+ outcomeText?: string
83
+ /** latest LLM text chunk seen while the agent is running (live view) */
84
+ liveText?: string
85
+ /** recent live activity (text chunks, thinking, tool calls), newest last, capped */
86
+ liveFeed?: { at: number; kind: "text" | "tool" | "think"; text: string }[]
87
+ startedAt?: number
88
+ endedAt?: number
89
+ error?: string
90
+ sessionId?: string
91
+ /** true when this agent's result was replayed from a previous run of the same runId (resume) */
92
+ replayed?: boolean
93
+ }
94
+
95
+ export interface RunLogEntry {
96
+ at: number
97
+ message: string
98
+ }
99
+
100
+ export interface RunState {
101
+ runId: string
102
+ status: RunStatus
103
+ /** workflow meta */
104
+ name: string
105
+ description: string
106
+ whenToUse?: string
107
+ /** phases in display order (from meta.phases, plus any discovered) */
108
+ phases: PhaseState[]
109
+ /** every agent, in spawn order */
110
+ agents: Record<string, AgentState>
111
+ /** agent ids in spawn order */
112
+ agentOrder: string[]
113
+ logs: RunLogEntry[]
114
+ /** total agents spawned so far */
115
+ agentCount: number
116
+ /** agents that reached a terminal state */
117
+ agentDone: number
118
+ startedAt: number
119
+ endedAt?: number
120
+ /** total BILLED tokens across all agents (see AgentState.tokens) */
121
+ totalTokens: number
122
+ /** sum of every agent's current context size (see AgentState.contextTokens) */
123
+ totalContextTokens: number
124
+ totalCost: number
125
+ /** resolved script path (for save) */
126
+ scriptPath?: string
127
+ /** the workflow's final return value (stringified for storage) */
128
+ result?: string
129
+ /** error message if failed */
130
+ error?: string
131
+ /** the directory this run was created in */
132
+ directory: string
133
+ /** opencode session that started the run; the result turn is delivered here (also after a resume) */
134
+ mainSessionID?: string
135
+ /** model the starting session used; agents without an explicit model inherit it (needed to resume) */
136
+ defaultModel?: string
137
+ /** the script's `args` value, kept so a resume re-runs the script with the same input */
138
+ args?: unknown
139
+ /** set when the run was resumed after its engine died (opencode exit/crash) */
140
+ resumedAt?: number
141
+ /** how many times the run has been resumed */
142
+ resumeCount?: number
143
+ }
144
+
145
+ /**
146
+ * control.json written by the TUI. A live engine polls it for pause/resume/stop.
147
+ * `resume` on a run with no live engine (opencode exited while it ran) asks the
148
+ * server plugin to restart the run: completed agents replay from the journal,
149
+ * the rest run again.
150
+ */
151
+ export interface ControlState {
152
+ action?: "pause" | "resume" | "stop"
153
+ pause?: boolean
154
+ resume?: boolean
155
+ stop?: boolean
156
+ at?: number
157
+ }
158
+
159
+ // --- wire helpers -----------------------------------------------------------
160
+
161
+ /**
162
+ * Where run artifacts (state.json, journal.jsonl, script.js, control.json) live:
163
+ * /tmp/opencode-workflows/<project-name>-<hash6>. Runs are scratch data, so they
164
+ * stay out of the project tree; the hash suffix keeps two projects with the same
165
+ * folder name (e.g. two "api" checkouts) from sharing a run list.
166
+ * Saved workflows (<name>.js) are project assets and stay under workflowRoot().
167
+ */
168
+ export function runsRoot(worktree: string): string {
169
+ const base = process.platform === "win32" ? tmpdir() : "/tmp"
170
+ const name = (basename(worktree) || "project").replace(/[^a-zA-Z0-9._-]/g, "-")
171
+ const hash = createHash("sha1").update(worktree).digest("hex").slice(0, 6)
172
+ return `${base}/opencode-workflows/${name}-${hash}`
173
+ }
174
+ export function runDir(runsRootDir: string, runId: string): string {
175
+ return `${runsRootDir}/${runId}`
176
+ }
177
+ export function statePath(runsRootDir: string, runId: string): string {
178
+ return `${runDir(runsRootDir, runId)}/state.json`
179
+ }
180
+ export function controlPath(runsRootDir: string, runId: string): string {
181
+ return `${runDir(runsRootDir, runId)}/control.json`
182
+ }
183
+ export function journalPath(runsRootDir: string, runId: string): string {
184
+ return `${runDir(runsRootDir, runId)}/journal.jsonl`
185
+ }
186
+ /** saved (named) workflow scripts: <worktree>/.opencode/workflows/<name>.js */
187
+ export function workflowRoot(worktree: string): string {
188
+ return `${worktree}/.opencode/workflows`
189
+ }