@opencode-cockpit/shell 0.1.5 → 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 (64) 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/dist/agent/tools/list.js +68 -0
  5. package/dist/agent/tools/read.js +59 -0
  6. package/dist/agent/tools/restart.js +44 -0
  7. package/dist/agent/tools/send.js +71 -0
  8. package/dist/agent/tools/shared.js +94 -0
  9. package/dist/agent/tools/start.js +140 -0
  10. package/dist/agent/tools/stop.js +42 -0
  11. package/dist/agent/tools/wait.js +79 -0
  12. package/dist/agent/tools/watch-args.js +12 -0
  13. package/dist/agent/tools/watch.js +74 -0
  14. package/dist/core/config.js +97 -0
  15. package/dist/{tools → core}/find.js +3 -0
  16. package/dist/core/kind.js +31 -0
  17. package/dist/server.js +2 -152
  18. package/dist/tui/{badge.js → components/badge.js} +1 -1
  19. package/dist/tui/{console.js → components/console.js} +270 -139
  20. package/dist/tui/{dock.js → components/dock.js} +75 -19
  21. package/dist/tui/{sidebar.js → components/sidebar.js} +16 -1
  22. package/dist/tui/dialogs.js +163 -0
  23. package/dist/tui/index.js +35 -94
  24. package/dist/tui/lib/details.js +23 -0
  25. package/dist/tui/lib/search.js +39 -0
  26. package/dist/tui/lib/update.js +58 -0
  27. package/dist/tui/{view.js → lib/view.js} +38 -1
  28. package/dist/tui/{store.js → state/store.js} +4 -2
  29. package/package.json +4 -5
  30. package/types/agent/plugin.d.ts +12 -0
  31. package/types/agent/tools/index.d.ts +5 -0
  32. package/types/agent/tools/list.d.ts +3 -0
  33. package/types/agent/tools/read.d.ts +3 -0
  34. package/types/agent/tools/restart.d.ts +3 -0
  35. package/types/agent/tools/send.d.ts +3 -0
  36. package/types/agent/tools/shared.d.ts +40 -0
  37. package/types/agent/tools/start.d.ts +3 -0
  38. package/types/agent/tools/stop.d.ts +3 -0
  39. package/types/agent/tools/wait.d.ts +3 -0
  40. package/types/agent/tools/watch-args.d.ts +10 -0
  41. package/types/agent/tools/watch.d.ts +3 -0
  42. package/types/core/config.d.ts +59 -0
  43. package/types/{tools → core}/find.d.ts +5 -0
  44. package/types/core/kind.d.ts +9 -0
  45. package/types/server.d.ts +2 -12
  46. package/types/tui/{console.d.ts → components/console.d.ts} +7 -1
  47. package/types/tui/{dock.d.ts → components/dock.d.ts} +3 -1
  48. package/types/tui/{sidebar.d.ts → components/sidebar.d.ts} +1 -1
  49. package/types/tui/dialogs.d.ts +10 -0
  50. package/types/tui/index.d.ts +3 -9
  51. package/types/tui/lib/details.d.ts +3 -0
  52. package/types/tui/lib/search.d.ts +7 -0
  53. package/types/tui/lib/update.d.ts +25 -0
  54. package/types/tui/{view.d.ts → lib/view.d.ts} +14 -1
  55. package/types/tui/{store.d.ts → state/store.d.ts} +9 -0
  56. package/dist/tools/index.js +0 -433
  57. package/types/tools/index.d.ts +0 -17
  58. /package/dist/{tools → agent/tools}/keys.js +0 -0
  59. /package/dist/{tools → core}/format.js +0 -0
  60. /package/dist/tui/{keys.js → lib/keys.js} +0 -0
  61. /package/types/{tools → agent/tools}/keys.d.ts +0 -0
  62. /package/types/{tools → core}/format.d.ts +0 -0
  63. /package/types/tui/{badge.d.ts → components/badge.d.ts} +0 -0
  64. /package/types/tui/{keys.d.ts → lib/keys.d.ts} +0 -0
package/dist/server.js CHANGED
@@ -1,152 +1,2 @@
1
- import { claimFeature, duplicateFeatureMessage } from "@opencode-cockpit/client";
2
- import { createClient } from "./connect.js";
3
- import { describeStatus, formatLines } from "./tools/format.js";
4
- import { createTools } from "./tools/index.js";
5
- const GUIDANCE = `## Background shells (opencode-cockpit)
6
- Long-running or interactive commands (dev servers, watchers, slow builds/tests, REPLs) go in shell_start, not bash with "&".
7
- Block with shell_wait (pattern, port, idle, exit) instead of sleeping; follow output with shell_read(after=cursor).
8
- You are messaged when a shell you started exits.`;
9
- export const SHELL_PACKAGE = "@opencode-cockpit/shell";
10
- /** Shell's server half as a factory, so bundles such as `opencode-cockpit` can include it. */
11
- export function createShellServer({
12
- source = SHELL_PACKAGE
13
- } = {}) {
14
- return async input => {
15
- const claim = claimFeature(input, "shell", source);
16
- if (!claim.active) {
17
- // Logging through the server during plugin initialisation could wait on ourselves; defer it.
18
- setTimeout(() => {
19
- void input.client.app.log({
20
- body: {
21
- service: "opencode-cockpit",
22
- level: "warn",
23
- message: duplicateFeatureMessage("Shell", claim.owner, source)
24
- }
25
- }).catch(() => {});
26
- }, 0);
27
- return {};
28
- }
29
- const hooks = await shellHooks(input);
30
- const dispose = hooks.dispose;
31
- return {
32
- ...hooks,
33
- dispose: async () => {
34
- claim.release();
35
- await dispose?.();
36
- }
37
- };
38
- };
39
- }
40
- async function shellHooks({
41
- client: opencode,
42
- directory
43
- }) {
44
- const cockpit = createClient("opencode-cockpit/server");
45
- const instance = crypto.randomUUID();
46
- const quiet = new Set();
47
- const userShell = process.env.SHELL && /(bash|zsh|fish|sh)$/.test(process.env.SHELL) ? process.env.SHELL : "/bin/bash";
48
- const env = () => {
49
- const out = {};
50
- for (const [k, v] of Object.entries(process.env)) if (v !== undefined && !k.startsWith("OPENCODE_")) out[k] = v;
51
- return out;
52
- };
53
-
54
- // Session titles rarely change; cache them so listing shells stays one round trip.
55
- const titles = new Map();
56
- const sessionTitle = async sessionID => {
57
- const hit = titles.get(sessionID);
58
- if (hit && Date.now() - hit.at < 60_000) return hit.title;
59
- const result = await opencode.session.get({
60
- path: {
61
- id: sessionID
62
- }
63
- }).catch(() => undefined);
64
- const title = result?.data?.title;
65
- titles.set(sessionID, {
66
- title,
67
- at: Date.now()
68
- });
69
- return title;
70
- };
71
-
72
- // Wake the agent when a shell it owns ends on its own.
73
- cockpit.on("shell.exited", info => {
74
- if (info.owner.instance !== instance || !info.owner.session) return;
75
- if (quiet.delete(info.id)) return;
76
- void notifyExit(info).catch(() => {});
77
- });
78
- async function notifyExit(info) {
79
- const session = info.owner.session;
80
- const page = await cockpit.call("shell.read", {
81
- id: info.id,
82
- tail: 15
83
- });
84
- const failed = info.status === "failed" || info.status === "exited" && info.exitCode !== 0 || info.status === "killed";
85
- const text = [`<shell_exited id="${info.id}" title="${info.title}">`, describeStatus(info), page.lines.length > 0 ? `last output:\n${formatLines(page.lines)}` : "(no output)", "</shell_exited>", failed ? `Investigate with shell_read id=${info.id} grep="error|fail" if the failure matters to the task.` : `Full output: shell_read id=${info.id}.`].join("\n");
86
- await opencode.session.promptAsync({
87
- path: {
88
- id: session
89
- },
90
- body: {
91
- parts: [{
92
- type: "text",
93
- text,
94
- synthetic: true
95
- }]
96
- }
97
- });
98
- }
99
- return {
100
- tool: createTools({
101
- client: cockpit,
102
- instance,
103
- quiet,
104
- env,
105
- sessionTitle,
106
- shellCommand: command => ({
107
- command: userShell,
108
- args: ["-c", command]
109
- })
110
- }),
111
- "experimental.chat.system.transform": async (input, output) => {
112
- output.system.push(GUIDANCE);
113
- const running = await cockpit.call("shell.list", {
114
- owner: {
115
- project: directory
116
- },
117
- includeExited: false
118
- }).catch(() => []);
119
- if (running.length > 0) {
120
- output.system.push(`Background shells currently running in this project:\n${running.slice(0, 15).map(s => {
121
- const from = !s.owner.session ? ", started by the user" : s.owner.session === input.sessionID ? "" : ", another session";
122
- return `- ${s.id} "${s.title}" (${describeStatus(s)}${from})`;
123
- }).join("\n")}`);
124
- }
125
- },
126
- event: async ({
127
- event
128
- }) => {
129
- if (event.type !== "session.deleted") return;
130
- const sessionID = event.properties.info.id;
131
- const owned = await cockpit.call("shell.list", {
132
- owner: {
133
- session: sessionID
134
- }
135
- }).catch(() => []);
136
- for (const shell of owned) {
137
- quiet.add(shell.id);
138
- await cockpit.call("shell.remove", {
139
- id: shell.id
140
- }).catch(() => {});
141
- }
142
- },
143
- dispose: async () => {
144
- cockpit.close();
145
- }
146
- };
147
- }
148
- const plugin = {
149
- id: "opencode-cockpit.shell",
150
- server: createShellServer()
151
- };
152
- export default plugin;
1
+ /** Published entry point: `@opencode-cockpit/shell/server`. */
2
+ export { createShellServer, default, SHELL_PACKAGE } from "./agent/plugin.js";
@@ -5,7 +5,7 @@ import { setProp as _$setProp } from "@opentui/solid";
5
5
  import { createElement as _$createElement } from "@opentui/solid";
6
6
  /** @jsxImportSource @opentui/solid */
7
7
 
8
- import { badgeText, kindColor, kindOf } from "./view.js";
8
+ import { badgeText, kindColor, kindOf } from "../lib/view.js";
9
9
 
10
10
  /** Status pill: label on a coloured background, readable in any font and colour scheme. */
11
11
  export function Badge(props) {