terminal-pilot 0.0.6 → 0.0.8
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/dist/cli.js +5663 -1269
- package/dist/cli.js.map +4 -4
- package/dist/commands/close-session.js +268 -87
- package/dist/commands/close-session.js.map +4 -4
- package/dist/commands/create-session.js +268 -87
- package/dist/commands/create-session.js.map +4 -4
- package/dist/commands/fill.js +268 -87
- package/dist/commands/fill.js.map +4 -4
- package/dist/commands/get-session.js +268 -87
- package/dist/commands/get-session.js.map +4 -4
- package/dist/commands/index.js +2404 -279
- package/dist/commands/index.js.map +4 -4
- package/dist/commands/install.js +1372 -14
- package/dist/commands/install.js.map +4 -4
- package/dist/commands/installer.js +178 -15
- package/dist/commands/installer.js.map +4 -4
- package/dist/commands/list-sessions.js +268 -87
- package/dist/commands/list-sessions.js.map +4 -4
- package/dist/commands/press-key.js +268 -87
- package/dist/commands/press-key.js.map +4 -4
- package/dist/commands/read-history.js +268 -87
- package/dist/commands/read-history.js.map +4 -4
- package/dist/commands/read-screen.js +268 -87
- package/dist/commands/read-screen.js.map +4 -4
- package/dist/commands/resize.js +268 -87
- package/dist/commands/resize.js.map +4 -4
- package/dist/commands/runtime.js +27 -85
- package/dist/commands/runtime.js.map +4 -4
- package/dist/commands/screenshot.js +1033 -91
- package/dist/commands/screenshot.js.map +4 -4
- package/dist/commands/send-signal.js +268 -87
- package/dist/commands/send-signal.js.map +4 -4
- package/dist/commands/type.js +268 -87
- package/dist/commands/type.js.map +4 -4
- package/dist/commands/uninstall.js +419 -17
- package/dist/commands/uninstall.js.map +4 -4
- package/dist/commands/wait-for-exit.js +268 -87
- package/dist/commands/wait-for-exit.js.map +4 -4
- package/dist/commands/wait-for.js +268 -87
- package/dist/commands/wait-for.js.map +4 -4
- package/dist/index.js +19 -83
- package/dist/index.js.map +3 -3
- package/dist/terminal-pilot.js +19 -83
- package/dist/terminal-pilot.js.map +3 -3
- package/dist/terminal-session.js +19 -83
- package/dist/terminal-session.js.map +3 -3
- package/dist/testing/cli-repl.js +5598 -1203
- package/dist/testing/cli-repl.js.map +4 -4
- package/dist/testing/qa-cli.js +5601 -1206
- package/dist/testing/qa-cli.js.map +4 -4
- package/package.json +17 -8
package/dist/commands/index.js
CHANGED
|
@@ -1,18 +1,351 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
import {
|
|
1
|
+
// ../cmdkit/src/index.ts
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
3
|
|
|
4
|
-
// src/
|
|
5
|
-
|
|
4
|
+
// ../cmdkit-schema/src/index.ts
|
|
5
|
+
function assertValidEnumValues(values) {
|
|
6
|
+
if (values.length === 0) {
|
|
7
|
+
throw new Error("Enum schema requires at least one value");
|
|
8
|
+
}
|
|
9
|
+
const uniqueValues = new Set(values);
|
|
10
|
+
if (uniqueValues.size !== values.length) {
|
|
11
|
+
throw new Error("Enum schema values must be unique");
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
var S = {
|
|
15
|
+
String(options = {}) {
|
|
16
|
+
return {
|
|
17
|
+
kind: "string",
|
|
18
|
+
...options
|
|
19
|
+
};
|
|
20
|
+
},
|
|
21
|
+
Number(options = {}) {
|
|
22
|
+
return {
|
|
23
|
+
kind: "number",
|
|
24
|
+
...options
|
|
25
|
+
};
|
|
26
|
+
},
|
|
27
|
+
Boolean(options = {}) {
|
|
28
|
+
return {
|
|
29
|
+
kind: "boolean",
|
|
30
|
+
...options
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
Enum(values, options = {}) {
|
|
34
|
+
assertValidEnumValues(values);
|
|
35
|
+
return {
|
|
36
|
+
kind: "enum",
|
|
37
|
+
values,
|
|
38
|
+
...options
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
Array(item, options = {}) {
|
|
42
|
+
return {
|
|
43
|
+
kind: "array",
|
|
44
|
+
item,
|
|
45
|
+
...options
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
Object(shape) {
|
|
49
|
+
return {
|
|
50
|
+
kind: "object",
|
|
51
|
+
shape
|
|
52
|
+
};
|
|
53
|
+
},
|
|
54
|
+
Optional(inner) {
|
|
55
|
+
return {
|
|
56
|
+
kind: "optional",
|
|
57
|
+
inner
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
};
|
|
6
61
|
|
|
7
|
-
// src/
|
|
8
|
-
|
|
62
|
+
// ../cmdkit/src/index.ts
|
|
63
|
+
var commandConfigSymbol = /* @__PURE__ */ Symbol("cmdkit.command.config");
|
|
64
|
+
var groupConfigSymbol = /* @__PURE__ */ Symbol("cmdkit.group.config");
|
|
65
|
+
var commandSourcePathSymbol = /* @__PURE__ */ Symbol("cmdkit.command.sourcePath");
|
|
66
|
+
var UserError = class extends Error {
|
|
67
|
+
constructor(message) {
|
|
68
|
+
super(message);
|
|
69
|
+
this.name = "UserError";
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
function cloneScope(scope) {
|
|
73
|
+
return scope === void 0 ? void 0 : [...scope];
|
|
74
|
+
}
|
|
75
|
+
function cloneSecretDefinition(secret) {
|
|
76
|
+
return {
|
|
77
|
+
env: secret.env,
|
|
78
|
+
description: secret.description,
|
|
79
|
+
optional: secret.optional
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function cloneSecrets(secrets) {
|
|
83
|
+
if (secrets === void 0) {
|
|
84
|
+
return {};
|
|
85
|
+
}
|
|
86
|
+
return Object.fromEntries(
|
|
87
|
+
Object.entries(secrets).map(([key, secret]) => [key, cloneSecretDefinition(secret)])
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
function cloneRequires(requires) {
|
|
91
|
+
if (requires === void 0) {
|
|
92
|
+
return void 0;
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
auth: requires.auth,
|
|
96
|
+
apiVersion: requires.apiVersion,
|
|
97
|
+
check: requires.check
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function parseStackPath(candidate) {
|
|
101
|
+
if (candidate.startsWith("file://")) {
|
|
102
|
+
try {
|
|
103
|
+
return fileURLToPath(candidate);
|
|
104
|
+
} catch {
|
|
105
|
+
return void 0;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (candidate.startsWith("/")) {
|
|
109
|
+
return candidate;
|
|
110
|
+
}
|
|
111
|
+
return void 0;
|
|
112
|
+
}
|
|
113
|
+
function extractStackPath(line) {
|
|
114
|
+
const trimmed = line.trim();
|
|
115
|
+
const fileIndex = trimmed.indexOf("file://");
|
|
116
|
+
if (fileIndex >= 0) {
|
|
117
|
+
const location2 = trimmed.slice(fileIndex);
|
|
118
|
+
const separatorIndex2 = location2.lastIndexOf(":");
|
|
119
|
+
const previousSeparatorIndex2 = separatorIndex2 >= 0 ? location2.lastIndexOf(":", separatorIndex2 - 1) : -1;
|
|
120
|
+
const candidate2 = separatorIndex2 >= 0 && previousSeparatorIndex2 >= 0 ? location2.slice(0, previousSeparatorIndex2) : location2;
|
|
121
|
+
return parseStackPath(candidate2);
|
|
122
|
+
}
|
|
123
|
+
const slashIndex = trimmed.indexOf("/");
|
|
124
|
+
if (slashIndex < 0) {
|
|
125
|
+
return void 0;
|
|
126
|
+
}
|
|
127
|
+
const location = trimmed.slice(slashIndex);
|
|
128
|
+
const separatorIndex = location.lastIndexOf(":");
|
|
129
|
+
const previousSeparatorIndex = separatorIndex >= 0 ? location.lastIndexOf(":", separatorIndex - 1) : -1;
|
|
130
|
+
const candidate = separatorIndex >= 0 && previousSeparatorIndex >= 0 ? location.slice(0, previousSeparatorIndex) : location;
|
|
131
|
+
return parseStackPath(candidate);
|
|
132
|
+
}
|
|
133
|
+
function inferCommandSourcePath() {
|
|
134
|
+
const stack = new Error().stack;
|
|
135
|
+
if (typeof stack !== "string") {
|
|
136
|
+
return void 0;
|
|
137
|
+
}
|
|
138
|
+
for (const line of stack.split("\n").slice(1)) {
|
|
139
|
+
const candidate = extractStackPath(line);
|
|
140
|
+
if (candidate === void 0) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (candidate.includes("/packages/cmdkit/src/index.ts") || candidate.includes("/packages/cmdkit/dist/index.js")) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
return candidate;
|
|
147
|
+
}
|
|
148
|
+
return void 0;
|
|
149
|
+
}
|
|
150
|
+
function composeChecks(parentCheck, childCheck) {
|
|
151
|
+
if (parentCheck === void 0) {
|
|
152
|
+
return childCheck;
|
|
153
|
+
}
|
|
154
|
+
if (childCheck === void 0) {
|
|
155
|
+
return parentCheck;
|
|
156
|
+
}
|
|
157
|
+
return async (ctx) => {
|
|
158
|
+
const parentResult = await parentCheck(ctx);
|
|
159
|
+
if (!parentResult.ok) {
|
|
160
|
+
return parentResult;
|
|
161
|
+
}
|
|
162
|
+
return childCheck(ctx);
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function mergeRequires(parent, child) {
|
|
166
|
+
if (parent === void 0 && child === void 0) {
|
|
167
|
+
return void 0;
|
|
168
|
+
}
|
|
169
|
+
const merged = {
|
|
170
|
+
auth: child?.auth ?? parent?.auth,
|
|
171
|
+
apiVersion: child?.apiVersion ?? parent?.apiVersion,
|
|
172
|
+
check: composeChecks(parent?.check, child?.check)
|
|
173
|
+
};
|
|
174
|
+
if (merged.auth === void 0 && merged.apiVersion === void 0 && merged.check === void 0) {
|
|
175
|
+
return void 0;
|
|
176
|
+
}
|
|
177
|
+
return merged;
|
|
178
|
+
}
|
|
179
|
+
function mergeSecrets(parent, child) {
|
|
180
|
+
return cloneSecrets({
|
|
181
|
+
...parent,
|
|
182
|
+
...child
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
function resolveCommandScope(ownScope, inheritedScope) {
|
|
186
|
+
return cloneScope(ownScope ?? inheritedScope) ?? ["cli", "sdk"];
|
|
187
|
+
}
|
|
188
|
+
function resolveGroupScope(ownScope, inheritedScope) {
|
|
189
|
+
return cloneScope(ownScope ?? inheritedScope);
|
|
190
|
+
}
|
|
191
|
+
function createBaseCommand(config) {
|
|
192
|
+
const command = {
|
|
193
|
+
kind: "command",
|
|
194
|
+
name: config.name,
|
|
195
|
+
description: config.description,
|
|
196
|
+
aliases: [...config.aliases ?? []],
|
|
197
|
+
positional: [...config.positional ?? []],
|
|
198
|
+
params: config.params,
|
|
199
|
+
secrets: cloneSecrets(config.secrets),
|
|
200
|
+
scope: resolveCommandScope(config.scope, void 0),
|
|
201
|
+
confirm: config.confirm ?? false,
|
|
202
|
+
requires: cloneRequires(config.requires),
|
|
203
|
+
handler: config.handler,
|
|
204
|
+
render: config.render
|
|
205
|
+
};
|
|
206
|
+
Object.defineProperty(command, commandConfigSymbol, {
|
|
207
|
+
value: {
|
|
208
|
+
scope: cloneScope(config.scope),
|
|
209
|
+
secrets: cloneSecrets(config.secrets),
|
|
210
|
+
requires: cloneRequires(config.requires),
|
|
211
|
+
sourcePath: inferCommandSourcePath()
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
return command;
|
|
215
|
+
}
|
|
216
|
+
function createBaseGroup(config) {
|
|
217
|
+
const group = {
|
|
218
|
+
kind: "group",
|
|
219
|
+
name: config.name,
|
|
220
|
+
description: config.description,
|
|
221
|
+
aliases: [...config.aliases ?? []],
|
|
222
|
+
scope: resolveGroupScope(config.scope, void 0),
|
|
223
|
+
secrets: cloneSecrets(config.secrets),
|
|
224
|
+
requires: cloneRequires(config.requires),
|
|
225
|
+
children: [],
|
|
226
|
+
default: void 0
|
|
227
|
+
};
|
|
228
|
+
Object.defineProperty(group, groupConfigSymbol, {
|
|
229
|
+
value: {
|
|
230
|
+
scope: cloneScope(config.scope),
|
|
231
|
+
secrets: cloneSecrets(config.secrets),
|
|
232
|
+
requires: cloneRequires(config.requires),
|
|
233
|
+
children: [...config.children],
|
|
234
|
+
default: config.default
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
return group;
|
|
238
|
+
}
|
|
239
|
+
function getInternalCommandConfig(command) {
|
|
240
|
+
return command[commandConfigSymbol];
|
|
241
|
+
}
|
|
242
|
+
function getInternalGroupConfig(group) {
|
|
243
|
+
return group[groupConfigSymbol];
|
|
244
|
+
}
|
|
245
|
+
function materializeCommand(command, inherited) {
|
|
246
|
+
const internal = getInternalCommandConfig(command);
|
|
247
|
+
const materialized = {
|
|
248
|
+
kind: "command",
|
|
249
|
+
name: command.name,
|
|
250
|
+
description: command.description,
|
|
251
|
+
aliases: [...command.aliases],
|
|
252
|
+
positional: [...command.positional],
|
|
253
|
+
params: command.params,
|
|
254
|
+
secrets: mergeSecrets(inherited.secrets, internal.secrets),
|
|
255
|
+
scope: resolveCommandScope(internal.scope, inherited.scope),
|
|
256
|
+
confirm: command.confirm,
|
|
257
|
+
requires: mergeRequires(inherited.requires, internal.requires),
|
|
258
|
+
handler: command.handler,
|
|
259
|
+
render: command.render
|
|
260
|
+
};
|
|
261
|
+
Object.defineProperty(materialized, commandConfigSymbol, {
|
|
262
|
+
value: {
|
|
263
|
+
scope: cloneScope(internal.scope),
|
|
264
|
+
secrets: cloneSecrets(internal.secrets),
|
|
265
|
+
requires: cloneRequires(internal.requires),
|
|
266
|
+
sourcePath: internal.sourcePath
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
Object.defineProperty(materialized, commandSourcePathSymbol, {
|
|
270
|
+
value: internal.sourcePath
|
|
271
|
+
});
|
|
272
|
+
return materialized;
|
|
273
|
+
}
|
|
274
|
+
function materializeGroup(group, inherited) {
|
|
275
|
+
const internal = getInternalGroupConfig(group);
|
|
276
|
+
const scope = resolveGroupScope(internal.scope, inherited.scope);
|
|
277
|
+
const secrets = mergeSecrets(inherited.secrets, internal.secrets);
|
|
278
|
+
const requires = mergeRequires(inherited.requires, internal.requires);
|
|
279
|
+
const materializedChildren = internal.children.map(
|
|
280
|
+
(child) => materializeNode(child, {
|
|
281
|
+
scope,
|
|
282
|
+
secrets,
|
|
283
|
+
requires
|
|
284
|
+
})
|
|
285
|
+
);
|
|
286
|
+
let defaultChild;
|
|
287
|
+
if (internal.default !== void 0) {
|
|
288
|
+
const defaultIndex = internal.children.indexOf(internal.default);
|
|
289
|
+
if (defaultIndex === -1) {
|
|
290
|
+
throw new UserError(`Default command "${internal.default.name}" must be listed in children.`);
|
|
291
|
+
}
|
|
292
|
+
const resolvedDefault = materializedChildren[defaultIndex];
|
|
293
|
+
if (resolvedDefault?.kind !== "command") {
|
|
294
|
+
throw new UserError(`Default child "${internal.default.name}" must be a command.`);
|
|
295
|
+
}
|
|
296
|
+
defaultChild = resolvedDefault;
|
|
297
|
+
}
|
|
298
|
+
const materialized = {
|
|
299
|
+
kind: "group",
|
|
300
|
+
name: group.name,
|
|
301
|
+
description: group.description,
|
|
302
|
+
aliases: [...group.aliases],
|
|
303
|
+
scope,
|
|
304
|
+
secrets,
|
|
305
|
+
requires,
|
|
306
|
+
children: materializedChildren,
|
|
307
|
+
default: defaultChild
|
|
308
|
+
};
|
|
309
|
+
Object.defineProperty(materialized, groupConfigSymbol, {
|
|
310
|
+
value: {
|
|
311
|
+
scope: cloneScope(internal.scope),
|
|
312
|
+
secrets: cloneSecrets(internal.secrets),
|
|
313
|
+
requires: cloneRequires(internal.requires),
|
|
314
|
+
children: [...internal.children],
|
|
315
|
+
default: internal.default
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
return materialized;
|
|
319
|
+
}
|
|
320
|
+
function materializeNode(node, inherited) {
|
|
321
|
+
if (node.kind === "command") {
|
|
322
|
+
return materializeCommand(node, inherited);
|
|
323
|
+
}
|
|
324
|
+
return materializeGroup(node, inherited);
|
|
325
|
+
}
|
|
326
|
+
function defineCommand(config) {
|
|
327
|
+
return materializeCommand(createBaseCommand(config), {
|
|
328
|
+
scope: void 0,
|
|
329
|
+
secrets: {},
|
|
330
|
+
requires: void 0
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
function defineGroup(config) {
|
|
334
|
+
return materializeGroup(createBaseGroup(config), {
|
|
335
|
+
scope: void 0,
|
|
336
|
+
secrets: {},
|
|
337
|
+
requires: void 0
|
|
338
|
+
});
|
|
339
|
+
}
|
|
9
340
|
|
|
10
341
|
// src/terminal-pilot.ts
|
|
11
342
|
import { randomUUID } from "node:crypto";
|
|
12
343
|
|
|
13
344
|
// src/terminal-session.ts
|
|
14
|
-
import { spawn as spawnChildProcess } from "node:child_process";
|
|
15
345
|
import { EventEmitter } from "node:events";
|
|
346
|
+
import { accessSync, chmodSync, constants } from "node:fs";
|
|
347
|
+
import { createRequire } from "node:module";
|
|
348
|
+
import { dirname, join } from "node:path";
|
|
16
349
|
import * as nodePty from "node-pty";
|
|
17
350
|
|
|
18
351
|
// src/ansi.ts
|
|
@@ -923,93 +1256,27 @@ function createPtyProcess({
|
|
|
923
1256
|
cols,
|
|
924
1257
|
rows
|
|
925
1258
|
}) {
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
cwd,
|
|
929
|
-
env,
|
|
930
|
-
cols,
|
|
931
|
-
rows,
|
|
932
|
-
encoding: "utf8"
|
|
933
|
-
});
|
|
934
|
-
} catch {
|
|
935
|
-
return createChildProcessFallback({ command, args, cwd, env });
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
function createChildProcessFallback({
|
|
939
|
-
command,
|
|
940
|
-
args,
|
|
941
|
-
cwd,
|
|
942
|
-
env
|
|
943
|
-
}) {
|
|
944
|
-
const child = spawnChildProcess(command, args, {
|
|
1259
|
+
ensureSpawnHelperExecutable();
|
|
1260
|
+
return nodePty.spawn(command, args, {
|
|
945
1261
|
cwd,
|
|
946
1262
|
env,
|
|
947
|
-
|
|
1263
|
+
cols,
|
|
1264
|
+
rows,
|
|
1265
|
+
encoding: "utf8"
|
|
948
1266
|
});
|
|
949
|
-
return new ChildProcessFallback(child);
|
|
950
1267
|
}
|
|
951
|
-
var
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
child.stderr.on("data", this.handleData);
|
|
963
|
-
child.on("exit", (exitCode, signal) => {
|
|
964
|
-
this.exitEmitter.emit("exit", {
|
|
965
|
-
exitCode: exitCode ?? signalToExitCode(signal),
|
|
966
|
-
signal: void 0
|
|
967
|
-
});
|
|
968
|
-
});
|
|
969
|
-
}
|
|
970
|
-
write(data) {
|
|
971
|
-
this.child.stdin.write(data);
|
|
972
|
-
}
|
|
973
|
-
resize() {
|
|
974
|
-
}
|
|
975
|
-
kill(signal) {
|
|
976
|
-
this.child.kill(signal);
|
|
977
|
-
}
|
|
978
|
-
onData(listener) {
|
|
979
|
-
this.dataEmitter.on("data", listener);
|
|
980
|
-
return {
|
|
981
|
-
dispose: () => {
|
|
982
|
-
this.dataEmitter.off("data", listener);
|
|
983
|
-
}
|
|
984
|
-
};
|
|
985
|
-
}
|
|
986
|
-
onExit(listener) {
|
|
987
|
-
this.exitEmitter.on("exit", listener);
|
|
988
|
-
return {
|
|
989
|
-
dispose: () => {
|
|
990
|
-
this.exitEmitter.off("exit", listener);
|
|
991
|
-
}
|
|
992
|
-
};
|
|
993
|
-
}
|
|
994
|
-
handleData = (chunk) => {
|
|
995
|
-
this.dataEmitter.emit("data", String(chunk));
|
|
996
|
-
};
|
|
997
|
-
};
|
|
998
|
-
function signalToExitCode(signal) {
|
|
999
|
-
if (signal === null) {
|
|
1000
|
-
return 0;
|
|
1001
|
-
}
|
|
1002
|
-
const signalNumbers = {
|
|
1003
|
-
SIGTERM: 15,
|
|
1004
|
-
SIGINT: 2,
|
|
1005
|
-
SIGHUP: 1,
|
|
1006
|
-
SIGKILL: 9
|
|
1007
|
-
};
|
|
1008
|
-
const signalNumber = signalNumbers[signal];
|
|
1009
|
-
if (signalNumber === void 0) {
|
|
1010
|
-
return 1;
|
|
1268
|
+
var spawnHelperChecked = false;
|
|
1269
|
+
function ensureSpawnHelperExecutable() {
|
|
1270
|
+
if (spawnHelperChecked) return;
|
|
1271
|
+
spawnHelperChecked = true;
|
|
1272
|
+
const require3 = createRequire(import.meta.url);
|
|
1273
|
+
const nodePtyDir = dirname(require3.resolve("node-pty"));
|
|
1274
|
+
const helper = join(nodePtyDir, "..", "prebuilds", `${process.platform}-${process.arch}`, "spawn-helper");
|
|
1275
|
+
try {
|
|
1276
|
+
accessSync(helper, constants.X_OK);
|
|
1277
|
+
} catch {
|
|
1278
|
+
chmodSync(helper, 493);
|
|
1011
1279
|
}
|
|
1012
|
-
return 128 + signalNumber;
|
|
1013
1280
|
}
|
|
1014
1281
|
function matchPattern(buffer, pattern) {
|
|
1015
1282
|
const clean = normalizeHistoryBuffer(stripAnsi(buffer));
|
|
@@ -1263,17 +1530,16 @@ var closeSession = defineCommand({
|
|
|
1263
1530
|
});
|
|
1264
1531
|
|
|
1265
1532
|
// src/commands/create-session.ts
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
observe: S2.Optional(S2.Boolean({ description: "Mirror PTY output to stderr" }))
|
|
1533
|
+
var params2 = S.Object({
|
|
1534
|
+
command: S.String({ description: "Command to execute" }),
|
|
1535
|
+
args: S.Optional(S.Array(S.String(), { description: "Command arguments" })),
|
|
1536
|
+
session: S.Optional(S.String({ short: "s", description: "Session name" })),
|
|
1537
|
+
cwd: S.Optional(S.String({ description: "Working directory" })),
|
|
1538
|
+
cols: S.Optional(S.Number({ description: "Terminal width in columns" })),
|
|
1539
|
+
rows: S.Optional(S.Number({ description: "Terminal height in rows" })),
|
|
1540
|
+
observe: S.Optional(S.Boolean({ description: "Mirror PTY output to stderr" }))
|
|
1275
1541
|
});
|
|
1276
|
-
var createSession =
|
|
1542
|
+
var createSession = defineCommand({
|
|
1277
1543
|
name: "create-session",
|
|
1278
1544
|
description: "Spawn an interactive CLI in a PTY",
|
|
1279
1545
|
scope: ["cli", "mcp", "sdk"],
|
|
@@ -1286,12 +1552,11 @@ var createSession = defineCommand2({
|
|
|
1286
1552
|
});
|
|
1287
1553
|
|
|
1288
1554
|
// src/commands/fill.ts
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
session: S3.Optional(S3.String({ short: "s", description: "Session name" }))
|
|
1555
|
+
var params3 = S.Object({
|
|
1556
|
+
text: S.String({ description: "Text to write to the session" }),
|
|
1557
|
+
session: S.Optional(S.String({ short: "s", description: "Session name" }))
|
|
1293
1558
|
});
|
|
1294
|
-
var fill =
|
|
1559
|
+
var fill = defineCommand({
|
|
1295
1560
|
name: "fill",
|
|
1296
1561
|
description: "Write text to an active terminal session all at once (replaces \\n with \\r)",
|
|
1297
1562
|
scope: ["cli", "mcp", "sdk"],
|
|
@@ -1305,11 +1570,10 @@ var fill = defineCommand3({
|
|
|
1305
1570
|
});
|
|
1306
1571
|
|
|
1307
1572
|
// src/commands/get-session.ts
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
session: S4.Optional(S4.String({ short: "s", description: "Session name" }))
|
|
1573
|
+
var params4 = S.Object({
|
|
1574
|
+
session: S.Optional(S.String({ short: "s", description: "Session name" }))
|
|
1311
1575
|
});
|
|
1312
|
-
var getSession =
|
|
1576
|
+
var getSession = defineCommand({
|
|
1313
1577
|
name: "get-session",
|
|
1314
1578
|
description: "Get session metadata (name, pid, command, exitCode)",
|
|
1315
1579
|
scope: ["cli", "mcp", "sdk"],
|
|
@@ -1325,138 +1589,1249 @@ var getSession = defineCommand4({
|
|
|
1325
1589
|
}
|
|
1326
1590
|
});
|
|
1327
1591
|
|
|
1328
|
-
// src/
|
|
1329
|
-
import { installSkill } from "@poe-code/agent-skill-config";
|
|
1330
|
-
import { defineCommand as defineCommand5, S as S5 } from "@poe-code/cmdkit";
|
|
1331
|
-
|
|
1332
|
-
// src/commands/installer.ts
|
|
1592
|
+
// ../agent-skill-config/src/configs.ts
|
|
1333
1593
|
import os from "node:os";
|
|
1334
1594
|
import path from "node:path";
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
}
|
|
1350
|
-
function resolveInstallerServices(installer) {
|
|
1351
|
-
return {
|
|
1352
|
-
fs: installer?.fs ?? nodeFs,
|
|
1353
|
-
cwd: installer?.cwd ?? process.cwd(),
|
|
1354
|
-
homeDir: installer?.homeDir ?? os.homedir(),
|
|
1355
|
-
platform: installer?.platform ?? process.platform
|
|
1356
|
-
};
|
|
1357
|
-
}
|
|
1358
|
-
function throwUnsupportedAgent(agent) {
|
|
1359
|
-
throw new UserError2(`Unsupported agent: ${agent}`);
|
|
1360
|
-
}
|
|
1361
|
-
function resolveInstallableAgent(agent) {
|
|
1362
|
-
const skillSupport = resolveSkillAgentSupport(agent);
|
|
1363
|
-
if (skillSupport.status !== "supported" || !skillSupport.id) {
|
|
1364
|
-
throwUnsupportedAgent(agent);
|
|
1595
|
+
|
|
1596
|
+
// ../agent-defs/src/agents/claude-code.ts
|
|
1597
|
+
var claudeCodeAgent = {
|
|
1598
|
+
id: "claude-code",
|
|
1599
|
+
name: "claude-code",
|
|
1600
|
+
label: "Claude Code",
|
|
1601
|
+
summary: "Configure Claude Code to route through Poe.",
|
|
1602
|
+
aliases: ["claude"],
|
|
1603
|
+
binaryName: "claude",
|
|
1604
|
+
configPath: "~/.claude/settings.json",
|
|
1605
|
+
branding: {
|
|
1606
|
+
colors: {
|
|
1607
|
+
dark: "#C15F3C",
|
|
1608
|
+
light: "#C15F3C"
|
|
1609
|
+
}
|
|
1365
1610
|
}
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1611
|
+
};
|
|
1612
|
+
|
|
1613
|
+
// ../agent-defs/src/agents/claude-desktop.ts
|
|
1614
|
+
var claudeDesktopAgent = {
|
|
1615
|
+
id: "claude-desktop",
|
|
1616
|
+
name: "claude-desktop",
|
|
1617
|
+
label: "Claude Desktop",
|
|
1618
|
+
summary: "Anthropic's official desktop application for Claude",
|
|
1619
|
+
configPath: "~/.claude/settings.json",
|
|
1620
|
+
branding: {
|
|
1621
|
+
colors: {
|
|
1622
|
+
dark: "#D97757",
|
|
1623
|
+
light: "#D97757"
|
|
1624
|
+
}
|
|
1371
1625
|
}
|
|
1372
|
-
|
|
1373
|
-
|
|
1626
|
+
};
|
|
1627
|
+
|
|
1628
|
+
// ../agent-defs/src/agents/codex.ts
|
|
1629
|
+
var codexAgent = {
|
|
1630
|
+
id: "codex",
|
|
1631
|
+
name: "codex",
|
|
1632
|
+
label: "Codex",
|
|
1633
|
+
summary: "Configure Codex to use Poe as the model provider.",
|
|
1634
|
+
binaryName: "codex",
|
|
1635
|
+
configPath: "~/.codex/config.toml",
|
|
1636
|
+
branding: {
|
|
1637
|
+
colors: {
|
|
1638
|
+
dark: "#D5D9DF",
|
|
1639
|
+
light: "#7A7F86"
|
|
1640
|
+
}
|
|
1374
1641
|
}
|
|
1375
|
-
|
|
1376
|
-
|
|
1642
|
+
};
|
|
1643
|
+
|
|
1644
|
+
// ../agent-defs/src/agents/opencode.ts
|
|
1645
|
+
var openCodeAgent = {
|
|
1646
|
+
id: "opencode",
|
|
1647
|
+
name: "opencode",
|
|
1648
|
+
label: "OpenCode CLI",
|
|
1649
|
+
summary: "Configure OpenCode CLI to use the Poe API.",
|
|
1650
|
+
binaryName: "opencode",
|
|
1651
|
+
configPath: "~/.config/opencode/config.json",
|
|
1652
|
+
branding: {
|
|
1653
|
+
colors: {
|
|
1654
|
+
dark: "#4A4F55",
|
|
1655
|
+
light: "#2F3338"
|
|
1656
|
+
}
|
|
1377
1657
|
}
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1658
|
+
};
|
|
1659
|
+
|
|
1660
|
+
// ../agent-defs/src/agents/kimi.ts
|
|
1661
|
+
var kimiAgent = {
|
|
1662
|
+
id: "kimi",
|
|
1663
|
+
name: "kimi",
|
|
1664
|
+
label: "Kimi",
|
|
1665
|
+
summary: "Configure Kimi CLI to use Poe API",
|
|
1666
|
+
aliases: ["kimi-cli"],
|
|
1667
|
+
binaryName: "kimi",
|
|
1668
|
+
configPath: "~/.kimi/config.toml",
|
|
1669
|
+
branding: {
|
|
1670
|
+
colors: {
|
|
1671
|
+
dark: "#7B68EE",
|
|
1672
|
+
light: "#6A5ACD"
|
|
1673
|
+
}
|
|
1384
1674
|
}
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1675
|
+
};
|
|
1676
|
+
|
|
1677
|
+
// ../agent-defs/src/registry.ts
|
|
1678
|
+
var allAgents = [
|
|
1679
|
+
claudeCodeAgent,
|
|
1680
|
+
claudeDesktopAgent,
|
|
1681
|
+
codexAgent,
|
|
1682
|
+
openCodeAgent,
|
|
1683
|
+
kimiAgent
|
|
1684
|
+
];
|
|
1685
|
+
var lookup = /* @__PURE__ */ new Map();
|
|
1686
|
+
for (const agent of allAgents) {
|
|
1687
|
+
const values = [agent.id, agent.name, ...agent.aliases ?? []];
|
|
1688
|
+
for (const value of values) {
|
|
1689
|
+
const normalized = value.toLowerCase();
|
|
1690
|
+
if (!lookup.has(normalized)) {
|
|
1691
|
+
lookup.set(normalized, agent.id);
|
|
1398
1692
|
}
|
|
1399
1693
|
}
|
|
1400
|
-
throw new UserError2("terminal-pilot skill template is missing.");
|
|
1401
1694
|
}
|
|
1402
|
-
function
|
|
1403
|
-
if (
|
|
1404
|
-
return
|
|
1405
|
-
}
|
|
1406
|
-
if (targetPath.startsWith("~/")) {
|
|
1407
|
-
return path.join(homeDir, targetPath.slice(2));
|
|
1695
|
+
function resolveAgentId(input) {
|
|
1696
|
+
if (!input) {
|
|
1697
|
+
return void 0;
|
|
1408
1698
|
}
|
|
1409
|
-
return
|
|
1699
|
+
return lookup.get(input.toLowerCase());
|
|
1410
1700
|
}
|
|
1411
|
-
|
|
1412
|
-
|
|
1701
|
+
|
|
1702
|
+
// ../agent-skill-config/src/configs.ts
|
|
1703
|
+
var agentSkillConfigs = {
|
|
1704
|
+
"claude-code": {
|
|
1705
|
+
globalSkillDir: "~/.claude/skills",
|
|
1706
|
+
localSkillDir: ".claude/skills"
|
|
1707
|
+
},
|
|
1708
|
+
codex: {
|
|
1709
|
+
globalSkillDir: "~/.codex/skills",
|
|
1710
|
+
localSkillDir: ".codex/skills"
|
|
1711
|
+
},
|
|
1712
|
+
opencode: {
|
|
1713
|
+
globalSkillDir: "~/.config/opencode/skills",
|
|
1714
|
+
localSkillDir: ".opencode/skills"
|
|
1715
|
+
}
|
|
1716
|
+
};
|
|
1717
|
+
var supportedAgents = Object.keys(agentSkillConfigs);
|
|
1718
|
+
function resolveAgentSupport(input, registry = agentSkillConfigs) {
|
|
1719
|
+
const resolvedId = resolveAgentId(input);
|
|
1720
|
+
if (!resolvedId) {
|
|
1721
|
+
return { status: "unknown", input };
|
|
1722
|
+
}
|
|
1723
|
+
const config = registry[resolvedId];
|
|
1413
1724
|
if (!config) {
|
|
1414
|
-
|
|
1725
|
+
return { status: "unsupported", input, id: resolvedId };
|
|
1415
1726
|
}
|
|
1727
|
+
return { status: "supported", input, id: resolvedId, config };
|
|
1728
|
+
}
|
|
1729
|
+
function getAgentConfig(agentId) {
|
|
1730
|
+
const support = resolveAgentSupport(agentId);
|
|
1731
|
+
return support.status === "supported" ? support.config : void 0;
|
|
1732
|
+
}
|
|
1733
|
+
|
|
1734
|
+
// ../config-mutations/src/mutations/file-mutation.ts
|
|
1735
|
+
function ensureDirectory(options) {
|
|
1416
1736
|
return {
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
),
|
|
1421
|
-
fullPath: path.join(
|
|
1422
|
-
scope === "global" ? resolveHomeRelativePath(config.globalSkillDir, homeDir) : path.resolve(cwd, config.localSkillDir),
|
|
1423
|
-
TERMINAL_PILOT_SKILL_NAME
|
|
1424
|
-
)
|
|
1737
|
+
kind: "ensureDirectory",
|
|
1738
|
+
path: options.path,
|
|
1739
|
+
label: options.label
|
|
1425
1740
|
};
|
|
1426
1741
|
}
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1742
|
+
function remove(options) {
|
|
1743
|
+
return {
|
|
1744
|
+
kind: "removeFile",
|
|
1745
|
+
target: options.target,
|
|
1746
|
+
whenEmpty: options.whenEmpty,
|
|
1747
|
+
whenContentMatches: options.whenContentMatches,
|
|
1748
|
+
label: options.label
|
|
1749
|
+
};
|
|
1750
|
+
}
|
|
1751
|
+
function removeDirectory(options) {
|
|
1752
|
+
return {
|
|
1753
|
+
kind: "removeDirectory",
|
|
1754
|
+
path: options.path,
|
|
1755
|
+
force: options.force,
|
|
1756
|
+
label: options.label
|
|
1757
|
+
};
|
|
1758
|
+
}
|
|
1759
|
+
function chmod(options) {
|
|
1760
|
+
return {
|
|
1761
|
+
kind: "chmod",
|
|
1762
|
+
target: options.target,
|
|
1763
|
+
mode: options.mode,
|
|
1764
|
+
label: options.label
|
|
1765
|
+
};
|
|
1441
1766
|
}
|
|
1767
|
+
function backup(options) {
|
|
1768
|
+
return {
|
|
1769
|
+
kind: "backup",
|
|
1770
|
+
target: options.target,
|
|
1771
|
+
label: options.label
|
|
1772
|
+
};
|
|
1773
|
+
}
|
|
1774
|
+
var fileMutation = {
|
|
1775
|
+
ensureDirectory,
|
|
1776
|
+
remove,
|
|
1777
|
+
removeDirectory,
|
|
1778
|
+
chmod,
|
|
1779
|
+
backup
|
|
1780
|
+
};
|
|
1442
1781
|
|
|
1443
|
-
// src/
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
}
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1782
|
+
// ../config-mutations/src/mutations/template-mutation.ts
|
|
1783
|
+
function write(options) {
|
|
1784
|
+
return {
|
|
1785
|
+
kind: "templateWrite",
|
|
1786
|
+
target: options.target,
|
|
1787
|
+
templateId: options.templateId,
|
|
1788
|
+
context: options.context,
|
|
1789
|
+
label: options.label
|
|
1790
|
+
};
|
|
1791
|
+
}
|
|
1792
|
+
function mergeToml(options) {
|
|
1793
|
+
return {
|
|
1794
|
+
kind: "templateMergeToml",
|
|
1795
|
+
target: options.target,
|
|
1796
|
+
templateId: options.templateId,
|
|
1797
|
+
context: options.context,
|
|
1798
|
+
label: options.label
|
|
1799
|
+
};
|
|
1800
|
+
}
|
|
1801
|
+
function mergeJson(options) {
|
|
1802
|
+
return {
|
|
1803
|
+
kind: "templateMergeJson",
|
|
1804
|
+
target: options.target,
|
|
1805
|
+
templateId: options.templateId,
|
|
1806
|
+
context: options.context,
|
|
1807
|
+
label: options.label
|
|
1808
|
+
};
|
|
1809
|
+
}
|
|
1810
|
+
var templateMutation = {
|
|
1811
|
+
write,
|
|
1812
|
+
mergeToml,
|
|
1813
|
+
mergeJson
|
|
1814
|
+
};
|
|
1815
|
+
|
|
1816
|
+
// ../config-mutations/src/execution/apply-mutation.ts
|
|
1817
|
+
import Mustache from "mustache";
|
|
1818
|
+
|
|
1819
|
+
// ../config-mutations/src/formats/json.ts
|
|
1820
|
+
import * as jsonc from "jsonc-parser";
|
|
1821
|
+
function isConfigObject(value) {
|
|
1822
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1823
|
+
}
|
|
1824
|
+
function parse2(content) {
|
|
1825
|
+
if (!content || content.trim() === "") {
|
|
1826
|
+
return {};
|
|
1827
|
+
}
|
|
1828
|
+
const errors = [];
|
|
1829
|
+
const parsed = jsonc.parse(content, errors, {
|
|
1830
|
+
allowTrailingComma: true,
|
|
1831
|
+
disallowComments: false
|
|
1832
|
+
});
|
|
1833
|
+
if (errors.length > 0) {
|
|
1834
|
+
throw new Error(`JSON parse error: ${jsonc.printParseErrorCode(errors[0].error)}`);
|
|
1835
|
+
}
|
|
1836
|
+
if (parsed === null || parsed === void 0) {
|
|
1837
|
+
return {};
|
|
1838
|
+
}
|
|
1839
|
+
if (!isConfigObject(parsed)) {
|
|
1840
|
+
throw new Error("Expected JSON object.");
|
|
1841
|
+
}
|
|
1842
|
+
return parsed;
|
|
1843
|
+
}
|
|
1844
|
+
function serialize(obj) {
|
|
1845
|
+
return `${JSON.stringify(obj, null, 2)}
|
|
1846
|
+
`;
|
|
1847
|
+
}
|
|
1848
|
+
function merge(base, patch) {
|
|
1849
|
+
const result = { ...base };
|
|
1850
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
1851
|
+
if (value === void 0) {
|
|
1852
|
+
continue;
|
|
1853
|
+
}
|
|
1854
|
+
const existing = result[key];
|
|
1855
|
+
if (isConfigObject(existing) && isConfigObject(value)) {
|
|
1856
|
+
result[key] = merge(existing, value);
|
|
1857
|
+
continue;
|
|
1858
|
+
}
|
|
1859
|
+
result[key] = value;
|
|
1860
|
+
}
|
|
1861
|
+
return result;
|
|
1862
|
+
}
|
|
1863
|
+
function prune(obj, shape) {
|
|
1864
|
+
let changed = false;
|
|
1865
|
+
const result = { ...obj };
|
|
1866
|
+
for (const [key, pattern] of Object.entries(shape)) {
|
|
1867
|
+
if (!(key in result)) {
|
|
1868
|
+
continue;
|
|
1869
|
+
}
|
|
1870
|
+
const current = result[key];
|
|
1871
|
+
if (isConfigObject(pattern) && Object.keys(pattern).length === 0) {
|
|
1872
|
+
delete result[key];
|
|
1873
|
+
changed = true;
|
|
1874
|
+
continue;
|
|
1875
|
+
}
|
|
1876
|
+
if (isConfigObject(pattern) && isConfigObject(current)) {
|
|
1877
|
+
const { changed: childChanged, result: childResult } = prune(
|
|
1878
|
+
current,
|
|
1879
|
+
pattern
|
|
1880
|
+
);
|
|
1881
|
+
if (childChanged) {
|
|
1882
|
+
changed = true;
|
|
1883
|
+
}
|
|
1884
|
+
if (Object.keys(childResult).length === 0) {
|
|
1885
|
+
delete result[key];
|
|
1886
|
+
} else {
|
|
1887
|
+
result[key] = childResult;
|
|
1888
|
+
}
|
|
1889
|
+
continue;
|
|
1890
|
+
}
|
|
1891
|
+
delete result[key];
|
|
1892
|
+
changed = true;
|
|
1893
|
+
}
|
|
1894
|
+
return { changed, result };
|
|
1895
|
+
}
|
|
1896
|
+
var jsonFormat = {
|
|
1897
|
+
parse: parse2,
|
|
1898
|
+
serialize,
|
|
1899
|
+
merge,
|
|
1900
|
+
prune
|
|
1901
|
+
};
|
|
1902
|
+
|
|
1903
|
+
// ../config-mutations/src/formats/toml.ts
|
|
1904
|
+
import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
|
|
1905
|
+
function isConfigObject2(value) {
|
|
1906
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1907
|
+
}
|
|
1908
|
+
function parse3(content) {
|
|
1909
|
+
if (!content || content.trim() === "") {
|
|
1910
|
+
return {};
|
|
1911
|
+
}
|
|
1912
|
+
const parsed = parseToml(content);
|
|
1913
|
+
if (!isConfigObject2(parsed)) {
|
|
1914
|
+
throw new Error("Expected TOML document to be a table.");
|
|
1915
|
+
}
|
|
1916
|
+
return parsed;
|
|
1917
|
+
}
|
|
1918
|
+
function serialize2(obj) {
|
|
1919
|
+
const serialized = stringifyToml(obj);
|
|
1920
|
+
return serialized.endsWith("\n") ? serialized : `${serialized}
|
|
1921
|
+
`;
|
|
1922
|
+
}
|
|
1923
|
+
function merge2(base, patch) {
|
|
1924
|
+
const result = { ...base };
|
|
1925
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
1926
|
+
if (value === void 0) {
|
|
1927
|
+
continue;
|
|
1928
|
+
}
|
|
1929
|
+
const existing = result[key];
|
|
1930
|
+
if (isConfigObject2(existing) && isConfigObject2(value)) {
|
|
1931
|
+
result[key] = merge2(existing, value);
|
|
1932
|
+
continue;
|
|
1933
|
+
}
|
|
1934
|
+
result[key] = value;
|
|
1935
|
+
}
|
|
1936
|
+
return result;
|
|
1937
|
+
}
|
|
1938
|
+
function prune2(obj, shape) {
|
|
1939
|
+
let changed = false;
|
|
1940
|
+
const result = { ...obj };
|
|
1941
|
+
for (const [key, pattern] of Object.entries(shape)) {
|
|
1942
|
+
if (!(key in result)) {
|
|
1943
|
+
continue;
|
|
1944
|
+
}
|
|
1945
|
+
const current = result[key];
|
|
1946
|
+
if (isConfigObject2(pattern) && Object.keys(pattern).length === 0) {
|
|
1947
|
+
delete result[key];
|
|
1948
|
+
changed = true;
|
|
1949
|
+
continue;
|
|
1950
|
+
}
|
|
1951
|
+
if (isConfigObject2(pattern) && isConfigObject2(current)) {
|
|
1952
|
+
const { changed: childChanged, result: childResult } = prune2(
|
|
1953
|
+
current,
|
|
1954
|
+
pattern
|
|
1955
|
+
);
|
|
1956
|
+
if (childChanged) {
|
|
1957
|
+
changed = true;
|
|
1958
|
+
}
|
|
1959
|
+
if (Object.keys(childResult).length === 0) {
|
|
1960
|
+
delete result[key];
|
|
1961
|
+
} else {
|
|
1962
|
+
result[key] = childResult;
|
|
1963
|
+
}
|
|
1964
|
+
continue;
|
|
1965
|
+
}
|
|
1966
|
+
delete result[key];
|
|
1967
|
+
changed = true;
|
|
1968
|
+
}
|
|
1969
|
+
return { changed, result };
|
|
1970
|
+
}
|
|
1971
|
+
var tomlFormat = {
|
|
1972
|
+
parse: parse3,
|
|
1973
|
+
serialize: serialize2,
|
|
1974
|
+
merge: merge2,
|
|
1975
|
+
prune: prune2
|
|
1976
|
+
};
|
|
1977
|
+
|
|
1978
|
+
// ../config-mutations/src/formats/index.ts
|
|
1979
|
+
var formatRegistry = {
|
|
1980
|
+
json: jsonFormat,
|
|
1981
|
+
toml: tomlFormat
|
|
1982
|
+
};
|
|
1983
|
+
var extensionMap = {
|
|
1984
|
+
".json": "json",
|
|
1985
|
+
".toml": "toml"
|
|
1986
|
+
};
|
|
1987
|
+
function getConfigFormat(pathOrFormat) {
|
|
1988
|
+
if (pathOrFormat in formatRegistry) {
|
|
1989
|
+
return formatRegistry[pathOrFormat];
|
|
1990
|
+
}
|
|
1991
|
+
const ext = getExtension(pathOrFormat);
|
|
1992
|
+
const formatName = extensionMap[ext];
|
|
1993
|
+
if (!formatName) {
|
|
1994
|
+
throw new Error(
|
|
1995
|
+
`Unsupported config format. Cannot detect format from "${pathOrFormat}". Supported extensions: ${Object.keys(extensionMap).join(", ")}. Supported format names: ${Object.keys(formatRegistry).join(", ")}.`
|
|
1996
|
+
);
|
|
1997
|
+
}
|
|
1998
|
+
return formatRegistry[formatName];
|
|
1999
|
+
}
|
|
2000
|
+
function detectFormat(path4) {
|
|
2001
|
+
const ext = getExtension(path4);
|
|
2002
|
+
return extensionMap[ext];
|
|
2003
|
+
}
|
|
2004
|
+
function getExtension(path4) {
|
|
2005
|
+
const lastDot = path4.lastIndexOf(".");
|
|
2006
|
+
if (lastDot === -1) {
|
|
2007
|
+
return "";
|
|
2008
|
+
}
|
|
2009
|
+
return path4.slice(lastDot).toLowerCase();
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
// ../config-mutations/src/execution/path-utils.ts
|
|
2013
|
+
import path2 from "node:path";
|
|
2014
|
+
function expandHome(targetPath, homeDir) {
|
|
2015
|
+
if (!targetPath?.startsWith("~")) {
|
|
2016
|
+
return targetPath;
|
|
2017
|
+
}
|
|
2018
|
+
if (targetPath.startsWith("~./")) {
|
|
2019
|
+
targetPath = `~/.${targetPath.slice(3)}`;
|
|
2020
|
+
}
|
|
2021
|
+
let remainder = targetPath.slice(1);
|
|
2022
|
+
if (remainder.startsWith("/") || remainder.startsWith("\\")) {
|
|
2023
|
+
remainder = remainder.slice(1);
|
|
2024
|
+
} else if (remainder.startsWith(".")) {
|
|
2025
|
+
remainder = remainder.slice(1);
|
|
2026
|
+
if (remainder.startsWith("/") || remainder.startsWith("\\")) {
|
|
2027
|
+
remainder = remainder.slice(1);
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
return remainder.length === 0 ? homeDir : path2.join(homeDir, remainder);
|
|
2031
|
+
}
|
|
2032
|
+
function validateHomePath(targetPath) {
|
|
2033
|
+
if (typeof targetPath !== "string" || targetPath.length === 0) {
|
|
2034
|
+
throw new Error("Target path must be a non-empty string.");
|
|
2035
|
+
}
|
|
2036
|
+
if (!targetPath.startsWith("~")) {
|
|
2037
|
+
throw new Error(
|
|
2038
|
+
`All target paths must be home-relative (start with ~). Received: "${targetPath}"`
|
|
2039
|
+
);
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
function resolvePath(rawPath, homeDir, pathMapper) {
|
|
2043
|
+
validateHomePath(rawPath);
|
|
2044
|
+
const expanded = expandHome(rawPath, homeDir);
|
|
2045
|
+
if (!pathMapper) {
|
|
2046
|
+
return expanded;
|
|
2047
|
+
}
|
|
2048
|
+
const rawDirectory = path2.dirname(expanded);
|
|
2049
|
+
const mappedDirectory = pathMapper.mapTargetDirectory({
|
|
2050
|
+
targetDirectory: rawDirectory
|
|
2051
|
+
});
|
|
2052
|
+
const filename = path2.basename(expanded);
|
|
2053
|
+
return filename.length === 0 ? mappedDirectory : path2.join(mappedDirectory, filename);
|
|
2054
|
+
}
|
|
2055
|
+
|
|
2056
|
+
// ../config-mutations/src/fs-utils.ts
|
|
2057
|
+
function isNotFound(error) {
|
|
2058
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
2059
|
+
}
|
|
2060
|
+
async function readFileIfExists(fs, target) {
|
|
2061
|
+
try {
|
|
2062
|
+
return await fs.readFile(target, "utf8");
|
|
2063
|
+
} catch (error) {
|
|
2064
|
+
if (isNotFound(error)) {
|
|
2065
|
+
return null;
|
|
2066
|
+
}
|
|
2067
|
+
throw error;
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
async function pathExists(fs, target) {
|
|
2071
|
+
try {
|
|
2072
|
+
await fs.stat(target);
|
|
2073
|
+
return true;
|
|
2074
|
+
} catch (error) {
|
|
2075
|
+
if (isNotFound(error)) {
|
|
2076
|
+
return false;
|
|
2077
|
+
}
|
|
2078
|
+
throw error;
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
function createTimestamp() {
|
|
2082
|
+
return (/* @__PURE__ */ new Date()).toISOString().replaceAll(":", "-").replaceAll(".", "-");
|
|
2083
|
+
}
|
|
2084
|
+
|
|
2085
|
+
// ../config-mutations/src/execution/apply-mutation.ts
|
|
2086
|
+
function resolveValue(resolver, options) {
|
|
2087
|
+
if (typeof resolver === "function") {
|
|
2088
|
+
return resolver(options);
|
|
2089
|
+
}
|
|
2090
|
+
return resolver;
|
|
2091
|
+
}
|
|
2092
|
+
function createInvalidDocumentBackupPath(targetPath) {
|
|
2093
|
+
const ext = targetPath.includes(".") ? targetPath.split(".").pop() : "bak";
|
|
2094
|
+
return `${targetPath}.invalid-${createTimestamp()}.${ext}`;
|
|
2095
|
+
}
|
|
2096
|
+
async function backupInvalidDocument(fs, targetPath, content) {
|
|
2097
|
+
const backupPath = createInvalidDocumentBackupPath(targetPath);
|
|
2098
|
+
await fs.writeFile(backupPath, content, { encoding: "utf8" });
|
|
2099
|
+
}
|
|
2100
|
+
function describeMutation(kind, targetPath) {
|
|
2101
|
+
const displayPath = targetPath ?? "target";
|
|
2102
|
+
switch (kind) {
|
|
2103
|
+
case "ensureDirectory":
|
|
2104
|
+
return `Create ${displayPath}`;
|
|
2105
|
+
case "removeDirectory":
|
|
2106
|
+
return `Remove directory ${displayPath}`;
|
|
2107
|
+
case "backup":
|
|
2108
|
+
return `Backup ${displayPath}`;
|
|
2109
|
+
case "templateWrite":
|
|
2110
|
+
return `Write ${displayPath}`;
|
|
2111
|
+
case "chmod":
|
|
2112
|
+
return `Set permissions on ${displayPath}`;
|
|
2113
|
+
case "removeFile":
|
|
2114
|
+
return `Remove ${displayPath}`;
|
|
2115
|
+
case "configMerge":
|
|
2116
|
+
case "configPrune":
|
|
2117
|
+
case "configTransform":
|
|
2118
|
+
case "templateMergeToml":
|
|
2119
|
+
case "templateMergeJson":
|
|
2120
|
+
return `Update ${displayPath}`;
|
|
2121
|
+
default:
|
|
2122
|
+
return "Operation";
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
function pruneKeysByPrefix(table, prefix) {
|
|
2126
|
+
const result = {};
|
|
2127
|
+
for (const [key, value] of Object.entries(table)) {
|
|
2128
|
+
if (!key.startsWith(prefix)) {
|
|
2129
|
+
result[key] = value;
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
2132
|
+
return result;
|
|
2133
|
+
}
|
|
2134
|
+
function isConfigObject3(value) {
|
|
2135
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2136
|
+
}
|
|
2137
|
+
function mergeWithPruneByPrefix(base, patch, pruneByPrefix) {
|
|
2138
|
+
const result = { ...base };
|
|
2139
|
+
const prefixMap = pruneByPrefix ?? {};
|
|
2140
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
2141
|
+
const current = result[key];
|
|
2142
|
+
const prefix = prefixMap[key];
|
|
2143
|
+
if (isConfigObject3(current) && isConfigObject3(value)) {
|
|
2144
|
+
if (prefix) {
|
|
2145
|
+
const pruned = pruneKeysByPrefix(current, prefix);
|
|
2146
|
+
result[key] = { ...pruned, ...value };
|
|
2147
|
+
} else {
|
|
2148
|
+
result[key] = mergeWithPruneByPrefix(
|
|
2149
|
+
current,
|
|
2150
|
+
value,
|
|
2151
|
+
prefixMap
|
|
2152
|
+
);
|
|
2153
|
+
}
|
|
2154
|
+
continue;
|
|
2155
|
+
}
|
|
2156
|
+
result[key] = value;
|
|
2157
|
+
}
|
|
2158
|
+
return result;
|
|
2159
|
+
}
|
|
2160
|
+
async function applyMutation(mutation, context, options) {
|
|
2161
|
+
switch (mutation.kind) {
|
|
2162
|
+
case "ensureDirectory":
|
|
2163
|
+
return applyEnsureDirectory(mutation, context, options);
|
|
2164
|
+
case "removeDirectory":
|
|
2165
|
+
return applyRemoveDirectory(mutation, context, options);
|
|
2166
|
+
case "removeFile":
|
|
2167
|
+
return applyRemoveFile(mutation, context, options);
|
|
2168
|
+
case "chmod":
|
|
2169
|
+
return applyChmod(mutation, context, options);
|
|
2170
|
+
case "backup":
|
|
2171
|
+
return applyBackup(mutation, context, options);
|
|
2172
|
+
case "configMerge":
|
|
2173
|
+
return applyConfigMerge(mutation, context, options);
|
|
2174
|
+
case "configPrune":
|
|
2175
|
+
return applyConfigPrune(mutation, context, options);
|
|
2176
|
+
case "configTransform":
|
|
2177
|
+
return applyConfigTransform(mutation, context, options);
|
|
2178
|
+
case "templateWrite":
|
|
2179
|
+
return applyTemplateWrite(mutation, context, options);
|
|
2180
|
+
case "templateMergeToml":
|
|
2181
|
+
return applyTemplateMerge(mutation, context, options, "toml");
|
|
2182
|
+
case "templateMergeJson":
|
|
2183
|
+
return applyTemplateMerge(mutation, context, options, "json");
|
|
2184
|
+
default: {
|
|
2185
|
+
const never = mutation;
|
|
2186
|
+
throw new Error(`Unknown mutation kind: ${never.kind}`);
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
async function applyEnsureDirectory(mutation, context, options) {
|
|
2191
|
+
const rawPath = resolveValue(mutation.path, options);
|
|
2192
|
+
const targetPath = resolvePath(rawPath, context.homeDir, context.pathMapper);
|
|
2193
|
+
const details = {
|
|
2194
|
+
kind: mutation.kind,
|
|
2195
|
+
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
2196
|
+
targetPath
|
|
2197
|
+
};
|
|
2198
|
+
const existed = await pathExists(context.fs, targetPath);
|
|
2199
|
+
if (!context.dryRun) {
|
|
2200
|
+
await context.fs.mkdir(targetPath, { recursive: true });
|
|
2201
|
+
}
|
|
2202
|
+
return {
|
|
2203
|
+
outcome: {
|
|
2204
|
+
changed: !existed,
|
|
2205
|
+
effect: "mkdir",
|
|
2206
|
+
detail: existed ? "noop" : "create"
|
|
2207
|
+
},
|
|
2208
|
+
details
|
|
2209
|
+
};
|
|
2210
|
+
}
|
|
2211
|
+
async function applyRemoveDirectory(mutation, context, options) {
|
|
2212
|
+
const rawPath = resolveValue(mutation.path, options);
|
|
2213
|
+
const targetPath = resolvePath(rawPath, context.homeDir, context.pathMapper);
|
|
2214
|
+
const details = {
|
|
2215
|
+
kind: mutation.kind,
|
|
2216
|
+
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
2217
|
+
targetPath
|
|
2218
|
+
};
|
|
2219
|
+
const existed = await pathExists(context.fs, targetPath);
|
|
2220
|
+
if (!existed) {
|
|
2221
|
+
return {
|
|
2222
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
2223
|
+
details
|
|
2224
|
+
};
|
|
2225
|
+
}
|
|
2226
|
+
if (typeof context.fs.rm !== "function") {
|
|
2227
|
+
return {
|
|
2228
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
2229
|
+
details
|
|
2230
|
+
};
|
|
2231
|
+
}
|
|
2232
|
+
if (mutation.force) {
|
|
2233
|
+
if (!context.dryRun) {
|
|
2234
|
+
await context.fs.rm(targetPath, { recursive: true, force: true });
|
|
2235
|
+
}
|
|
2236
|
+
return {
|
|
2237
|
+
outcome: { changed: true, effect: "delete", detail: "delete" },
|
|
2238
|
+
details
|
|
2239
|
+
};
|
|
2240
|
+
}
|
|
2241
|
+
const entries = await context.fs.readdir(targetPath);
|
|
2242
|
+
if (entries.length > 0) {
|
|
2243
|
+
return {
|
|
2244
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
2245
|
+
details
|
|
2246
|
+
};
|
|
2247
|
+
}
|
|
2248
|
+
if (!context.dryRun) {
|
|
2249
|
+
await context.fs.rm(targetPath, { recursive: true, force: true });
|
|
2250
|
+
}
|
|
2251
|
+
return {
|
|
2252
|
+
outcome: { changed: true, effect: "delete", detail: "delete" },
|
|
2253
|
+
details
|
|
2254
|
+
};
|
|
2255
|
+
}
|
|
2256
|
+
async function applyRemoveFile(mutation, context, options) {
|
|
2257
|
+
const rawPath = resolveValue(mutation.target, options);
|
|
2258
|
+
const targetPath = resolvePath(rawPath, context.homeDir, context.pathMapper);
|
|
2259
|
+
const details = {
|
|
2260
|
+
kind: mutation.kind,
|
|
2261
|
+
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
2262
|
+
targetPath
|
|
2263
|
+
};
|
|
2264
|
+
try {
|
|
2265
|
+
const content = await context.fs.readFile(targetPath, "utf8");
|
|
2266
|
+
const trimmed = content.trim();
|
|
2267
|
+
if (mutation.whenContentMatches && !mutation.whenContentMatches.test(trimmed)) {
|
|
2268
|
+
return {
|
|
2269
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
2270
|
+
details
|
|
2271
|
+
};
|
|
2272
|
+
}
|
|
2273
|
+
if (mutation.whenEmpty && trimmed.length > 0) {
|
|
2274
|
+
return {
|
|
2275
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
2276
|
+
details
|
|
2277
|
+
};
|
|
2278
|
+
}
|
|
2279
|
+
if (!context.dryRun) {
|
|
2280
|
+
await context.fs.unlink(targetPath);
|
|
2281
|
+
}
|
|
2282
|
+
return {
|
|
2283
|
+
outcome: { changed: true, effect: "delete", detail: "delete" },
|
|
2284
|
+
details
|
|
2285
|
+
};
|
|
2286
|
+
} catch (error) {
|
|
2287
|
+
if (isNotFound(error)) {
|
|
2288
|
+
return {
|
|
2289
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
2290
|
+
details
|
|
2291
|
+
};
|
|
2292
|
+
}
|
|
2293
|
+
throw error;
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2296
|
+
async function applyChmod(mutation, context, options) {
|
|
2297
|
+
const rawPath = resolveValue(mutation.target, options);
|
|
2298
|
+
const targetPath = resolvePath(rawPath, context.homeDir, context.pathMapper);
|
|
2299
|
+
const details = {
|
|
2300
|
+
kind: mutation.kind,
|
|
2301
|
+
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
2302
|
+
targetPath
|
|
2303
|
+
};
|
|
2304
|
+
if (typeof context.fs.chmod !== "function") {
|
|
2305
|
+
return {
|
|
2306
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
2307
|
+
details
|
|
2308
|
+
};
|
|
2309
|
+
}
|
|
2310
|
+
try {
|
|
2311
|
+
const stat = await context.fs.stat(targetPath);
|
|
2312
|
+
const currentMode = typeof stat.mode === "number" ? stat.mode & 511 : null;
|
|
2313
|
+
if (currentMode === mutation.mode) {
|
|
2314
|
+
return {
|
|
2315
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
2316
|
+
details
|
|
2317
|
+
};
|
|
2318
|
+
}
|
|
2319
|
+
if (!context.dryRun) {
|
|
2320
|
+
await context.fs.chmod(targetPath, mutation.mode);
|
|
2321
|
+
}
|
|
2322
|
+
return {
|
|
2323
|
+
outcome: { changed: true, effect: "chmod", detail: "update" },
|
|
2324
|
+
details
|
|
2325
|
+
};
|
|
2326
|
+
} catch (error) {
|
|
2327
|
+
if (isNotFound(error)) {
|
|
2328
|
+
return {
|
|
2329
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
2330
|
+
details
|
|
2331
|
+
};
|
|
2332
|
+
}
|
|
2333
|
+
throw error;
|
|
2334
|
+
}
|
|
2335
|
+
}
|
|
2336
|
+
async function applyBackup(mutation, context, options) {
|
|
2337
|
+
const rawPath = resolveValue(mutation.target, options);
|
|
2338
|
+
const targetPath = resolvePath(rawPath, context.homeDir, context.pathMapper);
|
|
2339
|
+
const details = {
|
|
2340
|
+
kind: mutation.kind,
|
|
2341
|
+
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
2342
|
+
targetPath
|
|
2343
|
+
};
|
|
2344
|
+
const content = await readFileIfExists(context.fs, targetPath);
|
|
2345
|
+
if (content === null) {
|
|
2346
|
+
return {
|
|
2347
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
2348
|
+
details
|
|
2349
|
+
};
|
|
2350
|
+
}
|
|
2351
|
+
if (!context.dryRun) {
|
|
2352
|
+
const backupPath = `${targetPath}.backup-${createTimestamp()}`;
|
|
2353
|
+
await context.fs.writeFile(backupPath, content, { encoding: "utf8" });
|
|
2354
|
+
}
|
|
2355
|
+
return {
|
|
2356
|
+
outcome: { changed: true, effect: "copy", detail: "backup" },
|
|
2357
|
+
details
|
|
2358
|
+
};
|
|
2359
|
+
}
|
|
2360
|
+
async function applyConfigMerge(mutation, context, options) {
|
|
2361
|
+
const rawPath = resolveValue(mutation.target, options);
|
|
2362
|
+
const targetPath = resolvePath(rawPath, context.homeDir, context.pathMapper);
|
|
2363
|
+
const details = {
|
|
2364
|
+
kind: mutation.kind,
|
|
2365
|
+
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
2366
|
+
targetPath
|
|
2367
|
+
};
|
|
2368
|
+
const formatName = mutation.format ?? detectFormat(rawPath);
|
|
2369
|
+
if (!formatName) {
|
|
2370
|
+
throw new Error(
|
|
2371
|
+
`Cannot detect config format for "${rawPath}". Provide explicit format option.`
|
|
2372
|
+
);
|
|
2373
|
+
}
|
|
2374
|
+
const format = getConfigFormat(formatName);
|
|
2375
|
+
const rawContent = await readFileIfExists(context.fs, targetPath);
|
|
2376
|
+
let current;
|
|
2377
|
+
try {
|
|
2378
|
+
current = rawContent === null ? {} : format.parse(rawContent);
|
|
2379
|
+
} catch {
|
|
2380
|
+
if (rawContent !== null) {
|
|
2381
|
+
await backupInvalidDocument(context.fs, targetPath, rawContent);
|
|
2382
|
+
}
|
|
2383
|
+
current = {};
|
|
2384
|
+
}
|
|
2385
|
+
const value = resolveValue(mutation.value, options);
|
|
2386
|
+
let merged;
|
|
2387
|
+
if (mutation.pruneByPrefix) {
|
|
2388
|
+
merged = mergeWithPruneByPrefix(current, value, mutation.pruneByPrefix);
|
|
2389
|
+
} else {
|
|
2390
|
+
merged = format.merge(current, value);
|
|
2391
|
+
}
|
|
2392
|
+
const serialized = format.serialize(merged);
|
|
2393
|
+
const changed = serialized !== rawContent;
|
|
2394
|
+
if (changed && !context.dryRun) {
|
|
2395
|
+
await context.fs.writeFile(targetPath, serialized, { encoding: "utf8" });
|
|
2396
|
+
}
|
|
2397
|
+
return {
|
|
2398
|
+
outcome: {
|
|
2399
|
+
changed,
|
|
2400
|
+
effect: changed ? "write" : "none",
|
|
2401
|
+
detail: changed ? rawContent === null ? "create" : "update" : "noop"
|
|
2402
|
+
},
|
|
2403
|
+
details
|
|
2404
|
+
};
|
|
2405
|
+
}
|
|
2406
|
+
async function applyConfigPrune(mutation, context, options) {
|
|
2407
|
+
const rawPath = resolveValue(mutation.target, options);
|
|
2408
|
+
const targetPath = resolvePath(rawPath, context.homeDir, context.pathMapper);
|
|
2409
|
+
const details = {
|
|
2410
|
+
kind: mutation.kind,
|
|
2411
|
+
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
2412
|
+
targetPath
|
|
2413
|
+
};
|
|
2414
|
+
const rawContent = await readFileIfExists(context.fs, targetPath);
|
|
2415
|
+
if (rawContent === null) {
|
|
2416
|
+
return {
|
|
2417
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
2418
|
+
details
|
|
2419
|
+
};
|
|
2420
|
+
}
|
|
2421
|
+
const formatName = mutation.format ?? detectFormat(rawPath);
|
|
2422
|
+
if (!formatName) {
|
|
2423
|
+
throw new Error(
|
|
2424
|
+
`Cannot detect config format for "${rawPath}". Provide explicit format option.`
|
|
2425
|
+
);
|
|
2426
|
+
}
|
|
2427
|
+
const format = getConfigFormat(formatName);
|
|
2428
|
+
let current;
|
|
2429
|
+
try {
|
|
2430
|
+
current = format.parse(rawContent);
|
|
2431
|
+
} catch {
|
|
2432
|
+
return {
|
|
2433
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
2434
|
+
details
|
|
2435
|
+
};
|
|
2436
|
+
}
|
|
2437
|
+
if (mutation.onlyIf && !mutation.onlyIf(current, options)) {
|
|
2438
|
+
return {
|
|
2439
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
2440
|
+
details
|
|
2441
|
+
};
|
|
2442
|
+
}
|
|
2443
|
+
const shape = resolveValue(mutation.shape, options);
|
|
2444
|
+
const { changed, result } = format.prune(current, shape);
|
|
2445
|
+
if (!changed) {
|
|
2446
|
+
return {
|
|
2447
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
2448
|
+
details
|
|
2449
|
+
};
|
|
2450
|
+
}
|
|
2451
|
+
if (Object.keys(result).length === 0) {
|
|
2452
|
+
if (!context.dryRun) {
|
|
2453
|
+
await context.fs.unlink(targetPath);
|
|
2454
|
+
}
|
|
2455
|
+
return {
|
|
2456
|
+
outcome: { changed: true, effect: "delete", detail: "delete" },
|
|
2457
|
+
details
|
|
2458
|
+
};
|
|
2459
|
+
}
|
|
2460
|
+
const serialized = format.serialize(result);
|
|
2461
|
+
if (!context.dryRun) {
|
|
2462
|
+
await context.fs.writeFile(targetPath, serialized, { encoding: "utf8" });
|
|
2463
|
+
}
|
|
2464
|
+
return {
|
|
2465
|
+
outcome: { changed: true, effect: "write", detail: "update" },
|
|
2466
|
+
details
|
|
2467
|
+
};
|
|
2468
|
+
}
|
|
2469
|
+
async function applyConfigTransform(mutation, context, options) {
|
|
2470
|
+
const rawPath = resolveValue(mutation.target, options);
|
|
2471
|
+
const targetPath = resolvePath(rawPath, context.homeDir, context.pathMapper);
|
|
2472
|
+
const details = {
|
|
2473
|
+
kind: mutation.kind,
|
|
2474
|
+
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
2475
|
+
targetPath
|
|
2476
|
+
};
|
|
2477
|
+
const formatName = mutation.format ?? detectFormat(rawPath);
|
|
2478
|
+
if (!formatName) {
|
|
2479
|
+
throw new Error(
|
|
2480
|
+
`Cannot detect config format for "${rawPath}". Provide explicit format option.`
|
|
2481
|
+
);
|
|
2482
|
+
}
|
|
2483
|
+
const format = getConfigFormat(formatName);
|
|
2484
|
+
const rawContent = await readFileIfExists(context.fs, targetPath);
|
|
2485
|
+
let current;
|
|
2486
|
+
try {
|
|
2487
|
+
current = rawContent === null ? {} : format.parse(rawContent);
|
|
2488
|
+
} catch {
|
|
2489
|
+
if (rawContent !== null) {
|
|
2490
|
+
await backupInvalidDocument(context.fs, targetPath, rawContent);
|
|
2491
|
+
}
|
|
2492
|
+
current = {};
|
|
2493
|
+
}
|
|
2494
|
+
const { content: transformed, changed } = mutation.transform(current, options);
|
|
2495
|
+
if (!changed) {
|
|
2496
|
+
return {
|
|
2497
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
2498
|
+
details
|
|
2499
|
+
};
|
|
2500
|
+
}
|
|
2501
|
+
if (transformed === null) {
|
|
2502
|
+
if (rawContent === null) {
|
|
2503
|
+
return {
|
|
2504
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
2505
|
+
details
|
|
2506
|
+
};
|
|
2507
|
+
}
|
|
2508
|
+
if (!context.dryRun) {
|
|
2509
|
+
await context.fs.unlink(targetPath);
|
|
2510
|
+
}
|
|
2511
|
+
return {
|
|
2512
|
+
outcome: { changed: true, effect: "delete", detail: "delete" },
|
|
2513
|
+
details
|
|
2514
|
+
};
|
|
2515
|
+
}
|
|
2516
|
+
const serialized = format.serialize(transformed);
|
|
2517
|
+
if (!context.dryRun) {
|
|
2518
|
+
await context.fs.writeFile(targetPath, serialized, { encoding: "utf8" });
|
|
2519
|
+
}
|
|
2520
|
+
return {
|
|
2521
|
+
outcome: {
|
|
2522
|
+
changed: true,
|
|
2523
|
+
effect: "write",
|
|
2524
|
+
detail: rawContent === null ? "create" : "update"
|
|
2525
|
+
},
|
|
2526
|
+
details
|
|
2527
|
+
};
|
|
2528
|
+
}
|
|
2529
|
+
async function applyTemplateWrite(mutation, context, options) {
|
|
2530
|
+
if (!context.templates) {
|
|
2531
|
+
throw new Error(
|
|
2532
|
+
"Template mutations require a templates loader. Provide templates function to runMutations context."
|
|
2533
|
+
);
|
|
2534
|
+
}
|
|
2535
|
+
const rawPath = resolveValue(mutation.target, options);
|
|
2536
|
+
const targetPath = resolvePath(rawPath, context.homeDir, context.pathMapper);
|
|
2537
|
+
const details = {
|
|
2538
|
+
kind: mutation.kind,
|
|
2539
|
+
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
2540
|
+
targetPath
|
|
2541
|
+
};
|
|
2542
|
+
const template = await context.templates(mutation.templateId);
|
|
2543
|
+
const templateContext = mutation.context ? resolveValue(mutation.context, options) : {};
|
|
2544
|
+
const rendered = Mustache.render(template, templateContext);
|
|
2545
|
+
const existed = await pathExists(context.fs, targetPath);
|
|
2546
|
+
if (!context.dryRun) {
|
|
2547
|
+
await context.fs.writeFile(targetPath, rendered, { encoding: "utf8" });
|
|
2548
|
+
}
|
|
2549
|
+
return {
|
|
2550
|
+
outcome: {
|
|
2551
|
+
changed: true,
|
|
2552
|
+
effect: "write",
|
|
2553
|
+
detail: existed ? "update" : "create"
|
|
2554
|
+
},
|
|
2555
|
+
details
|
|
2556
|
+
};
|
|
2557
|
+
}
|
|
2558
|
+
async function applyTemplateMerge(mutation, context, options, formatName) {
|
|
2559
|
+
if (!context.templates) {
|
|
2560
|
+
throw new Error(
|
|
2561
|
+
"Template mutations require a templates loader. Provide templates function to runMutations context."
|
|
2562
|
+
);
|
|
2563
|
+
}
|
|
2564
|
+
const rawPath = resolveValue(mutation.target, options);
|
|
2565
|
+
const targetPath = resolvePath(rawPath, context.homeDir, context.pathMapper);
|
|
2566
|
+
const details = {
|
|
2567
|
+
kind: mutation.kind,
|
|
2568
|
+
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
2569
|
+
targetPath
|
|
2570
|
+
};
|
|
2571
|
+
const format = getConfigFormat(formatName);
|
|
2572
|
+
const template = await context.templates(mutation.templateId);
|
|
2573
|
+
const templateContext = mutation.context ? resolveValue(mutation.context, options) : {};
|
|
2574
|
+
const rendered = Mustache.render(template, templateContext);
|
|
2575
|
+
let templateDoc;
|
|
2576
|
+
try {
|
|
2577
|
+
templateDoc = format.parse(rendered);
|
|
2578
|
+
} catch (error) {
|
|
2579
|
+
throw new Error(
|
|
2580
|
+
`Failed to parse rendered template "${mutation.templateId}" as ${formatName.toUpperCase()}: ${error}`,
|
|
2581
|
+
{ cause: error }
|
|
2582
|
+
);
|
|
2583
|
+
}
|
|
2584
|
+
const rawContent = await readFileIfExists(context.fs, targetPath);
|
|
2585
|
+
let current;
|
|
2586
|
+
try {
|
|
2587
|
+
current = rawContent === null ? {} : format.parse(rawContent);
|
|
2588
|
+
} catch {
|
|
2589
|
+
if (rawContent !== null) {
|
|
2590
|
+
await backupInvalidDocument(context.fs, targetPath, rawContent);
|
|
2591
|
+
}
|
|
2592
|
+
current = {};
|
|
2593
|
+
}
|
|
2594
|
+
const merged = format.merge(current, templateDoc);
|
|
2595
|
+
const serialized = format.serialize(merged);
|
|
2596
|
+
const changed = serialized !== rawContent;
|
|
2597
|
+
if (changed && !context.dryRun) {
|
|
2598
|
+
await context.fs.writeFile(targetPath, serialized, { encoding: "utf8" });
|
|
2599
|
+
}
|
|
2600
|
+
return {
|
|
2601
|
+
outcome: {
|
|
2602
|
+
changed,
|
|
2603
|
+
effect: changed ? "write" : "none",
|
|
2604
|
+
detail: changed ? rawContent === null ? "create" : "update" : "noop"
|
|
2605
|
+
},
|
|
2606
|
+
details
|
|
2607
|
+
};
|
|
2608
|
+
}
|
|
2609
|
+
|
|
2610
|
+
// ../config-mutations/src/execution/run-mutations.ts
|
|
2611
|
+
async function runMutations(mutations, context, options) {
|
|
2612
|
+
const effects = [];
|
|
2613
|
+
let anyChanged = false;
|
|
2614
|
+
const resolverOptions = options ?? {};
|
|
2615
|
+
for (const mutation of mutations) {
|
|
2616
|
+
const { outcome } = await executeMutation(
|
|
2617
|
+
mutation,
|
|
2618
|
+
context,
|
|
2619
|
+
resolverOptions
|
|
2620
|
+
);
|
|
2621
|
+
effects.push(outcome);
|
|
2622
|
+
if (outcome.changed) {
|
|
2623
|
+
anyChanged = true;
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
return {
|
|
2627
|
+
changed: anyChanged,
|
|
2628
|
+
effects
|
|
2629
|
+
};
|
|
2630
|
+
}
|
|
2631
|
+
async function executeMutation(mutation, context, options) {
|
|
2632
|
+
context.observers?.onStart?.({
|
|
2633
|
+
kind: mutation.kind,
|
|
2634
|
+
label: mutation.label ?? mutation.kind,
|
|
2635
|
+
targetPath: void 0
|
|
2636
|
+
// Will be resolved during apply
|
|
2637
|
+
});
|
|
2638
|
+
try {
|
|
2639
|
+
const { outcome, details } = await applyMutation(mutation, context, options);
|
|
2640
|
+
context.observers?.onComplete?.(details, outcome);
|
|
2641
|
+
return { outcome, details };
|
|
2642
|
+
} catch (error) {
|
|
2643
|
+
context.observers?.onError?.(
|
|
2644
|
+
{
|
|
2645
|
+
kind: mutation.kind,
|
|
2646
|
+
label: mutation.label ?? mutation.kind,
|
|
2647
|
+
targetPath: void 0
|
|
2648
|
+
},
|
|
2649
|
+
error
|
|
2650
|
+
);
|
|
2651
|
+
throw error;
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2654
|
+
|
|
2655
|
+
// ../config-mutations/src/template/render.ts
|
|
2656
|
+
import Mustache2 from "mustache";
|
|
2657
|
+
var originalEscape = Mustache2.escape;
|
|
2658
|
+
|
|
2659
|
+
// ../agent-skill-config/src/apply.ts
|
|
2660
|
+
var UnsupportedAgentError = class extends Error {
|
|
2661
|
+
constructor(agentId) {
|
|
2662
|
+
super(`Unsupported agent: ${agentId}`);
|
|
2663
|
+
this.name = "UnsupportedAgentError";
|
|
2664
|
+
}
|
|
2665
|
+
};
|
|
2666
|
+
function toHomeRelative(localSkillDir) {
|
|
2667
|
+
if (localSkillDir.startsWith("~/") || localSkillDir === "~") {
|
|
2668
|
+
return localSkillDir;
|
|
2669
|
+
}
|
|
2670
|
+
const normalized = localSkillDir.startsWith("./") ? localSkillDir.slice(2) : localSkillDir;
|
|
2671
|
+
return `~/${normalized}`;
|
|
2672
|
+
}
|
|
2673
|
+
var SKILL_TEMPLATE_ID = "__skill_content__";
|
|
2674
|
+
async function installSkill(agentId, skill, options) {
|
|
2675
|
+
const support = resolveAgentSupport(agentId);
|
|
2676
|
+
if (support.status !== "supported") {
|
|
2677
|
+
throw new UnsupportedAgentError(agentId);
|
|
2678
|
+
}
|
|
2679
|
+
const scope = options.scope ?? "local";
|
|
2680
|
+
const config = support.config;
|
|
2681
|
+
const skillDir = scope === "global" ? config.globalSkillDir : toHomeRelative(config.localSkillDir);
|
|
2682
|
+
const skillFolderPath = `${skillDir}/${skill.name}`;
|
|
2683
|
+
const skillFilePath = `${skillFolderPath}/SKILL.md`;
|
|
2684
|
+
const displayPath = `${scope === "global" ? config.globalSkillDir : config.localSkillDir}/${skill.name}/SKILL.md`;
|
|
2685
|
+
await runMutations(
|
|
2686
|
+
[
|
|
2687
|
+
fileMutation.ensureDirectory({
|
|
2688
|
+
path: skillFolderPath,
|
|
2689
|
+
label: `Ensure skill directory ${skill.name}`
|
|
2690
|
+
}),
|
|
2691
|
+
templateMutation.write({
|
|
2692
|
+
target: skillFilePath,
|
|
2693
|
+
templateId: SKILL_TEMPLATE_ID,
|
|
2694
|
+
label: `Write skill ${skill.name}`
|
|
2695
|
+
})
|
|
2696
|
+
],
|
|
2697
|
+
{
|
|
2698
|
+
fs: options.fs,
|
|
2699
|
+
homeDir: scope === "global" ? options.homeDir : options.cwd,
|
|
2700
|
+
dryRun: options.dryRun,
|
|
2701
|
+
observers: options.observers,
|
|
2702
|
+
templates: async (templateId) => {
|
|
2703
|
+
if (templateId === SKILL_TEMPLATE_ID) {
|
|
2704
|
+
return skill.content;
|
|
2705
|
+
}
|
|
2706
|
+
throw new Error(`Unknown template: ${templateId}`);
|
|
2707
|
+
}
|
|
2708
|
+
}
|
|
2709
|
+
);
|
|
2710
|
+
return { skillPath: skillFilePath, displayPath };
|
|
2711
|
+
}
|
|
2712
|
+
|
|
2713
|
+
// src/commands/installer.ts
|
|
2714
|
+
import os2 from "node:os";
|
|
2715
|
+
import path3 from "node:path";
|
|
2716
|
+
import * as nodeFs from "node:fs/promises";
|
|
2717
|
+
import { readFile } from "node:fs/promises";
|
|
2718
|
+
var DEFAULT_INSTALL_AGENT = "claude-code";
|
|
2719
|
+
var DEFAULT_INSTALL_SCOPE = "local";
|
|
2720
|
+
var TERMINAL_PILOT_SKILL_NAME = "terminal-pilot";
|
|
2721
|
+
var installableAgents = supportedAgents;
|
|
2722
|
+
function isNotFoundError(error) {
|
|
2723
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
2724
|
+
}
|
|
2725
|
+
function resolveInstallerServices(installer) {
|
|
2726
|
+
return {
|
|
2727
|
+
fs: installer?.fs ?? nodeFs,
|
|
2728
|
+
cwd: installer?.cwd ?? process.cwd(),
|
|
2729
|
+
homeDir: installer?.homeDir ?? os2.homedir(),
|
|
2730
|
+
platform: installer?.platform ?? process.platform
|
|
2731
|
+
};
|
|
2732
|
+
}
|
|
2733
|
+
function throwUnsupportedAgent(agent) {
|
|
2734
|
+
throw new UserError(`Unsupported agent: ${agent}`);
|
|
2735
|
+
}
|
|
2736
|
+
function resolveInstallableAgent(agent) {
|
|
2737
|
+
const skillSupport = resolveAgentSupport(agent);
|
|
2738
|
+
if (skillSupport.status !== "supported" || !skillSupport.id) {
|
|
2739
|
+
throwUnsupportedAgent(agent);
|
|
2740
|
+
}
|
|
2741
|
+
return skillSupport.id;
|
|
2742
|
+
}
|
|
2743
|
+
function resolveInstallScope(input) {
|
|
2744
|
+
if (input.local && input.global) {
|
|
2745
|
+
throw new UserError("Use either --local or --global, not both.");
|
|
2746
|
+
}
|
|
2747
|
+
if (input.local) {
|
|
2748
|
+
return "local";
|
|
2749
|
+
}
|
|
2750
|
+
if (input.global) {
|
|
2751
|
+
return "global";
|
|
2752
|
+
}
|
|
2753
|
+
return DEFAULT_INSTALL_SCOPE;
|
|
2754
|
+
}
|
|
2755
|
+
var terminalPilotTemplateCache;
|
|
2756
|
+
async function loadTerminalPilotTemplate() {
|
|
2757
|
+
if (terminalPilotTemplateCache !== void 0) {
|
|
2758
|
+
return terminalPilotTemplateCache;
|
|
2759
|
+
}
|
|
2760
|
+
const candidates = [
|
|
2761
|
+
new URL("./templates/terminal-pilot.md", import.meta.url),
|
|
2762
|
+
new URL("../templates/terminal-pilot.md", import.meta.url),
|
|
2763
|
+
new URL("../../../agent-skill-config/src/templates/terminal-pilot.md", import.meta.url)
|
|
2764
|
+
];
|
|
2765
|
+
for (const candidate of candidates) {
|
|
2766
|
+
try {
|
|
2767
|
+
terminalPilotTemplateCache = await readFile(candidate, "utf8");
|
|
2768
|
+
return terminalPilotTemplateCache;
|
|
2769
|
+
} catch (error) {
|
|
2770
|
+
if (!isNotFoundError(error)) {
|
|
2771
|
+
throw error;
|
|
2772
|
+
}
|
|
2773
|
+
}
|
|
2774
|
+
}
|
|
2775
|
+
throw new UserError("terminal-pilot skill template is missing.");
|
|
2776
|
+
}
|
|
2777
|
+
function resolveHomeRelativePath(targetPath, homeDir) {
|
|
2778
|
+
if (targetPath === "~") {
|
|
2779
|
+
return homeDir;
|
|
2780
|
+
}
|
|
2781
|
+
if (targetPath.startsWith("~/")) {
|
|
2782
|
+
return path3.join(homeDir, targetPath.slice(2));
|
|
2783
|
+
}
|
|
2784
|
+
return targetPath;
|
|
2785
|
+
}
|
|
2786
|
+
function getSkillFolderWithHome(agent, scope, cwd, homeDir) {
|
|
2787
|
+
const config = getAgentConfig(agent);
|
|
2788
|
+
if (!config) {
|
|
2789
|
+
throwUnsupportedAgent(agent);
|
|
2790
|
+
}
|
|
2791
|
+
return {
|
|
2792
|
+
displayPath: path3.join(
|
|
2793
|
+
scope === "global" ? config.globalSkillDir : config.localSkillDir,
|
|
2794
|
+
TERMINAL_PILOT_SKILL_NAME
|
|
2795
|
+
),
|
|
2796
|
+
fullPath: path3.join(
|
|
2797
|
+
scope === "global" ? resolveHomeRelativePath(config.globalSkillDir, homeDir) : path3.resolve(cwd, config.localSkillDir),
|
|
2798
|
+
TERMINAL_PILOT_SKILL_NAME
|
|
2799
|
+
)
|
|
2800
|
+
};
|
|
2801
|
+
}
|
|
2802
|
+
async function removeSkillFolder(fs, folderPath) {
|
|
2803
|
+
try {
|
|
2804
|
+
await fs.stat(folderPath);
|
|
2805
|
+
} catch (error) {
|
|
2806
|
+
if (isNotFoundError(error)) {
|
|
2807
|
+
return false;
|
|
2808
|
+
}
|
|
2809
|
+
throw error;
|
|
2810
|
+
}
|
|
2811
|
+
if (typeof fs.rm !== "function") {
|
|
2812
|
+
throw new UserError("The configured filesystem does not support removing directories.");
|
|
2813
|
+
}
|
|
2814
|
+
await fs.rm(folderPath, { recursive: true, force: true });
|
|
2815
|
+
return true;
|
|
2816
|
+
}
|
|
2817
|
+
|
|
2818
|
+
// src/commands/install.ts
|
|
2819
|
+
var params5 = S.Object({
|
|
2820
|
+
agent: S.Enum(installableAgents, {
|
|
2821
|
+
description: "Agent to install terminal-pilot for",
|
|
2822
|
+
default: DEFAULT_INSTALL_AGENT
|
|
2823
|
+
}),
|
|
2824
|
+
local: S.Optional(S.Boolean({ description: "Install the skill in the current project" })),
|
|
2825
|
+
global: S.Optional(S.Boolean({ description: "Install the skill in the user home directory" }))
|
|
2826
|
+
});
|
|
2827
|
+
var install = defineCommand({
|
|
2828
|
+
name: "install",
|
|
2829
|
+
description: "Install the terminal-pilot CLI skill.",
|
|
2830
|
+
scope: ["cli"],
|
|
2831
|
+
positional: ["agent"],
|
|
2832
|
+
params: params5,
|
|
2833
|
+
handler: async ({ params: params17, terminalPilotInstaller }) => {
|
|
2834
|
+
const services = resolveInstallerServices(terminalPilotInstaller);
|
|
1460
2835
|
const agent = resolveInstallableAgent(params17.agent);
|
|
1461
2836
|
const scope = resolveInstallScope(params17);
|
|
1462
2837
|
const template = await loadTerminalPilotTemplate();
|
|
@@ -1482,9 +2857,8 @@ var install = defineCommand5({
|
|
|
1482
2857
|
});
|
|
1483
2858
|
|
|
1484
2859
|
// src/commands/list-sessions.ts
|
|
1485
|
-
|
|
1486
|
-
var
|
|
1487
|
-
var listSessions = defineCommand6({
|
|
2860
|
+
var params6 = S.Object({});
|
|
2861
|
+
var listSessions = defineCommand({
|
|
1488
2862
|
name: "list-sessions",
|
|
1489
2863
|
description: "List active terminal sessions",
|
|
1490
2864
|
scope: ["cli", "mcp", "sdk"],
|
|
@@ -1502,12 +2876,11 @@ var listSessions = defineCommand6({
|
|
|
1502
2876
|
});
|
|
1503
2877
|
|
|
1504
2878
|
// src/commands/press-key.ts
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
session: S7.Optional(S7.String({ short: "s", description: "Session name" }))
|
|
2879
|
+
var params7 = S.Object({
|
|
2880
|
+
key: S.String({ description: "Named key to press" }),
|
|
2881
|
+
session: S.Optional(S.String({ short: "s", description: "Session name" }))
|
|
1509
2882
|
});
|
|
1510
|
-
var pressKey =
|
|
2883
|
+
var pressKey = defineCommand({
|
|
1511
2884
|
name: "press-key",
|
|
1512
2885
|
description: "Send a named key press to an active terminal session",
|
|
1513
2886
|
scope: ["cli", "mcp", "sdk"],
|
|
@@ -1521,12 +2894,11 @@ var pressKey = defineCommand7({
|
|
|
1521
2894
|
});
|
|
1522
2895
|
|
|
1523
2896
|
// src/commands/read-history.ts
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
last: S8.Optional(S8.Number({ short: "n", description: "Return only the last N lines" }))
|
|
2897
|
+
var params8 = S.Object({
|
|
2898
|
+
session: S.Optional(S.String({ short: "s", description: "Session name" })),
|
|
2899
|
+
last: S.Optional(S.Number({ short: "n", description: "Return only the last N lines" }))
|
|
1528
2900
|
});
|
|
1529
|
-
var readHistory =
|
|
2901
|
+
var readHistory = defineCommand({
|
|
1530
2902
|
name: "read-history",
|
|
1531
2903
|
description: "Read terminal output history",
|
|
1532
2904
|
scope: ["cli", "mcp", "sdk"],
|
|
@@ -1539,11 +2911,10 @@ var readHistory = defineCommand8({
|
|
|
1539
2911
|
});
|
|
1540
2912
|
|
|
1541
2913
|
// src/commands/read-screen.ts
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
session: S9.Optional(S9.String({ short: "s", description: "Session name" }))
|
|
2914
|
+
var params9 = S.Object({
|
|
2915
|
+
session: S.Optional(S.String({ short: "s", description: "Session name" }))
|
|
1545
2916
|
});
|
|
1546
|
-
var readScreen =
|
|
2917
|
+
var readScreen = defineCommand({
|
|
1547
2918
|
name: "read-screen",
|
|
1548
2919
|
description: "Read the current visible terminal screen",
|
|
1549
2920
|
scope: ["cli", "mcp", "sdk"],
|
|
@@ -1561,13 +2932,12 @@ var readScreen = defineCommand9({
|
|
|
1561
2932
|
});
|
|
1562
2933
|
|
|
1563
2934
|
// src/commands/resize.ts
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
session: S10.Optional(S10.String({ short: "s", description: "Session name" }))
|
|
2935
|
+
var params10 = S.Object({
|
|
2936
|
+
cols: S.Number({ description: "Terminal width in columns" }),
|
|
2937
|
+
rows: S.Number({ description: "Terminal height in rows" }),
|
|
2938
|
+
session: S.Optional(S.String({ short: "s", description: "Session name" }))
|
|
1569
2939
|
});
|
|
1570
|
-
var resize =
|
|
2940
|
+
var resize = defineCommand({
|
|
1571
2941
|
name: "resize",
|
|
1572
2942
|
description: "Resize an active terminal session",
|
|
1573
2943
|
scope: ["cli", "mcp", "sdk"],
|
|
@@ -1579,16 +2949,776 @@ var resize = defineCommand10({
|
|
|
1579
2949
|
}
|
|
1580
2950
|
});
|
|
1581
2951
|
|
|
2952
|
+
// ../terminal-png/src/index.ts
|
|
2953
|
+
import { writeFile } from "node:fs/promises";
|
|
2954
|
+
|
|
2955
|
+
// ../terminal-png/src/ansi-parser.ts
|
|
2956
|
+
var ESC2 = "\x1B";
|
|
2957
|
+
function createDefaultStyle() {
|
|
2958
|
+
return {
|
|
2959
|
+
fg: null,
|
|
2960
|
+
bg: null,
|
|
2961
|
+
bold: false,
|
|
2962
|
+
italic: false,
|
|
2963
|
+
underline: false,
|
|
2964
|
+
strikethrough: false,
|
|
2965
|
+
dim: false
|
|
2966
|
+
};
|
|
2967
|
+
}
|
|
2968
|
+
function cloneStyle(style) {
|
|
2969
|
+
return { ...style };
|
|
2970
|
+
}
|
|
2971
|
+
function stylesEqual(left, right) {
|
|
2972
|
+
return left.bold === right.bold && left.italic === right.italic && left.underline === right.underline && left.strikethrough === right.strikethrough && left.dim === right.dim && colorsEqual(left.fg, right.fg) && colorsEqual(left.bg, right.bg);
|
|
2973
|
+
}
|
|
2974
|
+
function colorsEqual(left, right) {
|
|
2975
|
+
if (left === right) {
|
|
2976
|
+
return true;
|
|
2977
|
+
}
|
|
2978
|
+
if (!left || !right || left.type !== right.type) {
|
|
2979
|
+
return false;
|
|
2980
|
+
}
|
|
2981
|
+
if (left.type === "rgb" && right.type === "rgb") {
|
|
2982
|
+
return left.r === right.r && left.g === right.g && left.b === right.b;
|
|
2983
|
+
}
|
|
2984
|
+
if ((left.type === "ansi4" || left.type === "ansi8") && left.type === right.type) {
|
|
2985
|
+
return left.index === right.index;
|
|
2986
|
+
}
|
|
2987
|
+
return false;
|
|
2988
|
+
}
|
|
2989
|
+
function pushRun(runs, style, text) {
|
|
2990
|
+
if (text.length === 0) {
|
|
2991
|
+
return;
|
|
2992
|
+
}
|
|
2993
|
+
const previous = runs.at(-1);
|
|
2994
|
+
if (previous && text !== "\n" && previous.text !== "\n" && stylesEqual(previous, style)) {
|
|
2995
|
+
previous.text += text;
|
|
2996
|
+
return;
|
|
2997
|
+
}
|
|
2998
|
+
runs.push({
|
|
2999
|
+
text,
|
|
3000
|
+
fg: style.fg,
|
|
3001
|
+
bg: style.bg,
|
|
3002
|
+
bold: style.bold,
|
|
3003
|
+
italic: style.italic,
|
|
3004
|
+
underline: style.underline,
|
|
3005
|
+
strikethrough: style.strikethrough,
|
|
3006
|
+
dim: style.dim
|
|
3007
|
+
});
|
|
3008
|
+
}
|
|
3009
|
+
function parseCsi(input, start) {
|
|
3010
|
+
let index = start + 2;
|
|
3011
|
+
while (index < input.length) {
|
|
3012
|
+
const code = input.charCodeAt(index);
|
|
3013
|
+
if (code >= 64 && code <= 126) {
|
|
3014
|
+
return {
|
|
3015
|
+
end: index + 1,
|
|
3016
|
+
final: input[index],
|
|
3017
|
+
params: input.slice(start + 2, index)
|
|
3018
|
+
};
|
|
3019
|
+
}
|
|
3020
|
+
index += 1;
|
|
3021
|
+
}
|
|
3022
|
+
return {
|
|
3023
|
+
end: input.length,
|
|
3024
|
+
final: null,
|
|
3025
|
+
params: input.slice(start + 2)
|
|
3026
|
+
};
|
|
3027
|
+
}
|
|
3028
|
+
function toInteger(value) {
|
|
3029
|
+
if (!value || value.length === 0) {
|
|
3030
|
+
return null;
|
|
3031
|
+
}
|
|
3032
|
+
for (const char of value) {
|
|
3033
|
+
if (char < "0" || char > "9") {
|
|
3034
|
+
return null;
|
|
3035
|
+
}
|
|
3036
|
+
}
|
|
3037
|
+
return Number.parseInt(value, 10);
|
|
3038
|
+
}
|
|
3039
|
+
function clampByte(value) {
|
|
3040
|
+
if (value < 0) {
|
|
3041
|
+
return 0;
|
|
3042
|
+
}
|
|
3043
|
+
if (value > 255) {
|
|
3044
|
+
return 255;
|
|
3045
|
+
}
|
|
3046
|
+
return value;
|
|
3047
|
+
}
|
|
3048
|
+
function applyExtendedColor(params17, start) {
|
|
3049
|
+
const mode = params17[start];
|
|
3050
|
+
if (mode === 5) {
|
|
3051
|
+
const index = params17[start + 1];
|
|
3052
|
+
if (index === void 0) {
|
|
3053
|
+
return null;
|
|
3054
|
+
}
|
|
3055
|
+
return {
|
|
3056
|
+
color: { type: "ansi8", index: clampByte(index) },
|
|
3057
|
+
consumed: 2
|
|
3058
|
+
};
|
|
3059
|
+
}
|
|
3060
|
+
if (mode === 2) {
|
|
3061
|
+
const r = params17[start + 1];
|
|
3062
|
+
const g = params17[start + 2];
|
|
3063
|
+
const b = params17[start + 3];
|
|
3064
|
+
if (r === void 0 || g === void 0 || b === void 0) {
|
|
3065
|
+
return null;
|
|
3066
|
+
}
|
|
3067
|
+
return {
|
|
3068
|
+
color: { type: "rgb", r: clampByte(r), g: clampByte(g), b: clampByte(b) },
|
|
3069
|
+
consumed: 4
|
|
3070
|
+
};
|
|
3071
|
+
}
|
|
3072
|
+
return null;
|
|
3073
|
+
}
|
|
3074
|
+
function applySgr(style, paramsText) {
|
|
3075
|
+
const nextStyle = cloneStyle(style);
|
|
3076
|
+
const rawParams = paramsText.length === 0 ? ["0"] : paramsText.split(";");
|
|
3077
|
+
const params17 = [];
|
|
3078
|
+
for (const rawParam of rawParams) {
|
|
3079
|
+
const value = toInteger(rawParam);
|
|
3080
|
+
if (value === null) {
|
|
3081
|
+
return nextStyle;
|
|
3082
|
+
}
|
|
3083
|
+
params17.push(value);
|
|
3084
|
+
}
|
|
3085
|
+
for (let index = 0; index < params17.length; index += 1) {
|
|
3086
|
+
const value = params17[index];
|
|
3087
|
+
if (value === 0) {
|
|
3088
|
+
Object.assign(nextStyle, createDefaultStyle());
|
|
3089
|
+
continue;
|
|
3090
|
+
}
|
|
3091
|
+
if (value === 1) {
|
|
3092
|
+
nextStyle.bold = true;
|
|
3093
|
+
continue;
|
|
3094
|
+
}
|
|
3095
|
+
if (value === 2) {
|
|
3096
|
+
nextStyle.dim = true;
|
|
3097
|
+
continue;
|
|
3098
|
+
}
|
|
3099
|
+
if (value === 22) {
|
|
3100
|
+
nextStyle.bold = false;
|
|
3101
|
+
nextStyle.dim = false;
|
|
3102
|
+
continue;
|
|
3103
|
+
}
|
|
3104
|
+
if (value === 3) {
|
|
3105
|
+
nextStyle.italic = true;
|
|
3106
|
+
continue;
|
|
3107
|
+
}
|
|
3108
|
+
if (value === 23) {
|
|
3109
|
+
nextStyle.italic = false;
|
|
3110
|
+
continue;
|
|
3111
|
+
}
|
|
3112
|
+
if (value === 4) {
|
|
3113
|
+
nextStyle.underline = true;
|
|
3114
|
+
continue;
|
|
3115
|
+
}
|
|
3116
|
+
if (value === 24) {
|
|
3117
|
+
nextStyle.underline = false;
|
|
3118
|
+
continue;
|
|
3119
|
+
}
|
|
3120
|
+
if (value === 9) {
|
|
3121
|
+
nextStyle.strikethrough = true;
|
|
3122
|
+
continue;
|
|
3123
|
+
}
|
|
3124
|
+
if (value === 29) {
|
|
3125
|
+
nextStyle.strikethrough = false;
|
|
3126
|
+
continue;
|
|
3127
|
+
}
|
|
3128
|
+
if (value === 39) {
|
|
3129
|
+
nextStyle.fg = null;
|
|
3130
|
+
continue;
|
|
3131
|
+
}
|
|
3132
|
+
if (value === 49) {
|
|
3133
|
+
nextStyle.bg = null;
|
|
3134
|
+
continue;
|
|
3135
|
+
}
|
|
3136
|
+
if (value >= 30 && value <= 37) {
|
|
3137
|
+
nextStyle.fg = { type: "ansi4", index: value - 30 };
|
|
3138
|
+
continue;
|
|
3139
|
+
}
|
|
3140
|
+
if (value >= 90 && value <= 97) {
|
|
3141
|
+
nextStyle.fg = { type: "ansi4", index: value - 90 + 8 };
|
|
3142
|
+
continue;
|
|
3143
|
+
}
|
|
3144
|
+
if (value >= 40 && value <= 47) {
|
|
3145
|
+
nextStyle.bg = { type: "ansi4", index: value - 40 };
|
|
3146
|
+
continue;
|
|
3147
|
+
}
|
|
3148
|
+
if (value >= 100 && value <= 107) {
|
|
3149
|
+
nextStyle.bg = { type: "ansi4", index: value - 100 + 8 };
|
|
3150
|
+
continue;
|
|
3151
|
+
}
|
|
3152
|
+
if (value === 38 || value === 48) {
|
|
3153
|
+
const extended = applyExtendedColor(params17, index + 1);
|
|
3154
|
+
if (!extended) {
|
|
3155
|
+
continue;
|
|
3156
|
+
}
|
|
3157
|
+
if (value === 38) {
|
|
3158
|
+
nextStyle.fg = extended.color;
|
|
3159
|
+
} else {
|
|
3160
|
+
nextStyle.bg = extended.color;
|
|
3161
|
+
}
|
|
3162
|
+
index += extended.consumed;
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
return nextStyle;
|
|
3166
|
+
}
|
|
3167
|
+
function parseAnsi(input) {
|
|
3168
|
+
const runs = [];
|
|
3169
|
+
let style = createDefaultStyle();
|
|
3170
|
+
let textStart = 0;
|
|
3171
|
+
let index = 0;
|
|
3172
|
+
while (index < input.length) {
|
|
3173
|
+
const char = input[index];
|
|
3174
|
+
if (char === "\n") {
|
|
3175
|
+
pushRun(runs, style, input.slice(textStart, index));
|
|
3176
|
+
pushRun(runs, style, "\n");
|
|
3177
|
+
index += 1;
|
|
3178
|
+
textStart = index;
|
|
3179
|
+
continue;
|
|
3180
|
+
}
|
|
3181
|
+
if (char === ESC2 && input[index + 1] === "[") {
|
|
3182
|
+
pushRun(runs, style, input.slice(textStart, index));
|
|
3183
|
+
const sequence = parseCsi(input, index);
|
|
3184
|
+
if (sequence.final === "m") {
|
|
3185
|
+
style = applySgr(style, sequence.params);
|
|
3186
|
+
}
|
|
3187
|
+
index = sequence.end;
|
|
3188
|
+
textStart = index;
|
|
3189
|
+
continue;
|
|
3190
|
+
}
|
|
3191
|
+
index += 1;
|
|
3192
|
+
}
|
|
3193
|
+
pushRun(runs, style, input.slice(textStart));
|
|
3194
|
+
return runs;
|
|
3195
|
+
}
|
|
3196
|
+
|
|
3197
|
+
// ../terminal-png/src/png-renderer.ts
|
|
3198
|
+
import { Resvg } from "@resvg/resvg-js";
|
|
3199
|
+
|
|
3200
|
+
// ../terminal-png/src/font.ts
|
|
3201
|
+
import { readFileSync } from "node:fs";
|
|
3202
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
3203
|
+
import { dirname as dirname2, join as join2 } from "node:path";
|
|
3204
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
3205
|
+
var require2 = createRequire2(import.meta.url);
|
|
3206
|
+
var fontPackageRoot = dirname2(require2.resolve("jetbrains-mono/package.json"));
|
|
3207
|
+
var webfontRoot = join2(fontPackageRoot, "fonts/webfonts");
|
|
3208
|
+
function readWebfontBase64(filename) {
|
|
3209
|
+
return readFileSync(join2(webfontRoot, filename)).toString("base64");
|
|
3210
|
+
}
|
|
3211
|
+
function resolveAssetPath(filename) {
|
|
3212
|
+
return fileURLToPath2(new URL(`../assets/${filename}`, import.meta.url));
|
|
3213
|
+
}
|
|
3214
|
+
function createFontFace(base64, weight, style) {
|
|
3215
|
+
return `@font-face {
|
|
3216
|
+
font-family: 'JetBrains Mono';
|
|
3217
|
+
font-style: ${style};
|
|
3218
|
+
font-weight: ${weight};
|
|
3219
|
+
src: url('data:font/woff2;base64,${base64}') format('woff2');
|
|
3220
|
+
}`;
|
|
3221
|
+
}
|
|
3222
|
+
var JETBRAINS_MONO_BASE64 = readWebfontBase64("JetBrainsMono-Regular.woff2");
|
|
3223
|
+
var JETBRAINS_MONO_FONT_FILES = [
|
|
3224
|
+
resolveAssetPath("jetbrains-mono-400-normal.ttf"),
|
|
3225
|
+
resolveAssetPath("jetbrains-mono-700-normal.ttf"),
|
|
3226
|
+
resolveAssetPath("jetbrains-mono-400-italic.ttf"),
|
|
3227
|
+
resolveAssetPath("jetbrains-mono-700-italic.ttf")
|
|
3228
|
+
];
|
|
3229
|
+
var JETBRAINS_MONO_TTF_PATH = JETBRAINS_MONO_FONT_FILES[0];
|
|
3230
|
+
var FONT_FACE_CSS = [
|
|
3231
|
+
createFontFace(JETBRAINS_MONO_BASE64, 400, "normal"),
|
|
3232
|
+
createFontFace(readWebfontBase64("JetBrainsMono-Bold.woff2"), 700, "normal"),
|
|
3233
|
+
createFontFace(readWebfontBase64("JetBrainsMono-Italic.woff2"), 400, "italic"),
|
|
3234
|
+
createFontFace(readWebfontBase64("JetBrainsMono-BoldItalic.woff2"), 700, "italic")
|
|
3235
|
+
].join("\n");
|
|
3236
|
+
|
|
3237
|
+
// ../terminal-png/src/png-renderer.ts
|
|
3238
|
+
function renderPng(svg) {
|
|
3239
|
+
const resvg = new Resvg(svg, {
|
|
3240
|
+
font: {
|
|
3241
|
+
defaultFontFamily: "JetBrains Mono",
|
|
3242
|
+
fontFiles: [...JETBRAINS_MONO_FONT_FILES],
|
|
3243
|
+
loadSystemFonts: false,
|
|
3244
|
+
monospaceFamily: "JetBrains Mono"
|
|
3245
|
+
},
|
|
3246
|
+
fitTo: {
|
|
3247
|
+
mode: "zoom",
|
|
3248
|
+
value: 4
|
|
3249
|
+
}
|
|
3250
|
+
});
|
|
3251
|
+
const png = resvg.render();
|
|
3252
|
+
return Buffer.from(png.asPng());
|
|
3253
|
+
}
|
|
3254
|
+
|
|
3255
|
+
// ../terminal-png/src/svg-renderer.ts
|
|
3256
|
+
var ANSI_16_PALETTE = [
|
|
3257
|
+
"#282a2e",
|
|
3258
|
+
"#D74E6F",
|
|
3259
|
+
"#31BB71",
|
|
3260
|
+
"#D3E561",
|
|
3261
|
+
"#8056FF",
|
|
3262
|
+
"#ED61D7",
|
|
3263
|
+
"#04D7D7",
|
|
3264
|
+
"#C5C8C6",
|
|
3265
|
+
"#4B4B4B",
|
|
3266
|
+
"#FE5F86",
|
|
3267
|
+
"#00D787",
|
|
3268
|
+
"#EBFF71",
|
|
3269
|
+
"#8F69FF",
|
|
3270
|
+
"#FF7AEA",
|
|
3271
|
+
"#00FEFE",
|
|
3272
|
+
"#FFFFFF"
|
|
3273
|
+
];
|
|
3274
|
+
var XTERM_256_PALETTE = [
|
|
3275
|
+
"#000000",
|
|
3276
|
+
"#800000",
|
|
3277
|
+
"#008000",
|
|
3278
|
+
"#808000",
|
|
3279
|
+
"#000080",
|
|
3280
|
+
"#800080",
|
|
3281
|
+
"#008080",
|
|
3282
|
+
"#c0c0c0",
|
|
3283
|
+
"#808080",
|
|
3284
|
+
"#ff0000",
|
|
3285
|
+
"#00ff00",
|
|
3286
|
+
"#ffff00",
|
|
3287
|
+
"#0000ff",
|
|
3288
|
+
"#ff00ff",
|
|
3289
|
+
"#00ffff",
|
|
3290
|
+
"#ffffff",
|
|
3291
|
+
"#000000",
|
|
3292
|
+
"#00005f",
|
|
3293
|
+
"#000087",
|
|
3294
|
+
"#0000af",
|
|
3295
|
+
"#0000d7",
|
|
3296
|
+
"#0000ff",
|
|
3297
|
+
"#005f00",
|
|
3298
|
+
"#005f5f",
|
|
3299
|
+
"#005f87",
|
|
3300
|
+
"#005faf",
|
|
3301
|
+
"#005fd7",
|
|
3302
|
+
"#005fff",
|
|
3303
|
+
"#008700",
|
|
3304
|
+
"#00875f",
|
|
3305
|
+
"#008787",
|
|
3306
|
+
"#0087af",
|
|
3307
|
+
"#0087d7",
|
|
3308
|
+
"#0087ff",
|
|
3309
|
+
"#00af00",
|
|
3310
|
+
"#00af5f",
|
|
3311
|
+
"#00af87",
|
|
3312
|
+
"#00afaf",
|
|
3313
|
+
"#00afd7",
|
|
3314
|
+
"#00afff",
|
|
3315
|
+
"#00d700",
|
|
3316
|
+
"#00d75f",
|
|
3317
|
+
"#00d787",
|
|
3318
|
+
"#00d7af",
|
|
3319
|
+
"#00d7d7",
|
|
3320
|
+
"#00d7ff",
|
|
3321
|
+
"#00ff00",
|
|
3322
|
+
"#00ff5f",
|
|
3323
|
+
"#00ff87",
|
|
3324
|
+
"#00ffaf",
|
|
3325
|
+
"#00ffd7",
|
|
3326
|
+
"#00ffff",
|
|
3327
|
+
"#5f0000",
|
|
3328
|
+
"#5f005f",
|
|
3329
|
+
"#5f0087",
|
|
3330
|
+
"#5f00af",
|
|
3331
|
+
"#5f00d7",
|
|
3332
|
+
"#5f00ff",
|
|
3333
|
+
"#5f5f00",
|
|
3334
|
+
"#5f5f5f",
|
|
3335
|
+
"#5f5f87",
|
|
3336
|
+
"#5f5faf",
|
|
3337
|
+
"#5f5fd7",
|
|
3338
|
+
"#5f5fff",
|
|
3339
|
+
"#5f8700",
|
|
3340
|
+
"#5f875f",
|
|
3341
|
+
"#5f8787",
|
|
3342
|
+
"#5f87af",
|
|
3343
|
+
"#5f87d7",
|
|
3344
|
+
"#5f87ff",
|
|
3345
|
+
"#5faf00",
|
|
3346
|
+
"#5faf5f",
|
|
3347
|
+
"#5faf87",
|
|
3348
|
+
"#5fafaf",
|
|
3349
|
+
"#5fafd7",
|
|
3350
|
+
"#5fafff",
|
|
3351
|
+
"#5fd700",
|
|
3352
|
+
"#5fd75f",
|
|
3353
|
+
"#5fd787",
|
|
3354
|
+
"#5fd7af",
|
|
3355
|
+
"#5fd7d7",
|
|
3356
|
+
"#5fd7ff",
|
|
3357
|
+
"#5fff00",
|
|
3358
|
+
"#5fff5f",
|
|
3359
|
+
"#5fff87",
|
|
3360
|
+
"#5fffaf",
|
|
3361
|
+
"#5fffd7",
|
|
3362
|
+
"#5fffff",
|
|
3363
|
+
"#870000",
|
|
3364
|
+
"#87005f",
|
|
3365
|
+
"#870087",
|
|
3366
|
+
"#8700af",
|
|
3367
|
+
"#8700d7",
|
|
3368
|
+
"#8700ff",
|
|
3369
|
+
"#875f00",
|
|
3370
|
+
"#875f5f",
|
|
3371
|
+
"#875f87",
|
|
3372
|
+
"#875faf",
|
|
3373
|
+
"#875fd7",
|
|
3374
|
+
"#875fff",
|
|
3375
|
+
"#878700",
|
|
3376
|
+
"#87875f",
|
|
3377
|
+
"#878787",
|
|
3378
|
+
"#8787af",
|
|
3379
|
+
"#8787d7",
|
|
3380
|
+
"#8787ff",
|
|
3381
|
+
"#87af00",
|
|
3382
|
+
"#87af5f",
|
|
3383
|
+
"#87af87",
|
|
3384
|
+
"#87afaf",
|
|
3385
|
+
"#87afd7",
|
|
3386
|
+
"#87afff",
|
|
3387
|
+
"#87d700",
|
|
3388
|
+
"#87d75f",
|
|
3389
|
+
"#87d787",
|
|
3390
|
+
"#87d7af",
|
|
3391
|
+
"#87d7d7",
|
|
3392
|
+
"#87d7ff",
|
|
3393
|
+
"#87ff00",
|
|
3394
|
+
"#87ff5f",
|
|
3395
|
+
"#87ff87",
|
|
3396
|
+
"#87ffaf",
|
|
3397
|
+
"#87ffd7",
|
|
3398
|
+
"#87ffff",
|
|
3399
|
+
"#af0000",
|
|
3400
|
+
"#af005f",
|
|
3401
|
+
"#af0087",
|
|
3402
|
+
"#af00af",
|
|
3403
|
+
"#af00d7",
|
|
3404
|
+
"#af00ff",
|
|
3405
|
+
"#af5f00",
|
|
3406
|
+
"#af5f5f",
|
|
3407
|
+
"#af5f87",
|
|
3408
|
+
"#af5faf",
|
|
3409
|
+
"#af5fd7",
|
|
3410
|
+
"#af5fff",
|
|
3411
|
+
"#af8700",
|
|
3412
|
+
"#af875f",
|
|
3413
|
+
"#af8787",
|
|
3414
|
+
"#af87af",
|
|
3415
|
+
"#af87d7",
|
|
3416
|
+
"#af87ff",
|
|
3417
|
+
"#afaf00",
|
|
3418
|
+
"#afaf5f",
|
|
3419
|
+
"#afaf87",
|
|
3420
|
+
"#afafaf",
|
|
3421
|
+
"#afafd7",
|
|
3422
|
+
"#afafff",
|
|
3423
|
+
"#afd700",
|
|
3424
|
+
"#afd75f",
|
|
3425
|
+
"#afd787",
|
|
3426
|
+
"#afd7af",
|
|
3427
|
+
"#afd7d7",
|
|
3428
|
+
"#afd7ff",
|
|
3429
|
+
"#afff00",
|
|
3430
|
+
"#afff5f",
|
|
3431
|
+
"#afff87",
|
|
3432
|
+
"#afffaf",
|
|
3433
|
+
"#afffd7",
|
|
3434
|
+
"#afffff",
|
|
3435
|
+
"#d70000",
|
|
3436
|
+
"#d7005f",
|
|
3437
|
+
"#d70087",
|
|
3438
|
+
"#d700af",
|
|
3439
|
+
"#d700d7",
|
|
3440
|
+
"#d700ff",
|
|
3441
|
+
"#d75f00",
|
|
3442
|
+
"#d75f5f",
|
|
3443
|
+
"#d75f87",
|
|
3444
|
+
"#d75faf",
|
|
3445
|
+
"#d75fd7",
|
|
3446
|
+
"#d75fff",
|
|
3447
|
+
"#d78700",
|
|
3448
|
+
"#d7875f",
|
|
3449
|
+
"#d78787",
|
|
3450
|
+
"#d787af",
|
|
3451
|
+
"#d787d7",
|
|
3452
|
+
"#d787ff",
|
|
3453
|
+
"#d7af00",
|
|
3454
|
+
"#d7af5f",
|
|
3455
|
+
"#d7af87",
|
|
3456
|
+
"#d7afaf",
|
|
3457
|
+
"#d7afd7",
|
|
3458
|
+
"#d7afff",
|
|
3459
|
+
"#d7d700",
|
|
3460
|
+
"#d7d75f",
|
|
3461
|
+
"#d7d787",
|
|
3462
|
+
"#d7d7af",
|
|
3463
|
+
"#d7d7d7",
|
|
3464
|
+
"#d7d7ff",
|
|
3465
|
+
"#d7ff00",
|
|
3466
|
+
"#d7ff5f",
|
|
3467
|
+
"#d7ff87",
|
|
3468
|
+
"#d7ffaf",
|
|
3469
|
+
"#d7ffd7",
|
|
3470
|
+
"#d7ffff",
|
|
3471
|
+
"#ff0000",
|
|
3472
|
+
"#ff005f",
|
|
3473
|
+
"#ff0087",
|
|
3474
|
+
"#ff00af",
|
|
3475
|
+
"#ff00d7",
|
|
3476
|
+
"#ff00ff",
|
|
3477
|
+
"#ff5f00",
|
|
3478
|
+
"#ff5f5f",
|
|
3479
|
+
"#ff5f87",
|
|
3480
|
+
"#ff5faf",
|
|
3481
|
+
"#ff5fd7",
|
|
3482
|
+
"#ff5fff",
|
|
3483
|
+
"#ff8700",
|
|
3484
|
+
"#ff875f",
|
|
3485
|
+
"#ff8787",
|
|
3486
|
+
"#ff87af",
|
|
3487
|
+
"#ff87d7",
|
|
3488
|
+
"#ff87ff",
|
|
3489
|
+
"#ffaf00",
|
|
3490
|
+
"#ffaf5f",
|
|
3491
|
+
"#ffaf87",
|
|
3492
|
+
"#ffafaf",
|
|
3493
|
+
"#ffafd7",
|
|
3494
|
+
"#ffafff",
|
|
3495
|
+
"#ffd700",
|
|
3496
|
+
"#ffd75f",
|
|
3497
|
+
"#ffd787",
|
|
3498
|
+
"#ffd7af",
|
|
3499
|
+
"#ffd7d7",
|
|
3500
|
+
"#ffd7ff",
|
|
3501
|
+
"#ffff00",
|
|
3502
|
+
"#ffff5f",
|
|
3503
|
+
"#ffff87",
|
|
3504
|
+
"#ffffaf",
|
|
3505
|
+
"#ffffd7",
|
|
3506
|
+
"#ffffff",
|
|
3507
|
+
"#080808",
|
|
3508
|
+
"#121212",
|
|
3509
|
+
"#1c1c1c",
|
|
3510
|
+
"#262626",
|
|
3511
|
+
"#303030",
|
|
3512
|
+
"#3a3a3a",
|
|
3513
|
+
"#444444",
|
|
3514
|
+
"#4e4e4e",
|
|
3515
|
+
"#585858",
|
|
3516
|
+
"#606060",
|
|
3517
|
+
"#666666",
|
|
3518
|
+
"#767676",
|
|
3519
|
+
"#808080",
|
|
3520
|
+
"#8a8a8a",
|
|
3521
|
+
"#949494",
|
|
3522
|
+
"#9e9e9e",
|
|
3523
|
+
"#a8a8a8",
|
|
3524
|
+
"#b2b2b2",
|
|
3525
|
+
"#bcbcbc",
|
|
3526
|
+
"#c6c6c6",
|
|
3527
|
+
"#d0d0d0",
|
|
3528
|
+
"#dadada",
|
|
3529
|
+
"#e4e4e4",
|
|
3530
|
+
"#eeeeee"
|
|
3531
|
+
];
|
|
3532
|
+
var BACKGROUND = "#171717";
|
|
3533
|
+
var DEFAULT_FOREGROUND = "#c4c4c4";
|
|
3534
|
+
var FONT_FAMILY = "JetBrains Mono";
|
|
3535
|
+
var FONT_SIZE = 14;
|
|
3536
|
+
var LINE_HEIGHT = 1.2;
|
|
3537
|
+
var CHARACTER_WIDTH = 8.412666666666667;
|
|
3538
|
+
var TEXT_BOTTOM_PADDING = 11.6;
|
|
3539
|
+
var DEFAULT_PADDING = {
|
|
3540
|
+
top: 20,
|
|
3541
|
+
right: 40,
|
|
3542
|
+
bottom: 20,
|
|
3543
|
+
left: 20
|
|
3544
|
+
};
|
|
3545
|
+
var WINDOW_BAR_HEIGHT = 15;
|
|
3546
|
+
function renderSvg(runs, options = {}) {
|
|
3547
|
+
const padding = options.padding === void 0 ? DEFAULT_PADDING : {
|
|
3548
|
+
top: options.padding,
|
|
3549
|
+
right: options.padding,
|
|
3550
|
+
bottom: options.padding,
|
|
3551
|
+
left: options.padding
|
|
3552
|
+
};
|
|
3553
|
+
const showWindow = options.window ?? true;
|
|
3554
|
+
const titleBarHeight = showWindow ? WINDOW_BAR_HEIGHT : 0;
|
|
3555
|
+
const textStartX = padding.left;
|
|
3556
|
+
const lineHeightPx = FONT_SIZE * LINE_HEIGHT;
|
|
3557
|
+
const textStartY = titleBarHeight + padding.top + lineHeightPx;
|
|
3558
|
+
const lines = splitIntoLines(runs);
|
|
3559
|
+
const contentWidth = measureLines(lines);
|
|
3560
|
+
const width = padding.left + contentWidth + padding.right;
|
|
3561
|
+
const height = titleBarHeight + padding.top + lines.length * lineHeightPx + padding.bottom + TEXT_BOTTOM_PADDING;
|
|
3562
|
+
const svgWidth = formatNumber(width);
|
|
3563
|
+
const svgHeight = formatNumber(height);
|
|
3564
|
+
const viewBox = `0 0 ${svgWidth} ${svgHeight}`;
|
|
3565
|
+
const textElements = renderLines(lines, textStartX, textStartY, lineHeightPx);
|
|
3566
|
+
return [
|
|
3567
|
+
`<svg xmlns="http://www.w3.org/2000/svg" width="${svgWidth}" height="${svgHeight}" viewBox="${viewBox}">`,
|
|
3568
|
+
"<defs>",
|
|
3569
|
+
"<style><![CDATA[",
|
|
3570
|
+
FONT_FACE_CSS,
|
|
3571
|
+
"]]></style>",
|
|
3572
|
+
"</defs>",
|
|
3573
|
+
`<rect x="0" y="0" width="${svgWidth}" height="${svgHeight}" fill="${BACKGROUND}" />`,
|
|
3574
|
+
showWindow ? renderWindowControls() : "",
|
|
3575
|
+
`<g font-family="${FONT_FAMILY}" font-size="${formatNumber(FONT_SIZE)}px" fill="${DEFAULT_FOREGROUND}">`,
|
|
3576
|
+
textElements,
|
|
3577
|
+
"</g>",
|
|
3578
|
+
"</svg>"
|
|
3579
|
+
].join("");
|
|
3580
|
+
}
|
|
3581
|
+
function splitIntoLines(runs) {
|
|
3582
|
+
const lines = [[]];
|
|
3583
|
+
for (const run of runs) {
|
|
3584
|
+
if (run.text === "\n") {
|
|
3585
|
+
lines.push([]);
|
|
3586
|
+
continue;
|
|
3587
|
+
}
|
|
3588
|
+
lines[lines.length - 1]?.push(run);
|
|
3589
|
+
}
|
|
3590
|
+
return lines;
|
|
3591
|
+
}
|
|
3592
|
+
function measureLines(lines) {
|
|
3593
|
+
return Math.max(
|
|
3594
|
+
...lines.map((line) => line.reduce((width, run) => width + displayWidth(run.text) * CHARACTER_WIDTH, 0)),
|
|
3595
|
+
0
|
|
3596
|
+
);
|
|
3597
|
+
}
|
|
3598
|
+
function displayWidth(text) {
|
|
3599
|
+
const segmenter = new Intl.Segmenter();
|
|
3600
|
+
let width = 0;
|
|
3601
|
+
for (const { segment } of segmenter.segment(text)) {
|
|
3602
|
+
const cp = segment.codePointAt(0);
|
|
3603
|
+
width += cp !== void 0 && isWideCodePoint(cp) ? 2 : 1;
|
|
3604
|
+
}
|
|
3605
|
+
return width;
|
|
3606
|
+
}
|
|
3607
|
+
function isWideCodePoint(cp) {
|
|
3608
|
+
return cp >= 4352 && cp <= 4447 || // Hangul Jamo
|
|
3609
|
+
cp === 9001 || cp === 9002 || // Angle brackets
|
|
3610
|
+
cp >= 11904 && cp <= 12350 || // CJK Radicals, Kangxi
|
|
3611
|
+
cp >= 12353 && cp <= 13247 || // Hiragana, Katakana, CJK symbols
|
|
3612
|
+
cp >= 13312 && cp <= 19903 || // CJK Extension A
|
|
3613
|
+
cp >= 19968 && cp <= 42191 || // CJK Unified Ideographs
|
|
3614
|
+
cp >= 43360 && cp <= 43391 || // Hangul Jamo Extended-A
|
|
3615
|
+
cp >= 44032 && cp <= 55215 || // Hangul Syllables
|
|
3616
|
+
cp >= 63744 && cp <= 64255 || // CJK Compatibility Ideographs
|
|
3617
|
+
cp >= 65040 && cp <= 65049 || // Vertical Forms
|
|
3618
|
+
cp >= 65072 && cp <= 65135 || // CJK Compatibility Forms
|
|
3619
|
+
cp >= 65280 && cp <= 65376 || // Fullwidth Latin, Halfwidth Katakana
|
|
3620
|
+
cp >= 65504 && cp <= 65510 || // Fullwidth Signs
|
|
3621
|
+
cp >= 110592 && cp <= 110847 || // Kana Supplement
|
|
3622
|
+
cp >= 126980 && cp <= 126980 || // Mahjong tile
|
|
3623
|
+
cp >= 127183 && cp <= 127183 || // Playing card black joker
|
|
3624
|
+
cp >= 127488 && cp <= 131069 || // Enclosed CJK + Emoji
|
|
3625
|
+
cp >= 131072 && cp <= 196605 || // CJK Extension B–F
|
|
3626
|
+
cp >= 196608 && cp <= 262141;
|
|
3627
|
+
}
|
|
3628
|
+
function renderLines(lines, textStartX, textStartY, lineHeightPx) {
|
|
3629
|
+
return lines.map((line, index) => {
|
|
3630
|
+
const y = formatNumber(textStartY + index * lineHeightPx);
|
|
3631
|
+
if (line.length === 0) {
|
|
3632
|
+
return `<text x="${formatNumber(textStartX)}" y="${y}" xml:space="preserve"/>`;
|
|
3633
|
+
}
|
|
3634
|
+
return [
|
|
3635
|
+
`<text x="${formatNumber(textStartX)}" y="${y}" xml:space="preserve">`,
|
|
3636
|
+
line.map(renderRun).join(""),
|
|
3637
|
+
"</text>"
|
|
3638
|
+
].join("");
|
|
3639
|
+
}).join("");
|
|
3640
|
+
}
|
|
3641
|
+
function renderRun(run) {
|
|
3642
|
+
const attributes = ['xml:space="preserve"'];
|
|
3643
|
+
const color = resolveColor(run.fg);
|
|
3644
|
+
const textDecorations = [];
|
|
3645
|
+
if (color !== DEFAULT_FOREGROUND) {
|
|
3646
|
+
attributes.push(`fill="${escapeXmlAttribute(color)}"`);
|
|
3647
|
+
}
|
|
3648
|
+
if (run.bold) {
|
|
3649
|
+
attributes.push('font-weight="bold"');
|
|
3650
|
+
}
|
|
3651
|
+
if (run.italic) {
|
|
3652
|
+
attributes.push('font-style="italic"');
|
|
3653
|
+
}
|
|
3654
|
+
if (run.underline) {
|
|
3655
|
+
textDecorations.push("underline");
|
|
3656
|
+
}
|
|
3657
|
+
if (run.strikethrough) {
|
|
3658
|
+
textDecorations.push("line-through");
|
|
3659
|
+
}
|
|
3660
|
+
if (textDecorations.length > 0) {
|
|
3661
|
+
attributes.push(`text-decoration="${textDecorations.join(" ")}"`);
|
|
3662
|
+
}
|
|
3663
|
+
if (run.dim) {
|
|
3664
|
+
attributes.push('opacity="0.7"');
|
|
3665
|
+
}
|
|
3666
|
+
return `<tspan ${attributes.join(" ")}>${escapeXmlText(run.text)}</tspan>`;
|
|
3667
|
+
}
|
|
3668
|
+
function renderWindowControls() {
|
|
3669
|
+
return [
|
|
3670
|
+
'<circle cx="13.5" cy="12" r="5.5" fill="#FF5A54" />',
|
|
3671
|
+
'<circle cx="32.5" cy="12" r="5.5" fill="#E6BF29" />',
|
|
3672
|
+
'<circle cx="51.5" cy="12" r="5.5" fill="#52C12B" />'
|
|
3673
|
+
].join("");
|
|
3674
|
+
}
|
|
3675
|
+
function resolveColor(color) {
|
|
3676
|
+
if (color === null) {
|
|
3677
|
+
return DEFAULT_FOREGROUND;
|
|
3678
|
+
}
|
|
3679
|
+
if (color.type === "ansi4") {
|
|
3680
|
+
return ANSI_16_PALETTE[color.index] ?? DEFAULT_FOREGROUND;
|
|
3681
|
+
}
|
|
3682
|
+
if (color.type === "ansi8") {
|
|
3683
|
+
if (color.index < ANSI_16_PALETTE.length) {
|
|
3684
|
+
return ANSI_16_PALETTE[color.index] ?? DEFAULT_FOREGROUND;
|
|
3685
|
+
}
|
|
3686
|
+
return XTERM_256_PALETTE[color.index] ?? DEFAULT_FOREGROUND;
|
|
3687
|
+
}
|
|
3688
|
+
return `rgb(${color.r},${color.g},${color.b})`;
|
|
3689
|
+
}
|
|
3690
|
+
function escapeXmlText(value) {
|
|
3691
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
3692
|
+
}
|
|
3693
|
+
function escapeXmlAttribute(value) {
|
|
3694
|
+
return escapeXmlText(value).replaceAll('"', """).replaceAll("'", "'");
|
|
3695
|
+
}
|
|
3696
|
+
function formatNumber(value) {
|
|
3697
|
+
return value.toFixed(2);
|
|
3698
|
+
}
|
|
3699
|
+
|
|
3700
|
+
// ../terminal-png/src/index.ts
|
|
3701
|
+
async function renderTerminalPng(ansiText, options = {}) {
|
|
3702
|
+
const runs = parseAnsi(ansiText);
|
|
3703
|
+
const svg = renderSvg(runs, {
|
|
3704
|
+
padding: options.padding,
|
|
3705
|
+
window: options.window
|
|
3706
|
+
});
|
|
3707
|
+
const png = renderPng(svg);
|
|
3708
|
+
if (options.output) {
|
|
3709
|
+
await writeFile(options.output, png);
|
|
3710
|
+
}
|
|
3711
|
+
return png;
|
|
3712
|
+
}
|
|
3713
|
+
|
|
1582
3714
|
// src/commands/screenshot.ts
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
window: S11.Optional(S11.Boolean({ description: "Include terminal window chrome", default: true })),
|
|
1589
|
-
padding: S11.Optional(S11.Number({ short: "p", description: "Padding around terminal content" }))
|
|
3715
|
+
var params11 = S.Object({
|
|
3716
|
+
session: S.Optional(S.String({ short: "s", description: "Session name" })),
|
|
3717
|
+
output: S.String({ short: "o", description: "Path to the output PNG file" }),
|
|
3718
|
+
window: S.Optional(S.Boolean({ description: "Include terminal window chrome", default: true })),
|
|
3719
|
+
padding: S.Optional(S.Number({ short: "p", description: "Padding around terminal content" }))
|
|
1590
3720
|
});
|
|
1591
|
-
var screenshot =
|
|
3721
|
+
var screenshot = defineCommand({
|
|
1592
3722
|
name: "screenshot",
|
|
1593
3723
|
description: "Capture the current terminal screen as a PNG image",
|
|
1594
3724
|
scope: ["cli"],
|
|
@@ -1606,12 +3736,11 @@ var screenshot = defineCommand11({
|
|
|
1606
3736
|
});
|
|
1607
3737
|
|
|
1608
3738
|
// src/commands/send-signal.ts
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
session: S12.Optional(S12.String({ short: "s", description: "Session name" }))
|
|
3739
|
+
var params12 = S.Object({
|
|
3740
|
+
signal: S.String({ description: "Signal to send to the session process" }),
|
|
3741
|
+
session: S.Optional(S.String({ short: "s", description: "Session name" }))
|
|
1613
3742
|
});
|
|
1614
|
-
var sendSignal =
|
|
3743
|
+
var sendSignal = defineCommand({
|
|
1615
3744
|
name: "send-signal",
|
|
1616
3745
|
description: "Send a process signal to an active terminal session",
|
|
1617
3746
|
scope: ["cli", "mcp", "sdk"],
|
|
@@ -1625,12 +3754,11 @@ var sendSignal = defineCommand12({
|
|
|
1625
3754
|
});
|
|
1626
3755
|
|
|
1627
3756
|
// src/commands/type.ts
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
session: S13.Optional(S13.String({ short: "s", description: "Session name" }))
|
|
3757
|
+
var params13 = S.Object({
|
|
3758
|
+
text: S.String({ description: "Text to write to the session" }),
|
|
3759
|
+
session: S.Optional(S.String({ short: "s", description: "Session name" }))
|
|
1632
3760
|
});
|
|
1633
|
-
var type =
|
|
3761
|
+
var type = defineCommand({
|
|
1634
3762
|
name: "type",
|
|
1635
3763
|
description: "Write text to an active terminal session character-by-character with delay",
|
|
1636
3764
|
scope: ["cli", "mcp", "sdk"],
|
|
@@ -1644,14 +3772,13 @@ var type = defineCommand13({
|
|
|
1644
3772
|
});
|
|
1645
3773
|
|
|
1646
3774
|
// src/commands/uninstall.ts
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
agent: S14.Enum(installableAgents, {
|
|
3775
|
+
var params14 = S.Object({
|
|
3776
|
+
agent: S.Enum(installableAgents, {
|
|
1650
3777
|
description: "Agent to uninstall terminal-pilot from",
|
|
1651
3778
|
default: DEFAULT_INSTALL_AGENT
|
|
1652
3779
|
})
|
|
1653
3780
|
});
|
|
1654
|
-
var uninstall =
|
|
3781
|
+
var uninstall = defineCommand({
|
|
1655
3782
|
name: "uninstall",
|
|
1656
3783
|
description: "Remove the terminal-pilot CLI skill.",
|
|
1657
3784
|
scope: ["cli"],
|
|
@@ -1687,19 +3814,18 @@ var uninstall = defineCommand14({
|
|
|
1687
3814
|
});
|
|
1688
3815
|
|
|
1689
3816
|
// src/commands/wait-for.ts
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
S15.Boolean({
|
|
3817
|
+
var params15 = S.Object({
|
|
3818
|
+
pattern: S.String({ description: "Regular expression pattern to wait for" }),
|
|
3819
|
+
session: S.Optional(S.String({ short: "s", description: "Session name" })),
|
|
3820
|
+
timeout: S.Optional(S.Number({ short: "t", description: "Maximum wait time in milliseconds" })),
|
|
3821
|
+
literal: S.Optional(
|
|
3822
|
+
S.Boolean({
|
|
1697
3823
|
short: "l",
|
|
1698
3824
|
description: "When true, treat pattern as a literal string instead of a regex"
|
|
1699
3825
|
})
|
|
1700
3826
|
)
|
|
1701
3827
|
});
|
|
1702
|
-
var waitFor =
|
|
3828
|
+
var waitFor = defineCommand({
|
|
1703
3829
|
name: "wait-for",
|
|
1704
3830
|
description: "Wait for terminal output to match a pattern",
|
|
1705
3831
|
scope: ["cli", "mcp", "sdk"],
|
|
@@ -1714,12 +3840,11 @@ var waitFor = defineCommand15({
|
|
|
1714
3840
|
});
|
|
1715
3841
|
|
|
1716
3842
|
// src/commands/wait-for-exit.ts
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
timeout: S16.Optional(S16.Number({ short: "t", description: "Maximum wait time in milliseconds" }))
|
|
3843
|
+
var params16 = S.Object({
|
|
3844
|
+
session: S.Optional(S.String({ short: "s", description: "Session name" })),
|
|
3845
|
+
timeout: S.Optional(S.Number({ short: "t", description: "Maximum wait time in milliseconds" }))
|
|
1721
3846
|
});
|
|
1722
|
-
var waitForExit2 =
|
|
3847
|
+
var waitForExit2 = defineCommand({
|
|
1723
3848
|
name: "wait-for-exit",
|
|
1724
3849
|
description: "Wait for a terminal session process to finish",
|
|
1725
3850
|
scope: ["cli", "mcp", "sdk"],
|