@opencode-cockpit/shell 0.1.4 → 0.2.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.
Files changed (77) hide show
  1. package/README.md +100 -10
  2. package/dist/agent/plugin.js +180 -0
  3. package/dist/agent/tools/index.js +23 -0
  4. package/{src/tools/keys.ts → dist/agent/tools/keys.js} +11 -14
  5. package/dist/agent/tools/list.js +68 -0
  6. package/dist/agent/tools/read.js +59 -0
  7. package/dist/agent/tools/restart.js +44 -0
  8. package/dist/agent/tools/send.js +71 -0
  9. package/dist/agent/tools/shared.js +94 -0
  10. package/dist/agent/tools/start.js +140 -0
  11. package/dist/agent/tools/stop.js +42 -0
  12. package/dist/agent/tools/wait.js +79 -0
  13. package/dist/agent/tools/watch-args.js +12 -0
  14. package/dist/agent/tools/watch.js +74 -0
  15. package/dist/connect.js +31 -0
  16. package/dist/core/config.js +97 -0
  17. package/dist/core/find.js +69 -0
  18. package/dist/core/format.js +63 -0
  19. package/dist/core/kind.js +31 -0
  20. package/dist/server.js +2 -0
  21. package/dist/tui/components/badge.js +29 -0
  22. package/dist/tui/components/console.js +759 -0
  23. package/dist/tui/components/dock.js +270 -0
  24. package/dist/tui/components/sidebar.js +136 -0
  25. package/dist/tui/dialogs.js +163 -0
  26. package/dist/tui/index.js +205 -0
  27. package/dist/tui/lib/details.js +23 -0
  28. package/dist/tui/lib/keys.js +43 -0
  29. package/dist/tui/lib/search.js +39 -0
  30. package/dist/tui/lib/update.js +58 -0
  31. package/dist/tui/lib/view.js +191 -0
  32. package/dist/tui/state/store.js +158 -0
  33. package/package.json +21 -12
  34. package/types/agent/plugin.d.ts +12 -0
  35. package/types/agent/tools/index.d.ts +5 -0
  36. package/types/agent/tools/keys.d.ts +3 -0
  37. package/types/agent/tools/list.d.ts +3 -0
  38. package/types/agent/tools/read.d.ts +3 -0
  39. package/types/agent/tools/restart.d.ts +3 -0
  40. package/types/agent/tools/send.d.ts +3 -0
  41. package/types/agent/tools/shared.d.ts +40 -0
  42. package/types/agent/tools/start.d.ts +3 -0
  43. package/types/agent/tools/stop.d.ts +3 -0
  44. package/types/agent/tools/wait.d.ts +3 -0
  45. package/types/agent/tools/watch-args.d.ts +10 -0
  46. package/types/agent/tools/watch.d.ts +3 -0
  47. package/types/connect.d.ts +9 -0
  48. package/types/core/config.d.ts +59 -0
  49. package/types/core/find.d.ts +37 -0
  50. package/types/core/format.d.ts +8 -0
  51. package/types/core/kind.d.ts +9 -0
  52. package/types/server.d.ts +2 -0
  53. package/types/tui/components/badge.d.ts +9 -0
  54. package/types/tui/components/console.d.ts +22 -0
  55. package/types/tui/components/dock.d.ts +14 -0
  56. package/types/tui/components/sidebar.d.ts +14 -0
  57. package/types/tui/dialogs.d.ts +10 -0
  58. package/types/tui/index.d.ts +13 -0
  59. package/types/tui/lib/details.d.ts +3 -0
  60. package/types/tui/lib/keys.d.ts +8 -0
  61. package/types/tui/lib/search.d.ts +7 -0
  62. package/types/tui/lib/update.d.ts +25 -0
  63. package/types/tui/lib/view.d.ts +80 -0
  64. package/types/tui/state/store.d.ts +55 -0
  65. package/src/connect.ts +0 -24
  66. package/src/server.ts +0 -156
  67. package/src/tools/find.ts +0 -80
  68. package/src/tools/format.ts +0 -78
  69. package/src/tools/index.ts +0 -467
  70. package/src/tui/badge.tsx +0 -17
  71. package/src/tui/console.tsx +0 -438
  72. package/src/tui/dock.tsx +0 -130
  73. package/src/tui/index.tsx +0 -286
  74. package/src/tui/keys.ts +0 -52
  75. package/src/tui/sidebar.tsx +0 -44
  76. package/src/tui/store.ts +0 -185
  77. package/src/tui/view.ts +0 -161
package/src/tui/view.ts DELETED
@@ -1,161 +0,0 @@
1
- import type { TuiThemeCurrent } from "@opencode-ai/plugin/tui"
2
- import type { ShellInfo } from "@opencode-cockpit/protocol/shell"
3
- import { duration } from "../tools/format.ts"
4
-
5
- /** What a human cares about, derived from status + exit code so every surface agrees. */
6
- export type Kind = "run" | "fail" | "stop" | "done"
7
-
8
- export function kindOf(s: ShellInfo): Kind {
9
- if (s.status === "running") return "run"
10
- if (s.status === "killed") return "stop"
11
- if (s.status === "exited" && s.exitCode === 0) return "done"
12
- return "fail"
13
- }
14
-
15
- export const BADGE_LABEL: Record<Kind, string> = { run: "RUN", fail: "FAIL", stop: "STOP", done: "DONE" }
16
-
17
- /** Braille spinner: single-width in every terminal font. */
18
- export const SPINNER = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
19
-
20
- export function kindColor(theme: TuiThemeCurrent, kind: Kind) {
21
- switch (kind) {
22
- case "run":
23
- return theme.success
24
- case "fail":
25
- return theme.error
26
- case "stop":
27
- return theme.warning
28
- case "done":
29
- return theme.textMuted
30
- }
31
- }
32
-
33
- /** Fixed 7-column pill so lists line up: " ⠹ RUN ", " FAIL ". */
34
- export function badgeText(kind: Kind, frame = 0): string {
35
- if (kind === "run") return ` ${SPINNER[frame % SPINNER.length]} RUN `
36
- return ` ${BADGE_LABEL[kind].padEnd(4)} `
37
- }
38
-
39
- const RANK: Record<Kind, number> = { run: 0, fail: 1, stop: 2, done: 3 }
40
-
41
- /** Running first (oldest first, stable tabs), then failures, stopped, done (most recent first). */
42
- export function order(list: readonly ShellInfo[]): ShellInfo[] {
43
- return [...list].sort((a, b) => {
44
- const ka = kindOf(a)
45
- const kb = kindOf(b)
46
- if (ka !== kb) return RANK[ka] - RANK[kb]
47
- if (ka === "run") return a.startedAt - b.startedAt
48
- return (b.endedAt ?? b.startedAt) - (a.endedAt ?? a.startedAt)
49
- })
50
- }
51
-
52
- export interface PartitionOptions {
53
- showAll: boolean
54
- /** Failures stay visible this long after they end. */
55
- historyMs: number
56
- now: number
57
- /** Always visible, so the selection never disappears under the user. */
58
- keep?: string
59
- }
60
-
61
- /** Default view: running shells and recent failures. Everything else folds into a "N more" chip. */
62
- export function partition(list: readonly ShellInfo[], opts: PartitionOptions) {
63
- const ordered = order(list)
64
- if (opts.showAll) return { visible: ordered, hidden: [] as ShellInfo[] }
65
- const visible: ShellInfo[] = []
66
- const hidden: ShellInfo[] = []
67
- for (const s of ordered) {
68
- const kind = kindOf(s)
69
- const recent = opts.now - (s.endedAt ?? opts.now) <= opts.historyMs
70
- if (kind === "run" || (kind === "fail" && recent) || s.id === opts.keep) visible.push(s)
71
- else hidden.push(s)
72
- }
73
- return { visible, hidden }
74
- }
75
-
76
- export function statusDetail(s: ShellInfo, now: number): string {
77
- const kind = kindOf(s)
78
- const ran = duration((s.endedAt ?? now) - s.startedAt)
79
- const ago = s.endedAt ? since(now - s.endedAt) : ""
80
- switch (kind) {
81
- case "run":
82
- return ran
83
- case "done":
84
- return `took ${ran} · ${ago}`
85
- case "stop":
86
- return `stopped after ${ran} · ${ago}`
87
- case "fail":
88
- if (s.status === "failed") return "could not start"
89
- return `exit ${s.exitCode ?? "?"} after ${ran} · ${ago}`
90
- }
91
- }
92
-
93
- /** Compact detail for narrow lists. */
94
- export function shortDetail(s: ShellInfo, now: number): string {
95
- switch (kindOf(s)) {
96
- case "run":
97
- return duration(now - s.startedAt)
98
- case "fail":
99
- return s.status === "failed" ? "no start" : `exit ${s.exitCode ?? "?"}`
100
- case "stop":
101
- return "stopped"
102
- case "done":
103
- return s.endedAt ? since(now - s.endedAt) : "done"
104
- }
105
- }
106
-
107
- /** Coarse relative time: "just now", "12s ago", "9m ago", "3h ago". */
108
- export function since(ms: number): string {
109
- const s = Math.floor(ms / 1000)
110
- if (s < 5) return "just now"
111
- if (s < 60) return `${s}s ago`
112
- if (s < 3600) return `${Math.floor(s / 60)}m ago`
113
- if (s < 86_400) return `${Math.floor(s / 3600)}h ago`
114
- return `${Math.floor(s / 86_400)}d ago`
115
- }
116
-
117
- /** The command as the user or agent wrote it, without the `$SHELL -c` wrapper. */
118
- export function displayCommand(s: ShellInfo): string {
119
- if (s.args.length === 2 && s.args[0] === "-c" && /(^|\/)(ba|z|fi|da|k)?sh$/.test(s.command))
120
- return s.args[1] as string
121
- return [s.command, ...s.args].join(" ")
122
- }
123
-
124
- /** Folder relative to the project: "" at the root, "./sub" inside, "~/x" elsewhere under home. */
125
- export function relativeCwd(cwd: string, project: string, home = process.env.HOME ?? ""): string {
126
- const trim = (p: string) => p.replace(/\/+$/, "")
127
- const c = trim(cwd)
128
- const p = trim(project)
129
- if (c === p) return ""
130
- if (c.startsWith(`${p}/`)) return `./${c.slice(p.length + 1)}`
131
- if (home && c.startsWith(`${trim(home)}/`)) return `~/${c.slice(trim(home).length + 1)}`
132
- return c
133
- }
134
-
135
- /** Hard-wraps to `width`, at most `maxLines`; the last line ends with … when text was cut. */
136
- export function wrapText(text: string, width: number, maxLines: number): string[] {
137
- const flat = text.replace(/\s*\n\s*/g, " ⏎ ")
138
- const w = Math.max(4, width)
139
- const lines: string[] = []
140
- for (let i = 0; i < flat.length && lines.length < maxLines; i += w) lines.push(flat.slice(i, i + w))
141
- if (lines.length === 0) return [""]
142
- if (flat.length > w * maxLines) {
143
- const last = lines[lines.length - 1] as string
144
- lines[lines.length - 1] = `${last.slice(0, w - 1)}…`
145
- }
146
- return lines
147
- }
148
-
149
- /** Last `rows` lines of screen text, each cut to `cols`. */
150
- export function tailLines(text: string | undefined, rows: number, cols: number): string {
151
- if (!text) return ""
152
- const lines = text.split("\n")
153
- return lines
154
- .slice(Math.max(0, lines.length - rows))
155
- .map((l) => (l.length > cols ? `${l.slice(0, Math.max(0, cols - 1))}…` : l))
156
- .join("\n")
157
- }
158
-
159
- export function truncate(text: string, max: number): string {
160
- return text.length > max ? `${text.slice(0, Math.max(0, max - 1))}…` : text
161
- }