@phenx-inc/ctlsurf 0.13.5 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/out/headless/index.mjs +13663 -385
  2. package/out/headless/index.mjs.map +4 -4
  3. package/out/main/index.js +11677 -290
  4. package/out/main/node-CUnQxFha.js +868 -0
  5. package/out/preload/index.js +19 -0
  6. package/out/renderer/assets/{cssMode-CAEObGNt.js → cssMode-7adWSORr.js} +3 -3
  7. package/out/renderer/assets/{freemarker2-D63hnnDq.js → freemarker2-BkLLWnzk.js} +1 -1
  8. package/out/renderer/assets/{handlebars-UYo_IYpi.js → handlebars-Cinfm9fZ.js} +1 -1
  9. package/out/renderer/assets/{html-2dvYDi3g.js → html-vl9fkHKL.js} +1 -1
  10. package/out/renderer/assets/{htmlMode-B6fxDDPF.js → htmlMode-BtGqkTNI.js} +3 -3
  11. package/out/renderer/assets/{index-CMb4AqkZ.js → index-BhrV6ld-.js} +381 -29
  12. package/out/renderer/assets/{index-BEekQe3-.css → index-BpCORklm.css} +217 -0
  13. package/out/renderer/assets/{javascript-8RyFDDdk.js → javascript-B7CCdfuW.js} +2 -2
  14. package/out/renderer/assets/{jsonMode-CqspkWCb.js → jsonMode-ut9LWBMJ.js} +3 -3
  15. package/out/renderer/assets/{liquid-DaEnAsYY.js → liquid-DVDJ0lKt.js} +1 -1
  16. package/out/renderer/assets/{lspLanguageFeatures-Czkp5sZb.js → lspLanguageFeatures-BbMj8Wsc.js} +1 -1
  17. package/out/renderer/assets/{mdx-Q-qSZsFg.js → mdx-CcQzYB0J.js} +1 -1
  18. package/out/renderer/assets/{python-Sw0S0BJV.js → python-Byy7wKMv.js} +1 -1
  19. package/out/renderer/assets/{razor-C7zQmabz.js → razor-D1xi_wMM.js} +1 -1
  20. package/out/renderer/assets/{tsMode-BWdOxk6v.js → tsMode-DJPzbn5i.js} +1 -1
  21. package/out/renderer/assets/{typescript-BrdIiKZf.js → typescript-BuVaU7i3.js} +1 -1
  22. package/out/renderer/assets/{xml-DbKLNPOq.js → xml-rzc91O3d.js} +1 -1
  23. package/out/renderer/assets/{yaml-ehupJBsZ.js → yaml-fAOzQMge.js} +1 -1
  24. package/out/renderer/index.html +2 -2
  25. package/package.json +2 -1
  26. package/src/main/index.ts +55 -8
  27. package/src/main/observer/anthropic.ts +48 -0
  28. package/src/main/observer/budget.ts +79 -0
  29. package/src/main/observer/ledger.ts +61 -0
  30. package/src/main/observer/observer.ts +566 -0
  31. package/src/main/observer/spans.ts +170 -0
  32. package/src/main/observer/store.ts +200 -0
  33. package/src/main/observer/tier0.ts +234 -0
  34. package/src/main/observer/tier1.ts +306 -0
  35. package/src/main/observer/tier2.ts +125 -0
  36. package/src/main/observer/types.ts +224 -0
  37. package/src/main/orchestrator.ts +74 -0
  38. package/src/main/transcripts.ts +18 -0
  39. package/src/preload/index.ts +40 -2
  40. package/src/renderer/App.tsx +22 -0
  41. package/src/renderer/components/ObserverPanel.tsx +289 -0
  42. package/src/renderer/components/SettingsDialog.tsx +104 -0
  43. package/src/renderer/components/TerminalPanel.tsx +28 -5
  44. package/src/renderer/styles.css +217 -0
@@ -0,0 +1,868 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const index = require("./index.js");
4
+ const fs = require("node:fs/promises");
5
+ const fssync = require("node:fs");
6
+ const path = require("node:path");
7
+ const cp = require("node:child_process");
8
+ const crypto = require("node:crypto");
9
+ const readline = require("node:readline");
10
+ const node_util = require("node:util");
11
+ const node_stream = require("node:stream");
12
+ const promises = require("node:stream/promises");
13
+ function _interopNamespaceDefault(e) {
14
+ const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
15
+ if (e) {
16
+ for (const k in e) {
17
+ if (k !== "default") {
18
+ const d = Object.getOwnPropertyDescriptor(e, k);
19
+ Object.defineProperty(n, k, d.get ? d : {
20
+ enumerable: true,
21
+ get: () => e[k]
22
+ });
23
+ }
24
+ }
25
+ }
26
+ n.default = e;
27
+ return Object.freeze(n);
28
+ }
29
+ const fs__namespace = /* @__PURE__ */ _interopNamespaceDefault(fs);
30
+ const fssync__namespace = /* @__PURE__ */ _interopNamespaceDefault(fssync);
31
+ const path__namespace = /* @__PURE__ */ _interopNamespaceDefault(path);
32
+ const cp__namespace = /* @__PURE__ */ _interopNamespaceDefault(cp);
33
+ const crypto__namespace = /* @__PURE__ */ _interopNamespaceDefault(crypto);
34
+ const readline__namespace = /* @__PURE__ */ _interopNamespaceDefault(readline);
35
+ function betaTool(options) {
36
+ if (options.inputSchema.type !== "object") {
37
+ throw new Error(`JSON schema for tool "${options.name}" must be an object, but got ${options.inputSchema.type}`);
38
+ }
39
+ return {
40
+ type: "custom",
41
+ name: options.name,
42
+ input_schema: options.inputSchema,
43
+ description: options.description,
44
+ run: options.run,
45
+ parse: (content) => content,
46
+ ...options.close ? { close: options.close } : {}
47
+ };
48
+ }
49
+ const DIR_CREATE_MODE = 493;
50
+ const FILE_CREATE_MODE = 420;
51
+ async function realpathOrSelf(p) {
52
+ try {
53
+ return await fs__namespace.realpath(p);
54
+ } catch {
55
+ return p;
56
+ }
57
+ }
58
+ async function canonicalize(abs) {
59
+ const tail = [];
60
+ let prefix = abs;
61
+ let hops = 0;
62
+ for (; ; ) {
63
+ let real;
64
+ try {
65
+ real = await fs__namespace.realpath(prefix);
66
+ } catch {
67
+ let isLink = false;
68
+ try {
69
+ isLink = (await fs__namespace.lstat(prefix)).isSymbolicLink();
70
+ } catch {
71
+ }
72
+ if (isLink) {
73
+ if (++hops > 40) {
74
+ throw new index.ToolError(`path ${JSON.stringify(abs)} has too many levels of symbolic links`);
75
+ }
76
+ prefix = path__namespace.resolve(path__namespace.dirname(prefix), await fs__namespace.readlink(prefix));
77
+ continue;
78
+ }
79
+ const parent = path__namespace.dirname(prefix);
80
+ if (parent === prefix)
81
+ return abs;
82
+ tail.push(path__namespace.basename(prefix));
83
+ prefix = parent;
84
+ continue;
85
+ }
86
+ return tail.length ? path__namespace.join(real, ...tail.reverse()) : real;
87
+ }
88
+ }
89
+ async function confineToRoot(root, p, opts) {
90
+ const allowOutside = opts?.allowOutside ?? false;
91
+ const realRoot = await realpathOrSelf(path__namespace.resolve(root));
92
+ const abs = path__namespace.resolve(realRoot, p);
93
+ if (allowOutside)
94
+ return abs;
95
+ const real = await canonicalize(abs);
96
+ if (real !== realRoot && !real.startsWith(realRoot + path__namespace.sep)) {
97
+ throw new index.ToolError(`path ${JSON.stringify(p)} escapes workdir`);
98
+ }
99
+ return real;
100
+ }
101
+ async function atomicWriteFile(targetPath, content) {
102
+ const dir = path__namespace.dirname(targetPath);
103
+ const tempPath = path__namespace.join(dir, `.tmp-${process.pid}-${crypto.randomUUID()}`);
104
+ let handle;
105
+ try {
106
+ handle = await fs__namespace.open(tempPath, "wx", FILE_CREATE_MODE);
107
+ await handle.writeFile(content, "utf-8");
108
+ await handle.sync();
109
+ await handle.close();
110
+ handle = void 0;
111
+ await fs__namespace.rename(tempPath, targetPath);
112
+ } catch (err) {
113
+ if (handle)
114
+ await handle.close().catch(() => {
115
+ });
116
+ await fs__namespace.unlink(tempPath).catch(() => {
117
+ });
118
+ throw err;
119
+ }
120
+ }
121
+ function fsErrorMessage(err, file) {
122
+ const code = err?.code;
123
+ switch (code) {
124
+ case "ENOENT":
125
+ return `${file}: no such file or directory`;
126
+ case "EACCES":
127
+ case "EPERM":
128
+ return `${file}: permission denied`;
129
+ case "ENOTDIR":
130
+ return `${file}: not a directory`;
131
+ case "EISDIR":
132
+ return `${file}: is a directory`;
133
+ case "ELOOP":
134
+ return `${file}: too many levels of symbolic links`;
135
+ case "ENAMETOOLONG":
136
+ return `${file}: file name too long`;
137
+ case "ENOSPC":
138
+ return `${file}: no space left on device`;
139
+ case "EMFILE":
140
+ case "ENFILE":
141
+ return `${file}: too many open files`;
142
+ default:
143
+ return `${file}: ${err instanceof Error ? err.message : String(err)}`;
144
+ }
145
+ }
146
+ const execFileAsync = node_util.promisify(cp.execFile);
147
+ async function setupSkills(ctx) {
148
+ const { client, sessionId } = ctx;
149
+ if (!client || !sessionId)
150
+ return async () => {
151
+ };
152
+ const log = index.loggerFor(client);
153
+ const session = await client.beta.sessions.retrieve(sessionId);
154
+ const skillsRoot = path__namespace.resolve(ctx.workdir, "skills");
155
+ const created = [];
156
+ for (const skill of session.agent.skills) {
157
+ try {
158
+ const versionId = await resolveSkillVersion(client, skill.skill_id, skill.version);
159
+ const version = await client.beta.skills.versions.retrieve(versionId, { skill_id: skill.skill_id });
160
+ let dirname = path__namespace.basename(version.name.trim());
161
+ if (dirname === "" || dirname === "." || dirname === "..")
162
+ dirname = skill.skill_id;
163
+ const dest = path__namespace.resolve(skillsRoot, dirname);
164
+ if (dest !== skillsRoot && !dest.startsWith(skillsRoot + path__namespace.sep)) {
165
+ log.warn("skill name escapes the skills dir; skipping", {
166
+ component: "agent-tool-context",
167
+ name: version.name
168
+ });
169
+ continue;
170
+ }
171
+ const resp = await client.beta.skills.versions.download(versionId, { skill_id: skill.skill_id });
172
+ await fs__namespace.rm(dest, { recursive: true, force: true });
173
+ await fs__namespace.mkdir(dest, { recursive: true, mode: DIR_CREATE_MODE });
174
+ created.push(dest);
175
+ await extractSkillArchive(resp, dest);
176
+ log.info("downloaded skill", {
177
+ component: "agent-tool-context",
178
+ skill_id: skill.skill_id,
179
+ version: versionId,
180
+ dest
181
+ });
182
+ } catch (e) {
183
+ log.warn("failed to download skill", {
184
+ component: "agent-tool-context",
185
+ skill_id: skill.skill_id,
186
+ error: String(e)
187
+ });
188
+ }
189
+ }
190
+ return async () => {
191
+ for (const dest of created) {
192
+ await fs__namespace.rm(dest, { recursive: true, force: true }).catch((e) => {
193
+ log.warn("failed to clean up skill", { component: "agent-tool-context", dest, error: String(e) });
194
+ });
195
+ }
196
+ };
197
+ }
198
+ async function resolveSkillVersion(client, skillId, version) {
199
+ if (/^\d+$/.test(version))
200
+ return version;
201
+ let newest;
202
+ for await (const v of client.beta.skills.versions.list(skillId)) {
203
+ if (/^\d+$/.test(v.version) && (newest === void 0 || BigInt(v.version) > BigInt(newest))) {
204
+ newest = v.version;
205
+ }
206
+ }
207
+ if (newest === void 0) {
208
+ throw new index.AnthropicError(`skill ${JSON.stringify(skillId)} has no concrete version to resolve ${JSON.stringify(version)} against`);
209
+ }
210
+ return newest;
211
+ }
212
+ function assertSafeMemberNames(names) {
213
+ for (const raw of names.split("\n")) {
214
+ const entry = raw.trim();
215
+ if (!entry)
216
+ continue;
217
+ if (path__namespace.isAbsolute(entry) || entry.split(/[\\/]/).includes("..")) {
218
+ throw new index.AnthropicError(`refusing to extract unsafe archive member: ${entry}`);
219
+ }
220
+ }
221
+ }
222
+ function assertNoSpecialMembers(verboseListing) {
223
+ for (const line of verboseListing.split("\n")) {
224
+ const type = line.trimStart()[0];
225
+ if (type === "l" || type === "h" || type === "b" || type === "c" || type === "p" || type === "s") {
226
+ throw new index.AnthropicError("refusing to extract archive with symlink/hardlink/device member");
227
+ }
228
+ }
229
+ }
230
+ async function runArchiveTool(cmd, args) {
231
+ try {
232
+ const { stdout } = await execFileAsync(cmd, args);
233
+ return stdout;
234
+ } catch (e) {
235
+ if (e != null && typeof e === "object" && e.code === "ENOENT") {
236
+ throw new index.AnthropicError(`skill extraction requires the \`${cmd}\` command, but it was not found on PATH`);
237
+ }
238
+ throw e;
239
+ }
240
+ }
241
+ function archiveTopDir(listing) {
242
+ let top;
243
+ let nested = false;
244
+ for (const raw of listing.split("\n")) {
245
+ const parts = raw.trim().split("/").filter((p) => p !== "" && p !== ".");
246
+ if (parts.length === 0)
247
+ continue;
248
+ const first = parts[0];
249
+ if (top === void 0)
250
+ top = first;
251
+ else if (first !== top)
252
+ return "";
253
+ if (parts.length > 1)
254
+ nested = true;
255
+ }
256
+ return top !== void 0 && nested ? top : "";
257
+ }
258
+ async function extractSkillArchive(resp, dest) {
259
+ const tmp = path__namespace.join(dest, `.skill-archive-${process.pid}-${Date.now()}`);
260
+ if (!resp.body) {
261
+ throw new index.AnthropicError("skill download response had no body");
262
+ }
263
+ await promises.pipeline(node_stream.Readable.fromWeb(resp.body), fssync__namespace.createWriteStream(tmp));
264
+ const stage = path__namespace.join(path__namespace.dirname(dest), `.skill-stage-${process.pid}-${Date.now()}`);
265
+ try {
266
+ const head = await readHead(tmp, 4);
267
+ const isZip = head.length >= 4 && head[0] === 80 && head[1] === 75 && head[2] === 3 && head[3] === 4;
268
+ const archiveCmd = isZip ? "unzip" : "tar";
269
+ const listing = await runArchiveTool(archiveCmd, isZip ? ["-Z1", tmp] : ["-tf", tmp]);
270
+ assertSafeMemberNames(listing);
271
+ assertNoSpecialMembers(await runArchiveTool(archiveCmd, isZip ? ["-Z", tmp] : ["-tvf", tmp]));
272
+ const top = archiveTopDir(listing);
273
+ await fs__namespace.mkdir(stage, { recursive: true, mode: DIR_CREATE_MODE });
274
+ await runArchiveTool(archiveCmd, isZip ? ["-oq", tmp, "-d", stage] : ["-xf", tmp, "-C", stage]);
275
+ const srcRoot = top ? path__namespace.join(stage, top) : stage;
276
+ for (const entry of await fs__namespace.readdir(srcRoot)) {
277
+ await fs__namespace.rename(path__namespace.join(srcRoot, entry), path__namespace.join(dest, entry));
278
+ }
279
+ } finally {
280
+ await fs__namespace.rm(tmp, { force: true });
281
+ await fs__namespace.rm(stage, { recursive: true, force: true });
282
+ }
283
+ }
284
+ async function readHead(file, n) {
285
+ const handle = await fs__namespace.open(file, "r");
286
+ try {
287
+ const buf = Buffer.alloc(n);
288
+ const { bytesRead } = await handle.read(buf, 0, n, 0);
289
+ return buf.subarray(0, bytesRead);
290
+ } finally {
291
+ await handle.close();
292
+ }
293
+ }
294
+ var _BashSession_instances, _BashSession_proc, _BashSession_buf, _BashSession_truncated, _BashSession_closed, _BashSession_waiting, _BashSession_append;
295
+ const BASH_OUTPUT_LIMIT = 100 * 1024;
296
+ const BASH_DEFAULT_TIMEOUT_MS = 12e4;
297
+ const DEFAULT_MAX_FILE_BYTES = 256 * 1024;
298
+ const GREP_OUTPUT_LIMIT = 100 * 1024;
299
+ const GREP_MAX_LINE_LENGTH = 2e3;
300
+ const GLOB_RESULT_LIMIT = 200;
301
+ const ANSI_RE = /\x1b\[[0-9;?]*[ -/]*[@-~]/g;
302
+ const fsGlob = fs__namespace.glob;
303
+ function resolveMaxBytes(configured) {
304
+ return configured === void 0 ? DEFAULT_MAX_FILE_BYTES : configured;
305
+ }
306
+ function betaAgentToolset20260401(ctx) {
307
+ return [
308
+ betaBashTool(ctx),
309
+ betaReadTool(ctx),
310
+ betaWriteTool(ctx),
311
+ betaEditTool(ctx),
312
+ betaGlobTool(ctx),
313
+ betaGrepTool(ctx)
314
+ ];
315
+ }
316
+ function resolvePath(ctx, p) {
317
+ return confineToRoot(ctx.workdir, p, { allowOutside: ctx.unrestrictedPaths ?? false });
318
+ }
319
+ function scrubbedShellEnv() {
320
+ const env = {};
321
+ for (const [key, value] of Object.entries(process.env)) {
322
+ if (key.startsWith("ANTHROPIC_"))
323
+ continue;
324
+ env[key] = value;
325
+ }
326
+ return env;
327
+ }
328
+ class BashSession {
329
+ constructor(dir, env = scrubbedShellEnv()) {
330
+ _BashSession_instances.add(this);
331
+ _BashSession_proc.set(this, void 0);
332
+ _BashSession_buf.set(this, "");
333
+ _BashSession_truncated.set(this, false);
334
+ _BashSession_closed.set(this, false);
335
+ _BashSession_waiting.set(this, null);
336
+ index.__classPrivateFieldSet(this, _BashSession_proc, cp__namespace.spawn("/bin/bash", ["--noprofile", "--norc"], {
337
+ cwd: dir,
338
+ // `env` is the full base environment (the scrubbed process env by
339
+ // default, or the verbatim replacement from `AgentToolContext.env`).
340
+ // PS1/PS2/TERM are shell-control settings BashSession always applies so
341
+ // the pipe-based sentinel exec parsing works — not part of the
342
+ // user-facing environment.
343
+ env: { ...env, PS1: "", PS2: "", TERM: "dumb" },
344
+ stdio: ["pipe", "pipe", "pipe"],
345
+ detached: true
346
+ }));
347
+ index.__classPrivateFieldGet(this, _BashSession_proc, "f").stdout.setEncoding("utf8");
348
+ index.__classPrivateFieldGet(this, _BashSession_proc, "f").stderr.setEncoding("utf8");
349
+ index.__classPrivateFieldGet(this, _BashSession_proc, "f").stdout.on("data", (d) => index.__classPrivateFieldGet(this, _BashSession_instances, "m", _BashSession_append).call(this, d));
350
+ index.__classPrivateFieldGet(this, _BashSession_proc, "f").stderr.on("data", (d) => index.__classPrivateFieldGet(this, _BashSession_instances, "m", _BashSession_append).call(this, d));
351
+ index.__classPrivateFieldGet(this, _BashSession_proc, "f").once("close", () => {
352
+ index.__classPrivateFieldSet(this, _BashSession_closed, true);
353
+ const w = index.__classPrivateFieldGet(this, _BashSession_waiting, "f");
354
+ index.__classPrivateFieldSet(this, _BashSession_waiting, null);
355
+ w?.resolve();
356
+ });
357
+ }
358
+ /** Whether the underlying shell process has exited. */
359
+ get closed() {
360
+ return index.__classPrivateFieldGet(this, _BashSession_closed, "f");
361
+ }
362
+ async exec(command, opts = {}) {
363
+ if (index.__classPrivateFieldGet(this, _BashSession_closed, "f")) {
364
+ throw new index.AnthropicError("bash session terminated");
365
+ }
366
+ const timeoutMs = opts.timeoutMs ?? BASH_DEFAULT_TIMEOUT_MS;
367
+ const signal = opts.signal;
368
+ if (signal?.aborted) {
369
+ throw new index.AnthropicError("bash command aborted");
370
+ }
371
+ index.__classPrivateFieldSet(this, _BashSession_buf, "");
372
+ index.__classPrivateFieldSet(this, _BashSession_truncated, false);
373
+ const sentinel = `__ANT_CMD_${crypto__namespace.randomUUID()}_DONE__`;
374
+ const sentinelSplit = `${sentinel.slice(0, 8)}''${sentinel.slice(8)}`;
375
+ const wrapped = `{ ${command}
376
+ } </dev/null 2>&1; printf '\\n${sentinelSplit}%d\\n' $?
377
+ `;
378
+ index.__classPrivateFieldGet(this, _BashSession_proc, "f").stdin.write(wrapped);
379
+ if (index.__classPrivateFieldGet(this, _BashSession_buf, "f").indexOf(sentinel) < 0) {
380
+ const { promise: sentinelSeen, resolve } = index.promiseWithResolvers();
381
+ index.__classPrivateFieldSet(this, _BashSession_waiting, { sentinel, resolve });
382
+ let timer;
383
+ let onAbort;
384
+ try {
385
+ await Promise.race([
386
+ sentinelSeen,
387
+ new Promise((_, reject) => {
388
+ timer = setTimeout(() => reject(new index.AnthropicError(`bash command timed out after ${timeoutMs}ms`)), timeoutMs);
389
+ }),
390
+ new Promise((_, reject) => {
391
+ if (!signal)
392
+ return;
393
+ onAbort = () => reject(new index.AnthropicError("bash command aborted"));
394
+ signal.addEventListener("abort", onAbort, { once: true });
395
+ })
396
+ ]);
397
+ } finally {
398
+ if (timer)
399
+ clearTimeout(timer);
400
+ if (onAbort && signal)
401
+ signal.removeEventListener("abort", onAbort);
402
+ index.__classPrivateFieldSet(this, _BashSession_waiting, null);
403
+ }
404
+ }
405
+ const idx = index.__classPrivateFieldGet(this, _BashSession_buf, "f").indexOf(sentinel);
406
+ if (idx < 0) {
407
+ throw new index.AnthropicError("bash session terminated");
408
+ }
409
+ const tail = index.__classPrivateFieldGet(this, _BashSession_buf, "f").slice(idx + sentinel.length);
410
+ const m = tail.match(/^(-?\d+)/);
411
+ const exitCode = m ? parseInt(m[1], 10) : -1;
412
+ let out = index.__classPrivateFieldGet(this, _BashSession_buf, "f").slice(0, idx).replace(ANSI_RE, "").replace(/\n+$/, "");
413
+ if (index.__classPrivateFieldGet(this, _BashSession_truncated, "f")) {
414
+ out = `[output truncated]
415
+ ${out}`;
416
+ }
417
+ return { output: out, exitCode };
418
+ }
419
+ close() {
420
+ if (index.__classPrivateFieldGet(this, _BashSession_closed, "f"))
421
+ return;
422
+ index.__classPrivateFieldSet(this, _BashSession_closed, true);
423
+ const w = index.__classPrivateFieldGet(this, _BashSession_waiting, "f");
424
+ index.__classPrivateFieldSet(this, _BashSession_waiting, null);
425
+ w?.resolve();
426
+ index.__classPrivateFieldGet(this, _BashSession_proc, "f").stdout.destroy();
427
+ index.__classPrivateFieldGet(this, _BashSession_proc, "f").stderr.destroy();
428
+ index.__classPrivateFieldGet(this, _BashSession_proc, "f").stdin.destroy();
429
+ try {
430
+ process.kill(-index.__classPrivateFieldGet(this, _BashSession_proc, "f").pid, "SIGKILL");
431
+ } catch {
432
+ index.__classPrivateFieldGet(this, _BashSession_proc, "f").kill("SIGKILL");
433
+ }
434
+ index.__classPrivateFieldGet(this, _BashSession_proc, "f").unref();
435
+ }
436
+ }
437
+ _BashSession_proc = /* @__PURE__ */ new WeakMap(), _BashSession_buf = /* @__PURE__ */ new WeakMap(), _BashSession_truncated = /* @__PURE__ */ new WeakMap(), _BashSession_closed = /* @__PURE__ */ new WeakMap(), _BashSession_waiting = /* @__PURE__ */ new WeakMap(), _BashSession_instances = /* @__PURE__ */ new WeakSet(), _BashSession_append = function _BashSession_append2(d) {
438
+ index.__classPrivateFieldSet(this, _BashSession_buf, index.__classPrivateFieldGet(this, _BashSession_buf, "f") + d);
439
+ if (index.__classPrivateFieldGet(this, _BashSession_buf, "f").length > BASH_OUTPUT_LIMIT) {
440
+ index.__classPrivateFieldSet(this, _BashSession_buf, index.__classPrivateFieldGet(this, _BashSession_buf, "f").slice(index.__classPrivateFieldGet(this, _BashSession_buf, "f").length - BASH_OUTPUT_LIMIT));
441
+ index.__classPrivateFieldSet(this, _BashSession_truncated, true);
442
+ }
443
+ if (index.__classPrivateFieldGet(this, _BashSession_waiting, "f") && index.__classPrivateFieldGet(this, _BashSession_buf, "f").indexOf(index.__classPrivateFieldGet(this, _BashSession_waiting, "f").sentinel) >= 0) {
444
+ const w = index.__classPrivateFieldGet(this, _BashSession_waiting, "f");
445
+ index.__classPrivateFieldSet(this, _BashSession_waiting, null);
446
+ w.resolve();
447
+ }
448
+ };
449
+ function betaBashTool(ctx) {
450
+ let session;
451
+ let tail = Promise.resolve();
452
+ return betaTool({
453
+ name: "bash",
454
+ description: "Run a bash command in a persistent shell. State (cwd, env vars) persists across calls.",
455
+ inputSchema: {
456
+ type: "object",
457
+ properties: {
458
+ command: { type: "string", description: "The command to run" },
459
+ restart: { type: "boolean", description: "Restart the persistent shell before running" },
460
+ timeout_ms: { type: "integer", description: "Per-call timeout in milliseconds" }
461
+ }
462
+ },
463
+ run: async ({ command, restart, timeout_ms }, context) => {
464
+ const prev = tail;
465
+ const gate = index.promiseWithResolvers();
466
+ tail = gate.promise;
467
+ try {
468
+ await prev;
469
+ } catch {
470
+ }
471
+ try {
472
+ if (restart) {
473
+ session?.close();
474
+ session = void 0;
475
+ }
476
+ if (!command) {
477
+ if (restart)
478
+ return "bash session restarted";
479
+ throw new index.ToolError("bash: command is required");
480
+ }
481
+ session ?? (session = new BashSession(ctx.workdir, ctx.env));
482
+ try {
483
+ const { output, exitCode } = await session.exec(command, {
484
+ timeoutMs: timeout_ms ?? BASH_DEFAULT_TIMEOUT_MS,
485
+ signal: context?.signal
486
+ });
487
+ if (exitCode !== 0)
488
+ throw new index.ToolError(output || `exit ${exitCode}`);
489
+ return output;
490
+ } catch (e) {
491
+ if (e instanceof index.ToolError)
492
+ throw e;
493
+ session.close();
494
+ session = void 0;
495
+ throw new index.ToolError(`bash: ${e instanceof Error ? e.message : String(e)}`);
496
+ }
497
+ } finally {
498
+ gate.resolve();
499
+ }
500
+ },
501
+ close: () => {
502
+ session?.close();
503
+ session = void 0;
504
+ }
505
+ });
506
+ }
507
+ function betaReadTool(ctx) {
508
+ return betaTool({
509
+ name: "read",
510
+ description: "Read a UTF-8 text file relative to the workdir.",
511
+ inputSchema: {
512
+ type: "object",
513
+ properties: {
514
+ file_path: { type: "string" },
515
+ view_range: {
516
+ type: "array",
517
+ items: { type: "integer" },
518
+ description: "[start_line, end_line] 1-indexed inclusive"
519
+ }
520
+ },
521
+ required: ["file_path"]
522
+ },
523
+ run: async ({ file_path, view_range }) => {
524
+ if (!file_path)
525
+ throw new index.ToolError("read: file_path is required");
526
+ const abs = await resolvePath(ctx, file_path);
527
+ let data;
528
+ try {
529
+ const st = await fs__namespace.stat(abs);
530
+ if (!st.isFile()) {
531
+ throw new index.ToolError(`read: ${file_path} is not a regular file`);
532
+ }
533
+ const limit = resolveMaxBytes(ctx.maxFileBytes);
534
+ if (limit !== null && st.size > limit) {
535
+ throw new index.ToolError(`read: ${file_path} is ${st.size} bytes, exceeds ${limit}-byte limit. Use bash (head/tail/sed) to read a slice.`);
536
+ }
537
+ data = await fs__namespace.readFile(abs, "utf8");
538
+ } catch (e) {
539
+ if (e instanceof index.ToolError)
540
+ throw e;
541
+ throw new index.ToolError(`read: ${fsErrorMessage(e, file_path)}`);
542
+ }
543
+ if (!view_range)
544
+ return data;
545
+ if (view_range.length !== 2)
546
+ throw new index.ToolError("read: view_range must be [start_line, end_line]");
547
+ const [startLine, endLine] = view_range;
548
+ const lines = data.split("\n");
549
+ const start = Math.max(0, startLine - 1);
550
+ const end = endLine > 0 ? endLine : lines.length;
551
+ return lines.slice(start, end).join("\n");
552
+ }
553
+ });
554
+ }
555
+ function betaWriteTool(ctx) {
556
+ return betaTool({
557
+ name: "write",
558
+ description: "Write a UTF-8 text file relative to the workdir, creating parent directories as needed.",
559
+ inputSchema: {
560
+ type: "object",
561
+ properties: { file_path: { type: "string" }, content: { type: "string" } },
562
+ required: ["file_path", "content"]
563
+ },
564
+ run: async ({ file_path, content }) => {
565
+ if (!file_path)
566
+ throw new index.ToolError("write: file_path is required");
567
+ const abs = await resolvePath(ctx, file_path);
568
+ try {
569
+ await fs__namespace.mkdir(path__namespace.dirname(abs), { recursive: true, mode: DIR_CREATE_MODE });
570
+ await atomicWriteFile(abs, content ?? "");
571
+ } catch (e) {
572
+ throw new index.ToolError(`write: ${fsErrorMessage(e, file_path)}`);
573
+ }
574
+ return `wrote ${Buffer.byteLength(content ?? "")} bytes to ${file_path}`;
575
+ }
576
+ });
577
+ }
578
+ function betaEditTool(ctx) {
579
+ return betaTool({
580
+ name: "edit",
581
+ description: "Replace old_string with new_string in a file. old_string must be unique unless replace_all.",
582
+ inputSchema: {
583
+ type: "object",
584
+ properties: {
585
+ file_path: { type: "string" },
586
+ old_string: { type: "string" },
587
+ new_string: { type: "string" },
588
+ replace_all: { type: "boolean" }
589
+ },
590
+ required: ["file_path", "old_string", "new_string"]
591
+ },
592
+ run: async ({ file_path, old_string, new_string, replace_all }) => {
593
+ if (!file_path)
594
+ throw new index.ToolError("edit: file_path is required");
595
+ if (!old_string)
596
+ throw new index.ToolError("edit: old_string is required");
597
+ const abs = await resolvePath(ctx, file_path);
598
+ let data;
599
+ try {
600
+ const st = await fs__namespace.stat(abs);
601
+ if (!st.isFile()) {
602
+ throw new index.ToolError(`edit: ${file_path} is not a regular file`);
603
+ }
604
+ const limit = resolveMaxBytes(ctx.maxFileBytes);
605
+ if (limit !== null && st.size > limit) {
606
+ throw new index.ToolError(`edit: ${file_path} is ${st.size} bytes, exceeds ${limit}-byte limit. Use bash (sed/awk) to edit a large file.`);
607
+ }
608
+ data = await fs__namespace.readFile(abs, "utf8");
609
+ } catch (e) {
610
+ if (e instanceof index.ToolError)
611
+ throw e;
612
+ throw new index.ToolError(`edit: ${fsErrorMessage(e, file_path)}`);
613
+ }
614
+ const count = data.split(old_string).length - 1;
615
+ if (count === 0)
616
+ throw new index.ToolError(`edit: old_string not found in ${file_path}`);
617
+ let updated;
618
+ if (replace_all) {
619
+ updated = data.split(old_string).join(new_string);
620
+ } else {
621
+ if (count > 1)
622
+ throw new index.ToolError(`edit: old_string appears ${count} times in ${file_path} (must be unique)`);
623
+ updated = data.replace(old_string, () => new_string);
624
+ }
625
+ try {
626
+ await atomicWriteFile(abs, updated);
627
+ } catch (e) {
628
+ throw new index.ToolError(`edit: write: ${fsErrorMessage(e, file_path)}`);
629
+ }
630
+ return `edited ${file_path} (${replace_all ? count : 1} replacement(s))`;
631
+ }
632
+ });
633
+ }
634
+ function betaGlobTool(ctx) {
635
+ return betaTool({
636
+ name: "glob",
637
+ description: "Match files under the workdir against a glob pattern. Results are mtime-sorted, newest first.",
638
+ inputSchema: {
639
+ type: "object",
640
+ properties: {
641
+ pattern: { type: "string" },
642
+ path: { type: "string", description: "Directory to search in. Defaults to the workdir." }
643
+ },
644
+ required: ["pattern"]
645
+ },
646
+ run: async ({ pattern, path: searchPath }) => {
647
+ if (!pattern)
648
+ throw new index.ToolError("glob: pattern is required");
649
+ let root = path__namespace.resolve(ctx.workdir);
650
+ let pat = pattern;
651
+ if (path__namespace.isAbsolute(pattern)) {
652
+ if (!ctx.unrestrictedPaths)
653
+ throw new index.ToolError("glob: absolute pattern not permitted");
654
+ root = path__namespace.parse(pattern).root;
655
+ pat = path__namespace.relative(root, pattern);
656
+ } else if (searchPath) {
657
+ root = await resolvePath(ctx, searchPath);
658
+ }
659
+ if (!ctx.unrestrictedPaths && pat.split(/[\\/]/).includes("..")) {
660
+ throw new index.ToolError('glob: ".." is not permitted in the pattern');
661
+ }
662
+ const realRoot = ctx.unrestrictedPaths ? root : await fs__namespace.realpath(root).catch(() => root);
663
+ const matches = [];
664
+ try {
665
+ for await (const entry of fsGlob(pat, {
666
+ cwd: root,
667
+ withFileTypes: true,
668
+ exclude: (d) => d.name === ".git" || d.name === "node_modules"
669
+ })) {
670
+ if (!entry.isFile())
671
+ continue;
672
+ const full = path__namespace.join(entry.parentPath, entry.name);
673
+ if (!ctx.unrestrictedPaths) {
674
+ let real;
675
+ try {
676
+ real = await fs__namespace.realpath(full);
677
+ } catch {
678
+ continue;
679
+ }
680
+ if (!isWithin(realRoot, real))
681
+ continue;
682
+ }
683
+ let mtime = 0;
684
+ try {
685
+ mtime = (await fs__namespace.stat(full)).mtimeMs;
686
+ } catch {
687
+ }
688
+ matches.push({ path: full, mtime });
689
+ }
690
+ } catch (e) {
691
+ throw new index.ToolError(`glob: ${e instanceof Error ? e.message : String(e)}`);
692
+ }
693
+ if (matches.length === 0)
694
+ return "no matches";
695
+ matches.sort((a, b) => b.mtime - a.mtime);
696
+ return matches.slice(0, GLOB_RESULT_LIMIT).map((m) => m.path).join("\n");
697
+ }
698
+ });
699
+ }
700
+ function betaGrepTool(ctx) {
701
+ return betaTool({
702
+ name: "grep",
703
+ description: "Search file contents for a regex. Uses ripgrep if available, otherwise a built-in walker.",
704
+ inputSchema: {
705
+ type: "object",
706
+ properties: { pattern: { type: "string" }, path: { type: "string" } },
707
+ required: ["pattern"]
708
+ },
709
+ run: async ({ pattern, path: p }, context) => {
710
+ if (!pattern)
711
+ throw new index.ToolError("grep: pattern is required");
712
+ let searchPath = path__namespace.resolve(ctx.workdir);
713
+ if (p)
714
+ searchPath = await resolvePath(ctx, p);
715
+ const rg = await findRg();
716
+ return rg ? runRipgrep(rg, pattern, searchPath, context?.signal) : runWalkGrep(pattern, searchPath, context?.signal);
717
+ }
718
+ });
719
+ }
720
+ function runRipgrep(rg, pattern, searchPath, signal) {
721
+ return new Promise((resolve, reject) => {
722
+ const proc = cp__namespace.spawn(rg, ["-n", "--no-heading", "-e", pattern, "--", searchPath], {
723
+ ...signal ? { signal } : {}
724
+ });
725
+ let out = "";
726
+ let errOut = "";
727
+ let truncated = false;
728
+ proc.stdout.on("data", (d) => {
729
+ if (truncated)
730
+ return;
731
+ out += d;
732
+ if (out.length > GREP_OUTPUT_LIMIT) {
733
+ truncated = true;
734
+ out = out.slice(0, GREP_OUTPUT_LIMIT);
735
+ proc.kill("SIGKILL");
736
+ }
737
+ });
738
+ proc.stderr.on("data", (d) => errOut += d);
739
+ proc.on("close", (code) => {
740
+ if (signal?.aborted)
741
+ return reject(new index.ToolError("grep: aborted"));
742
+ if (truncated)
743
+ return resolve(out + `
744
+ [output truncated at ${GREP_OUTPUT_LIMIT} bytes]`);
745
+ if (code === 0)
746
+ return resolve(out);
747
+ if (code === 1)
748
+ return resolve("no matches");
749
+ reject(new index.ToolError(`grep: rg failed: ${errOut || `exit ${code}`}`));
750
+ });
751
+ proc.on("error", (e) => {
752
+ if (signal?.aborted)
753
+ return reject(new index.ToolError("grep: aborted"));
754
+ reject(new index.ToolError(`grep: rg failed: ${e.message}`));
755
+ });
756
+ });
757
+ }
758
+ async function runWalkGrep(pattern, root, signal) {
759
+ let re;
760
+ try {
761
+ re = new RegExp(pattern);
762
+ } catch (e) {
763
+ throw new index.ToolError(`grep: invalid regex: ${e instanceof Error ? e.message : String(e)}`);
764
+ }
765
+ const hits = [];
766
+ let budget = GREP_OUTPUT_LIMIT;
767
+ const push = (line) => {
768
+ budget -= line.length + 1;
769
+ if (budget < 0) {
770
+ hits.push(`[output truncated at ${GREP_OUTPUT_LIMIT} bytes]`);
771
+ return false;
772
+ }
773
+ hits.push(line);
774
+ return true;
775
+ };
776
+ const stat = await fs__namespace.stat(root).catch(() => null);
777
+ if (stat?.isFile()) {
778
+ await grepFile(root, re, push);
779
+ } else {
780
+ await walk(root, "", (rel) => grepFile(path__namespace.join(root, rel), re, push), signal);
781
+ }
782
+ if (signal?.aborted)
783
+ throw new index.ToolError("grep: aborted");
784
+ if (hits.length === 0)
785
+ return "no matches";
786
+ return hits.join("\n");
787
+ }
788
+ async function grepFile(file, re, push) {
789
+ const stream = fssync__namespace.createReadStream(file, { encoding: "utf8" });
790
+ const rl = readline__namespace.createInterface({ input: stream, crlfDelay: Infinity });
791
+ let i = 0;
792
+ try {
793
+ for await (const line of rl) {
794
+ i++;
795
+ if (line.length > GREP_MAX_LINE_LENGTH)
796
+ continue;
797
+ if (re.test(line) && !push(`${file}:${i}:${line}`))
798
+ return false;
799
+ }
800
+ } catch {
801
+ } finally {
802
+ stream.destroy();
803
+ }
804
+ return true;
805
+ }
806
+ function isWithin(root, p) {
807
+ const rel = path__namespace.relative(root, p);
808
+ return rel === "" || !rel.startsWith(".." + path__namespace.sep) && rel !== ".." && !path__namespace.isAbsolute(rel);
809
+ }
810
+ const WALK_MAX_DEPTH = 40;
811
+ const WALK_MAX_ENTRIES = 5e4;
812
+ async function walk(root, rel, fn, signal) {
813
+ let remaining = WALK_MAX_ENTRIES;
814
+ async function inner(rel2, depth) {
815
+ if (depth > WALK_MAX_DEPTH)
816
+ return true;
817
+ if (signal?.aborted)
818
+ return false;
819
+ let entries;
820
+ try {
821
+ entries = await fs__namespace.readdir(path__namespace.join(root, rel2), { withFileTypes: true });
822
+ } catch {
823
+ return true;
824
+ }
825
+ for (const e of entries) {
826
+ if (e.name === ".git" || e.name === "node_modules")
827
+ continue;
828
+ if (remaining-- <= 0)
829
+ return false;
830
+ if (signal?.aborted)
831
+ return false;
832
+ const childRel = rel2 ? path__namespace.join(rel2, e.name) : e.name;
833
+ if (e.isDirectory()) {
834
+ if (!await inner(childRel, depth + 1))
835
+ return false;
836
+ } else if (e.isFile()) {
837
+ if (await fn(childRel) === false)
838
+ return false;
839
+ }
840
+ }
841
+ return true;
842
+ }
843
+ await inner(rel, 0);
844
+ }
845
+ async function findRg() {
846
+ const dirs = (process.env["PATH"] ?? "").split(path__namespace.delimiter);
847
+ for (const d of dirs) {
848
+ const candidate = path__namespace.join(d, "rg");
849
+ try {
850
+ await fs__namespace.access(candidate, fssync__namespace.constants.X_OK);
851
+ return candidate;
852
+ } catch {
853
+ }
854
+ }
855
+ return null;
856
+ }
857
+ exports.BashSession = BashSession;
858
+ exports.betaAgentToolset20260401 = betaAgentToolset20260401;
859
+ exports.betaBashTool = betaBashTool;
860
+ exports.betaEditTool = betaEditTool;
861
+ exports.betaGlobTool = betaGlobTool;
862
+ exports.betaGrepTool = betaGrepTool;
863
+ exports.betaReadTool = betaReadTool;
864
+ exports.betaWriteTool = betaWriteTool;
865
+ exports.extractSkillArchive = extractSkillArchive;
866
+ exports.resolvePath = resolvePath;
867
+ exports.resolveSkillVersion = resolveSkillVersion;
868
+ exports.setupSkills = setupSkills;