@devframes/plugin-terminals 0.0.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/LICENSE.md +21 -0
- package/bin.mjs +13 -0
- package/dist/cli.d.mts +12 -0
- package/dist/cli.mjs +13 -0
- package/dist/client/index.d.mts +16 -0
- package/dist/client/index.mjs +12095 -0
- package/dist/constants.d.mts +30 -0
- package/dist/constants.mjs +30 -0
- package/dist/index.d.mts +28 -0
- package/dist/index.mjs +3 -0
- package/dist/node/index.d.mts +157 -0
- package/dist/node/index.mjs +580 -0
- package/dist/rpc/index.d.mts +695 -0
- package/dist/rpc/index.mjs +2 -0
- package/dist/rpc-F1ncx7tt.mjs +247 -0
- package/dist/spa/assets/index-Dmm_EwpX.js +38 -0
- package/dist/spa/assets/index-IBTOt_--.css +1 -0
- package/dist/spa/index.html +19 -0
- package/dist/src-Cu5HYNrI.mjs +56 -0
- package/dist/types.d.mts +129 -0
- package/dist/types.mjs +1 -0
- package/dist/vite.d.mts +18 -0
- package/dist/vite.mjs +20 -0
- package/package.json +88 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { defineRpcFunction } from "devframe";
|
|
2
|
+
import * as v from "valibot";
|
|
3
|
+
import { colors } from "devframe/utils/colors";
|
|
4
|
+
import { defineDiagnostics } from "nostics";
|
|
5
|
+
import { ansiFormatter } from "nostics/formatters/ansi";
|
|
6
|
+
//#region src/node/diagnostics.ts
|
|
7
|
+
const formatAnsi = ansiFormatter(colors);
|
|
8
|
+
function reporter(d, { method = "warn" } = {}) {
|
|
9
|
+
console[method](formatAnsi(d));
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Structured diagnostics for the terminals plugin. Uses the plugin's own
|
|
13
|
+
* `DP_TERMINALS_` prefix per the built-in plugin convention, keeping it
|
|
14
|
+
* collision-free with devframe core (`DF`) and the hub (`DF8xxx`).
|
|
15
|
+
*/
|
|
16
|
+
const diagnostics = defineDiagnostics({
|
|
17
|
+
docsBase: "https://devfra.me/errors",
|
|
18
|
+
reporters: [reporter],
|
|
19
|
+
codes: {
|
|
20
|
+
DP_TERMINALS_0001: {
|
|
21
|
+
why: (p) => `Terminal session "${p.id}" does not exist`,
|
|
22
|
+
fix: "Spawn a session first, or refresh the session list."
|
|
23
|
+
},
|
|
24
|
+
DP_TERMINALS_0002: {
|
|
25
|
+
why: (p) => `Spawning the arbitrary command "${p.command}" is not allowed`,
|
|
26
|
+
fix: "Add it to `presets`, or pass `allowArbitraryCommands: true` to createTerminalsDevframe()."
|
|
27
|
+
},
|
|
28
|
+
DP_TERMINALS_0003: {
|
|
29
|
+
why: (p) => `Cannot write to read-only terminal session "${p.id}"`,
|
|
30
|
+
fix: "Spawn the session with `mode: \"interactive\"` to accept input."
|
|
31
|
+
},
|
|
32
|
+
DP_TERMINALS_0004: { why: (p) => `Failed to spawn "${p.command}": ${p.reason}` },
|
|
33
|
+
DP_TERMINALS_0005: {
|
|
34
|
+
why: "Native PTY bindings (zigpty) are unavailable; interactive sessions fall back to pipe-based terminal emulation. Full-screen TUIs may not render correctly.",
|
|
35
|
+
fix: "Check that this platform is covered by zigpty's prebuilds (Linux/macOS/Windows, x64/arm64, glibc/musl) and that the dependency installed intact."
|
|
36
|
+
},
|
|
37
|
+
DP_TERMINALS_0006: { why: (p) => `Unknown terminal preset "${p.id}"` },
|
|
38
|
+
DP_TERMINALS_0007: {
|
|
39
|
+
why: "Terminals manager is not initialised on this context",
|
|
40
|
+
fix: "Call setupTerminals(ctx) (or use createTerminalsDevframe) before invoking terminal RPCs."
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/node/context.ts
|
|
46
|
+
const managers = /* @__PURE__ */ new WeakMap();
|
|
47
|
+
function setTerminalManager(ctx, manager) {
|
|
48
|
+
managers.set(ctx, manager);
|
|
49
|
+
}
|
|
50
|
+
function getTerminalManager(ctx) {
|
|
51
|
+
const manager = managers.get(ctx);
|
|
52
|
+
if (!manager) throw diagnostics.DP_TERMINALS_0007({});
|
|
53
|
+
return manager;
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/rpc/schemas.ts
|
|
57
|
+
const terminalModeSchema = v.picklist(["interactive", "readonly"]);
|
|
58
|
+
const spawnRequestSchema = v.object({
|
|
59
|
+
presetId: v.optional(v.string()),
|
|
60
|
+
command: v.optional(v.string()),
|
|
61
|
+
args: v.optional(v.array(v.string())),
|
|
62
|
+
cwd: v.optional(v.string()),
|
|
63
|
+
mode: v.optional(terminalModeSchema),
|
|
64
|
+
title: v.optional(v.string()),
|
|
65
|
+
cols: v.optional(v.number()),
|
|
66
|
+
rows: v.optional(v.number()),
|
|
67
|
+
env: v.optional(v.record(v.string(), v.string()))
|
|
68
|
+
});
|
|
69
|
+
const sessionInfoSchema = v.object({
|
|
70
|
+
id: v.string(),
|
|
71
|
+
title: v.string(),
|
|
72
|
+
processName: v.optional(v.string()),
|
|
73
|
+
customTitle: v.optional(v.string()),
|
|
74
|
+
mode: terminalModeSchema,
|
|
75
|
+
status: v.picklist([
|
|
76
|
+
"running",
|
|
77
|
+
"exited",
|
|
78
|
+
"error"
|
|
79
|
+
]),
|
|
80
|
+
backend: v.picklist(["pty", "pipe"]),
|
|
81
|
+
command: v.string(),
|
|
82
|
+
args: v.array(v.string()),
|
|
83
|
+
cwd: v.string(),
|
|
84
|
+
cols: v.number(),
|
|
85
|
+
rows: v.number(),
|
|
86
|
+
pid: v.optional(v.number()),
|
|
87
|
+
exitCode: v.optional(v.number()),
|
|
88
|
+
icon: v.optional(v.string()),
|
|
89
|
+
channel: v.optional(v.string()),
|
|
90
|
+
presetId: v.optional(v.string()),
|
|
91
|
+
createdAt: v.number()
|
|
92
|
+
});
|
|
93
|
+
const presetSchema = v.object({
|
|
94
|
+
id: v.string(),
|
|
95
|
+
title: v.string(),
|
|
96
|
+
command: v.string(),
|
|
97
|
+
args: v.array(v.string()),
|
|
98
|
+
mode: terminalModeSchema,
|
|
99
|
+
icon: v.optional(v.string())
|
|
100
|
+
});
|
|
101
|
+
//#endregion
|
|
102
|
+
//#region src/rpc/functions/list.ts
|
|
103
|
+
const list = defineRpcFunction({
|
|
104
|
+
name: "devframes-plugin-terminals:list",
|
|
105
|
+
type: "query",
|
|
106
|
+
jsonSerializable: true,
|
|
107
|
+
snapshot: true,
|
|
108
|
+
args: [],
|
|
109
|
+
returns: v.array(sessionInfoSchema),
|
|
110
|
+
agent: {
|
|
111
|
+
description: "List the current terminal sessions with their status, mode, and command.",
|
|
112
|
+
safety: "read"
|
|
113
|
+
},
|
|
114
|
+
setup: (ctx) => ({ handler: () => getTerminalManager(ctx).list() })
|
|
115
|
+
});
|
|
116
|
+
//#endregion
|
|
117
|
+
//#region src/rpc/functions/presets.ts
|
|
118
|
+
const presets = defineRpcFunction({
|
|
119
|
+
name: "devframes-plugin-terminals:presets",
|
|
120
|
+
type: "query",
|
|
121
|
+
jsonSerializable: true,
|
|
122
|
+
snapshot: true,
|
|
123
|
+
args: [],
|
|
124
|
+
returns: v.array(presetSchema),
|
|
125
|
+
setup: (ctx) => ({ handler: () => getTerminalManager(ctx).getPresets().map((p) => ({
|
|
126
|
+
id: p.id,
|
|
127
|
+
title: p.title,
|
|
128
|
+
command: p.command,
|
|
129
|
+
args: p.args ?? [],
|
|
130
|
+
mode: p.mode ?? "readonly",
|
|
131
|
+
icon: p.icon
|
|
132
|
+
})) })
|
|
133
|
+
});
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/rpc/functions/remove.ts
|
|
136
|
+
const remove = defineRpcFunction({
|
|
137
|
+
name: "devframes-plugin-terminals:remove",
|
|
138
|
+
type: "action",
|
|
139
|
+
jsonSerializable: true,
|
|
140
|
+
args: [v.object({ id: v.string() })],
|
|
141
|
+
returns: v.void(),
|
|
142
|
+
agent: {
|
|
143
|
+
description: "Kill a terminal session and discard it (process, stream, and scrollback).",
|
|
144
|
+
safety: "destructive"
|
|
145
|
+
},
|
|
146
|
+
setup: (ctx) => ({ handler: ({ id }) => {
|
|
147
|
+
getTerminalManager(ctx).remove(id);
|
|
148
|
+
} })
|
|
149
|
+
});
|
|
150
|
+
//#endregion
|
|
151
|
+
//#region src/rpc/functions/rename.ts
|
|
152
|
+
const rename = defineRpcFunction({
|
|
153
|
+
name: "devframes-plugin-terminals:rename",
|
|
154
|
+
type: "action",
|
|
155
|
+
jsonSerializable: true,
|
|
156
|
+
args: [v.object({
|
|
157
|
+
id: v.string(),
|
|
158
|
+
title: v.string()
|
|
159
|
+
})],
|
|
160
|
+
returns: v.void(),
|
|
161
|
+
setup: (ctx) => ({ handler: ({ id, title }) => {
|
|
162
|
+
getTerminalManager(ctx).rename(id, title);
|
|
163
|
+
} })
|
|
164
|
+
});
|
|
165
|
+
//#endregion
|
|
166
|
+
//#region src/rpc/functions/resize.ts
|
|
167
|
+
const resize = defineRpcFunction({
|
|
168
|
+
name: "devframes-plugin-terminals:resize",
|
|
169
|
+
type: "action",
|
|
170
|
+
jsonSerializable: true,
|
|
171
|
+
args: [v.object({
|
|
172
|
+
id: v.string(),
|
|
173
|
+
cols: v.pipe(v.number(), v.integer(), v.minValue(1)),
|
|
174
|
+
rows: v.pipe(v.number(), v.integer(), v.minValue(1))
|
|
175
|
+
})],
|
|
176
|
+
returns: v.void(),
|
|
177
|
+
setup: (ctx) => ({ handler: ({ id, cols, rows }) => {
|
|
178
|
+
getTerminalManager(ctx).resize(id, cols, rows);
|
|
179
|
+
} })
|
|
180
|
+
});
|
|
181
|
+
//#endregion
|
|
182
|
+
//#region src/rpc/functions/restart.ts
|
|
183
|
+
const restart = defineRpcFunction({
|
|
184
|
+
name: "devframes-plugin-terminals:restart",
|
|
185
|
+
type: "action",
|
|
186
|
+
jsonSerializable: true,
|
|
187
|
+
args: [v.object({ id: v.string() })],
|
|
188
|
+
returns: sessionInfoSchema,
|
|
189
|
+
setup: (ctx) => ({ handler: ({ id }) => getTerminalManager(ctx).restart(id) })
|
|
190
|
+
});
|
|
191
|
+
//#endregion
|
|
192
|
+
//#region src/rpc/functions/spawn.ts
|
|
193
|
+
const spawn = defineRpcFunction({
|
|
194
|
+
name: "devframes-plugin-terminals:spawn",
|
|
195
|
+
type: "action",
|
|
196
|
+
jsonSerializable: true,
|
|
197
|
+
args: [spawnRequestSchema],
|
|
198
|
+
returns: sessionInfoSchema,
|
|
199
|
+
agent: {
|
|
200
|
+
description: "Spawn a new terminal session. Pass a preset id, or a command + mode. Interactive sessions accept input; readonly sessions only stream output.",
|
|
201
|
+
safety: "action"
|
|
202
|
+
},
|
|
203
|
+
setup: (ctx) => ({ handler: (req) => getTerminalManager(ctx).spawn(req ?? {}) })
|
|
204
|
+
});
|
|
205
|
+
//#endregion
|
|
206
|
+
//#region src/rpc/functions/terminate.ts
|
|
207
|
+
const terminate = defineRpcFunction({
|
|
208
|
+
name: "devframes-plugin-terminals:terminate",
|
|
209
|
+
type: "action",
|
|
210
|
+
jsonSerializable: true,
|
|
211
|
+
args: [v.object({ id: v.string() })],
|
|
212
|
+
returns: v.void(),
|
|
213
|
+
agent: {
|
|
214
|
+
description: "Terminate a terminal session's running process. The session and its scrollback are kept; use restart to run it again.",
|
|
215
|
+
safety: "destructive"
|
|
216
|
+
},
|
|
217
|
+
setup: (ctx) => ({ handler: ({ id }) => {
|
|
218
|
+
getTerminalManager(ctx).terminate(id);
|
|
219
|
+
} })
|
|
220
|
+
});
|
|
221
|
+
//#endregion
|
|
222
|
+
//#region src/rpc/index.ts
|
|
223
|
+
const serverFunctions = [
|
|
224
|
+
list,
|
|
225
|
+
presets,
|
|
226
|
+
spawn,
|
|
227
|
+
defineRpcFunction({
|
|
228
|
+
name: "devframes-plugin-terminals:write",
|
|
229
|
+
type: "action",
|
|
230
|
+
jsonSerializable: true,
|
|
231
|
+
args: [v.object({
|
|
232
|
+
id: v.string(),
|
|
233
|
+
data: v.string()
|
|
234
|
+
})],
|
|
235
|
+
returns: v.void(),
|
|
236
|
+
setup: (ctx) => ({ handler: ({ id, data }) => {
|
|
237
|
+
getTerminalManager(ctx).write(id, data);
|
|
238
|
+
} })
|
|
239
|
+
}),
|
|
240
|
+
resize,
|
|
241
|
+
terminate,
|
|
242
|
+
restart,
|
|
243
|
+
rename,
|
|
244
|
+
remove
|
|
245
|
+
];
|
|
246
|
+
//#endregion
|
|
247
|
+
export { diagnostics as i, getTerminalManager as n, setTerminalManager as r, serverFunctions as t };
|