unagent 0.0.3 → 0.0.4

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 (78) hide show
  1. package/dist/{git-BczcRFau.mjs → clone-DgXhqC05.mjs} +7 -86
  2. package/dist/context/index.d.mts +2 -0
  3. package/dist/context/index.mjs +3 -0
  4. package/dist/context-CAk5kS7q.mjs +59 -0
  5. package/dist/{env-BcNA2wGd.mjs → detect-CDtKsCsD.mjs} +1 -1
  6. package/dist/env/index.d.mts +1 -1
  7. package/dist/env/index.mjs +3 -2
  8. package/dist/env-DeXFcrWN.mjs +1 -0
  9. package/dist/exec/index.d.mts +2 -0
  10. package/dist/exec/index.mjs +3 -0
  11. package/dist/exec-Dzl5r4Ui.mjs +116 -0
  12. package/dist/fs/index.d.mts +2 -0
  13. package/dist/fs/index.mjs +3 -0
  14. package/dist/fs-nJz4v9pE.mjs +269 -0
  15. package/dist/git/index.d.mts +1 -1
  16. package/dist/git/index.mjs +2 -1
  17. package/dist/git-D3qsdy9d.mjs +86 -0
  18. package/dist/hooks/index.d.mts +3 -0
  19. package/dist/hooks/index.mjs +3 -0
  20. package/dist/hooks-335rp9Cp.mjs +9 -0
  21. package/dist/index-BZaywR9E.d.mts +97 -0
  22. package/dist/index-Bd1gSwMB.d.mts +31 -0
  23. package/dist/index-Bd4x_1H9.d.mts +33 -0
  24. package/dist/index-C0ulBa5T.d.mts +21 -0
  25. package/dist/index-Csv1G0zj.d.mts +36 -0
  26. package/dist/index-CvCCCs-_.d.mts +20 -0
  27. package/dist/index-D5A0wwzb.d.mts +55 -0
  28. package/dist/index-DFqD_DAh.d.mts +80 -0
  29. package/dist/index-DShEKmmL.d.mts +43 -0
  30. package/dist/index-DpFup4kC.d.mts +21 -0
  31. package/dist/index-ucMWydcs.d.mts +19 -0
  32. package/dist/index.d.mts +18 -8
  33. package/dist/index.mjs +23 -9
  34. package/dist/link/index.d.mts +1 -1
  35. package/dist/link/index.mjs +2 -1
  36. package/dist/link-BRZABZ3A.mjs +1 -0
  37. package/dist/lock/index.d.mts +1 -1
  38. package/dist/lock/index.mjs +1 -1
  39. package/dist/registry/index.d.mts +2 -0
  40. package/dist/registry/index.mjs +3 -0
  41. package/dist/registry-DvxT2enn.mjs +30 -0
  42. package/dist/sandbox/index.d.mts +2 -0
  43. package/dist/sandbox/index.mjs +3 -0
  44. package/dist/sandbox-Dyz9jTaL.mjs +139 -0
  45. package/dist/skill/index.d.mts +2 -2
  46. package/dist/skill/index.mjs +8 -2
  47. package/dist/skill-BnKVgm4n.mjs +358 -0
  48. package/dist/source/index.d.mts +1 -1
  49. package/dist/source/index.mjs +2 -1
  50. package/dist/source-BCRylzkW.mjs +1 -0
  51. package/dist/stop/index.d.mts +3 -0
  52. package/dist/stop/index.mjs +4 -0
  53. package/dist/stop-B9w8PiPj.mjs +39 -0
  54. package/dist/stream/index.d.mts +3 -0
  55. package/dist/stream/index.mjs +3 -0
  56. package/dist/stream-CzGvLSeV.mjs +99 -0
  57. package/dist/tool/index.d.mts +2 -0
  58. package/dist/tool/index.mjs +3 -0
  59. package/dist/tool-CESxMfOv.mjs +45 -0
  60. package/dist/usage/index.d.mts +2 -0
  61. package/dist/usage/index.mjs +3 -0
  62. package/dist/usage-DTaeWIUK.mjs +165 -0
  63. package/dist/utils/index.d.mts +1 -1
  64. package/dist/utils/index.mjs +2 -2
  65. package/package.json +64 -7
  66. package/dist/index-BT7sxFbS.d.mts +0 -47
  67. package/dist/skill-Bnz84tJ5.mjs +0 -125
  68. /package/dist/{index-C9yyPAid.d.mts → index-C55JaUgw.d.mts} +0 -0
  69. /package/dist/{index-CzPUtptc.d.mts → index-CbYchDwg.d.mts} +0 -0
  70. /package/dist/{index-1wm94iym.d.mts → index-Cy8LThTV.d.mts} +0 -0
  71. /package/dist/{index-Bzc-AUnz.d.mts → index-CzgY9GU2.d.mts} +0 -0
  72. /package/dist/{index-QWAv-PAT.d.mts → index-DPt7J0hF.d.mts} +0 -0
  73. /package/dist/{index-BMUPEJgp.d.mts → index-wTumcHrH.d.mts} +0 -0
  74. /package/dist/{lock-B07ZofNa.mjs → lock-CB9Xr9pv.mjs} +0 -0
  75. /package/dist/{source-uxXVyVOh.mjs → parse-CEbeorIB.mjs} +0 -0
  76. /package/dist/{path-D5oePhrf.mjs → path-Dm-URQvz.mjs} +0 -0
  77. /package/dist/{link-CnwXkdzo.mjs → symlink-CbP-heyc.mjs} +0 -0
  78. /package/dist/{utils-BpTrIde9.mjs → utils-bP3i6rq3.mjs} +0 -0
@@ -1,11 +1,11 @@
1
1
  import { existsSync, mkdirSync, rmSync } from "node:fs";
2
2
  import { tmpdir } from "node:os";
3
3
  import { join } from "pathe";
4
- import { execSync } from "node:child_process";
4
+ import { spawnSync } from "node:child_process";
5
5
 
6
6
  //#region src/git/_exec.ts
7
7
  function git(args, opts) {
8
- return execSync(`git ${args.join(" ")}`, {
8
+ const result = spawnSync("git", args, {
9
9
  cwd: opts?.cwd,
10
10
  timeout: opts?.timeout,
11
11
  encoding: "utf8",
@@ -14,7 +14,10 @@ function git(args, opts) {
14
14
  "pipe",
15
15
  "pipe"
16
16
  ]
17
- }).trim();
17
+ });
18
+ if (result.error) throw result.error;
19
+ if (result.status !== 0) throw new Error(result.stderr || `git ${args[0]} failed with code ${result.status}`);
20
+ return (result.stdout ?? "").trim();
18
21
  }
19
22
  function parseGitStatus(output) {
20
23
  const lines = output.split("\n").filter(Boolean);
@@ -98,86 +101,4 @@ function isTempDir(path) {
98
101
  }
99
102
 
100
103
  //#endregion
101
- //#region src/git/operations.ts
102
- function getGitStatus(dir) {
103
- if (!existsSync(dir)) return void 0;
104
- try {
105
- git(["rev-parse", "--is-inside-work-tree"], { cwd: dir });
106
- const parsed = parseGitStatus(git([
107
- "status",
108
- "--porcelain=v2",
109
- "--branch"
110
- ], { cwd: dir }));
111
- return {
112
- isRepo: true,
113
- branch: parsed.branch,
114
- ahead: parsed.ahead,
115
- behind: parsed.behind,
116
- staged: parsed.staged,
117
- modified: parsed.modified,
118
- untracked: parsed.untracked,
119
- hasChanges: parsed.staged.length > 0 || parsed.modified.length > 0 || parsed.untracked.length > 0
120
- };
121
- } catch {
122
- return;
123
- }
124
- }
125
- function getCurrentBranch(dir) {
126
- try {
127
- return git([
128
- "rev-parse",
129
- "--abbrev-ref",
130
- "HEAD"
131
- ], { cwd: dir });
132
- } catch {
133
- return;
134
- }
135
- }
136
- function checkout(dir, ref) {
137
- try {
138
- git(["checkout", ref], { cwd: dir });
139
- return true;
140
- } catch {
141
- return false;
142
- }
143
- }
144
- function pull(dir) {
145
- try {
146
- git(["pull"], { cwd: dir });
147
- return true;
148
- } catch {
149
- return false;
150
- }
151
- }
152
- function fetch(dir, remote = "origin") {
153
- try {
154
- git(["fetch", remote], { cwd: dir });
155
- return true;
156
- } catch {
157
- return false;
158
- }
159
- }
160
- function getRemoteUrl(dir, remote = "origin") {
161
- try {
162
- return git([
163
- "remote",
164
- "get-url",
165
- remote
166
- ], { cwd: dir });
167
- } catch {
168
- return;
169
- }
170
- }
171
- function getLatestCommitHash(dir) {
172
- try {
173
- return git(["rev-parse", "HEAD"], { cwd: dir });
174
- } catch {
175
- return;
176
- }
177
- }
178
- function hasUncommittedChanges(dir) {
179
- return getGitStatus(dir)?.hasChanges ?? false;
180
- }
181
-
182
- //#endregion
183
- export { getLatestCommitHash as a, pull as c, cloneRepo as d, cloneToTemp as f, getGitStatus as i, GitCloneError as l, fetch as n, getRemoteUrl as o, isTempDir as p, getCurrentBranch as r, hasUncommittedChanges as s, checkout as t, cleanupTempDir as u };
104
+ export { isTempDir as a, cloneToTemp as i, cleanupTempDir as n, git as o, cloneRepo as r, parseGitStatus as s, GitCloneError as t };
@@ -0,0 +1,2 @@
1
+ import { a as TruncateOptions, c as splitByTokens, i as TokenEstimateOptions, l as truncateToFit, n as BuildContextResult, o as buildContext, r as ContextItem, s as estimateTokens, t as BuildContextOptions } from "../index-Bd1gSwMB.mjs";
2
+ export { BuildContextOptions, BuildContextResult, ContextItem, TokenEstimateOptions, TruncateOptions, buildContext, estimateTokens, splitByTokens, truncateToFit };
@@ -0,0 +1,3 @@
1
+ import { i as truncateToFit, n as estimateTokens, r as splitByTokens, t as buildContext } from "../context-CAk5kS7q.mjs";
2
+
3
+ export { buildContext, estimateTokens, splitByTokens, truncateToFit };
@@ -0,0 +1,59 @@
1
+ //#region src/context/index.ts
2
+ const CHARS_PER_TOKEN = 4;
3
+ function estimateTokens(text, options = {}) {
4
+ const { charsPerToken = CHARS_PER_TOKEN } = options;
5
+ return Math.ceil(text.length / charsPerToken);
6
+ }
7
+ function truncateToFit(content, options) {
8
+ const { maxTokens, charsPerToken = CHARS_PER_TOKEN, suffix = "\n...[truncated]" } = options;
9
+ const maxChars = maxTokens * charsPerToken;
10
+ if (content.length <= maxChars) return content;
11
+ const truncateAt = maxChars - suffix.length;
12
+ if (truncateAt <= 0) return suffix.slice(0, maxChars);
13
+ return content.slice(0, truncateAt) + suffix;
14
+ }
15
+ function buildContext(items, options) {
16
+ const { maxTokens, charsPerToken = CHARS_PER_TOKEN, separator = "\n\n" } = options;
17
+ const maxChars = maxTokens * charsPerToken;
18
+ const sorted = [...items].sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
19
+ const included = [];
20
+ const excluded = [];
21
+ const parts = [];
22
+ let currentChars = 0;
23
+ for (let i = 0; i < sorted.length; i++) {
24
+ const item = sorted[i];
25
+ const itemChars = item.content.length;
26
+ const separatorChars = parts.length > 0 ? separator.length : 0;
27
+ const totalChars = currentChars + itemChars + separatorChars;
28
+ if (totalChars <= maxChars) {
29
+ parts.push(item.content);
30
+ currentChars = totalChars;
31
+ included.push(item.id ?? `item-${i}`);
32
+ } else excluded.push(item.id ?? `item-${i}`);
33
+ }
34
+ return {
35
+ content: parts.join(separator),
36
+ tokens: estimateTokens(parts.join(separator), { charsPerToken }),
37
+ included,
38
+ excluded
39
+ };
40
+ }
41
+ function splitByTokens(text, maxTokensPerChunk, options = {}) {
42
+ const { charsPerToken = CHARS_PER_TOKEN } = options;
43
+ const maxChars = maxTokensPerChunk * charsPerToken;
44
+ const chunks = [];
45
+ let start = 0;
46
+ while (start < text.length) {
47
+ let end = Math.min(start + maxChars, text.length);
48
+ if (end < text.length) {
49
+ const newlineIdx = text.lastIndexOf("\n", end);
50
+ if (newlineIdx > start) end = newlineIdx + 1;
51
+ }
52
+ chunks.push(text.slice(start, end));
53
+ start = end;
54
+ }
55
+ return chunks;
56
+ }
57
+
58
+ //#endregion
59
+ export { truncateToFit as i, estimateTokens as n, splitByTokens as r, buildContext as t };
@@ -1,4 +1,4 @@
1
- import { t as expandPath } from "./path-D5oePhrf.mjs";
1
+ import { t as expandPath } from "./path-Dm-URQvz.mjs";
2
2
  import { existsSync } from "node:fs";
3
3
  import { homedir } from "node:os";
4
4
  import { join } from "pathe";
@@ -1,2 +1,2 @@
1
- import { _ as getAgentConfig, a as getAgentSkillsDir, c as isCI, d as detectAgentByEnv, f as detectCurrentAgent, g as agents, h as AgentConfig, i as getAgentRulesPath, l as isTTY, m as isRunningInAgent, n as agentConfigExists, o as getXDGPaths, p as detectInstalledAgents, r as getAgentConfigDir, s as hasTTY, t as XDGPaths, u as DetectedAgent, v as getAgentIds, y as getAllAgents } from "../index-Bzc-AUnz.mjs";
1
+ import { _ as getAgentConfig, a as getAgentSkillsDir, c as isCI, d as detectAgentByEnv, f as detectCurrentAgent, g as agents, h as AgentConfig, i as getAgentRulesPath, l as isTTY, m as isRunningInAgent, n as agentConfigExists, o as getXDGPaths, p as detectInstalledAgents, r as getAgentConfigDir, s as hasTTY, t as XDGPaths, u as DetectedAgent, v as getAgentIds, y as getAllAgents } from "../index-CzgY9GU2.mjs";
2
2
  export { AgentConfig, DetectedAgent, XDGPaths, agentConfigExists, agents, detectAgentByEnv, detectCurrentAgent, detectInstalledAgents, getAgentConfig, getAgentConfigDir, getAgentIds, getAgentRulesPath, getAgentSkillsDir, getAllAgents, getXDGPaths, hasTTY, isCI, isRunningInAgent, isTTY };
@@ -1,4 +1,5 @@
1
- import { a as agentConfigExists, c as getAgentSkillsDir, d as isCI, f as isTTY, g as getAllAgents, h as getAgentIds, i as isRunningInAgent, l as getXDGPaths, m as getAgentConfig, n as detectCurrentAgent, o as getAgentConfigDir, p as agents, r as detectInstalledAgents, s as getAgentRulesPath, t as detectAgentByEnv, u as hasTTY } from "../env-BcNA2wGd.mjs";
2
- import "../path-D5oePhrf.mjs";
1
+ import { a as agentConfigExists, c as getAgentSkillsDir, d as isCI, f as isTTY, g as getAllAgents, h as getAgentIds, i as isRunningInAgent, l as getXDGPaths, m as getAgentConfig, n as detectCurrentAgent, o as getAgentConfigDir, p as agents, r as detectInstalledAgents, s as getAgentRulesPath, t as detectAgentByEnv, u as hasTTY } from "../detect-CDtKsCsD.mjs";
2
+ import "../path-Dm-URQvz.mjs";
3
+ import "../env-DeXFcrWN.mjs";
3
4
 
4
5
  export { agentConfigExists, agents, detectAgentByEnv, detectCurrentAgent, detectInstalledAgents, getAgentConfig, getAgentConfigDir, getAgentIds, getAgentRulesPath, getAgentSkillsDir, getAllAgents, getXDGPaths, hasTTY, isCI, isRunningInAgent, isTTY };
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,2 @@
1
+ import { i as execSafeSync, n as ExecResult, r as execSafe, t as ExecOptions } from "../index-C0ulBa5T.mjs";
2
+ export { ExecOptions, ExecResult, execSafe, execSafeSync };
@@ -0,0 +1,3 @@
1
+ import { n as execSafeSync, t as execSafe } from "../exec-Dzl5r4Ui.mjs";
2
+
3
+ export { execSafe, execSafeSync };
@@ -0,0 +1,116 @@
1
+ import { spawn, spawnSync } from "node:child_process";
2
+
3
+ //#region src/exec/index.ts
4
+ const DEFAULT_TIMEOUT = 3e4;
5
+ const DEFAULT_MAX_OUTPUT = 1e5;
6
+ function execSafe(command, args, options = {}) {
7
+ const { cwd, timeout = DEFAULT_TIMEOUT, maxOutput = DEFAULT_MAX_OUTPUT, env, stdin } = options;
8
+ return new Promise((resolve) => {
9
+ let stdout = "";
10
+ let stderr = "";
11
+ let truncated = false;
12
+ let timedOut = false;
13
+ let timeoutId;
14
+ const proc = spawn(command, args, {
15
+ cwd,
16
+ env: env ? {
17
+ ...process.env,
18
+ ...env
19
+ } : process.env,
20
+ stdio: [
21
+ "pipe",
22
+ "pipe",
23
+ "pipe"
24
+ ]
25
+ });
26
+ const truncateOutput = (current, chunk) => {
27
+ const combined = current + chunk;
28
+ if (combined.length > maxOutput) {
29
+ truncated = true;
30
+ return combined.slice(0, maxOutput);
31
+ }
32
+ return combined;
33
+ };
34
+ proc.stdout?.on("data", (chunk) => {
35
+ stdout = truncateOutput(stdout, chunk.toString());
36
+ });
37
+ proc.stderr?.on("data", (chunk) => {
38
+ stderr = truncateOutput(stderr, chunk.toString());
39
+ });
40
+ if (stdin !== void 0) {
41
+ proc.stdin?.write(stdin);
42
+ proc.stdin?.end();
43
+ } else proc.stdin?.end();
44
+ if (timeout > 0) timeoutId = setTimeout(() => {
45
+ timedOut = true;
46
+ proc.kill("SIGTERM");
47
+ setTimeout(() => proc.kill("SIGKILL"), 1e3);
48
+ }, timeout);
49
+ proc.on("close", (code, signal) => {
50
+ if (timeoutId) clearTimeout(timeoutId);
51
+ resolve({
52
+ ok: code === 0,
53
+ code,
54
+ stdout: stdout.trim(),
55
+ stderr: stderr.trim(),
56
+ signal: signal ?? null,
57
+ truncated,
58
+ timedOut
59
+ });
60
+ });
61
+ proc.on("error", (err) => {
62
+ if (timeoutId) clearTimeout(timeoutId);
63
+ resolve({
64
+ ok: false,
65
+ code: null,
66
+ stdout: stdout.trim(),
67
+ stderr: err.message,
68
+ signal: null,
69
+ truncated,
70
+ timedOut
71
+ });
72
+ });
73
+ });
74
+ }
75
+ function execSafeSync(command, args, options = {}) {
76
+ const { cwd, timeout = DEFAULT_TIMEOUT, maxOutput = DEFAULT_MAX_OUTPUT, env } = options;
77
+ let truncated = false;
78
+ const result = spawnSync(command, args, {
79
+ cwd,
80
+ timeout,
81
+ env: env ? {
82
+ ...process.env,
83
+ ...env
84
+ } : process.env,
85
+ encoding: "utf8",
86
+ stdio: [
87
+ "pipe",
88
+ "pipe",
89
+ "pipe"
90
+ ],
91
+ maxBuffer: maxOutput * 2
92
+ });
93
+ const timedOut = result.signal === "SIGTERM";
94
+ let stdout = result.stdout ?? "";
95
+ let stderr = result.stderr ?? "";
96
+ if (stdout.length > maxOutput) {
97
+ stdout = stdout.slice(0, maxOutput);
98
+ truncated = true;
99
+ }
100
+ if (stderr.length > maxOutput) {
101
+ stderr = stderr.slice(0, maxOutput);
102
+ truncated = true;
103
+ }
104
+ return {
105
+ ok: result.status === 0,
106
+ code: result.status,
107
+ stdout: stdout.trim(),
108
+ stderr: stderr.trim(),
109
+ signal: result.signal ?? null,
110
+ truncated,
111
+ timedOut
112
+ };
113
+ }
114
+
115
+ //#endregion
116
+ export { execSafeSync as n, execSafe as t };
@@ -0,0 +1,2 @@
1
+ import { a as Storage, i as RealFS, n as InMemoryFS, o as VirtualFS, r as OverlayFS, s as createFSFromStorage, t as FileStat } from "../index-DFqD_DAh.mjs";
2
+ export { FileStat, InMemoryFS, OverlayFS, RealFS, Storage, VirtualFS, createFSFromStorage };
@@ -0,0 +1,3 @@
1
+ import { i as createFSFromStorage, n as OverlayFS, r as RealFS, t as InMemoryFS } from "../fs-nJz4v9pE.mjs";
2
+
3
+ export { InMemoryFS, OverlayFS, RealFS, createFSFromStorage };
@@ -0,0 +1,269 @@
1
+ import { dirname, join, normalize } from "pathe";
2
+ import * as nodeFs from "node:fs/promises";
3
+
4
+ //#region src/fs/index.ts
5
+ function ensureLeadingSlash(path) {
6
+ return path.startsWith("/") ? path : `/${path}`;
7
+ }
8
+ var InMemoryFS = class {
9
+ files = /* @__PURE__ */ new Map();
10
+ dirs = new Set(["/"]);
11
+ normalizePath(path) {
12
+ return ensureLeadingSlash(path);
13
+ }
14
+ async readFile(path) {
15
+ const p = this.normalizePath(path);
16
+ const content = this.files.get(p);
17
+ if (content === void 0) throw new Error(`ENOENT: no such file: ${p}`);
18
+ return content;
19
+ }
20
+ async writeFile(path, content) {
21
+ const p = this.normalizePath(path);
22
+ const dir = dirname(p);
23
+ if (dir !== "/" && !this.dirs.has(dir)) throw new Error(`ENOENT: no such directory: ${dir}`);
24
+ this.files.set(p, content);
25
+ }
26
+ async exists(path) {
27
+ const p = this.normalizePath(path);
28
+ return this.files.has(p) || this.dirs.has(p);
29
+ }
30
+ async readdir(path) {
31
+ const p = this.normalizePath(path);
32
+ if (!this.dirs.has(p)) throw new Error(`ENOENT: no such directory: ${p}`);
33
+ const entries = /* @__PURE__ */ new Set();
34
+ const prefix = p === "/" ? "/" : `${p}/`;
35
+ for (const filePath of this.files.keys()) if (filePath.startsWith(prefix)) {
36
+ const name = filePath.slice(prefix.length).split("/")[0];
37
+ if (name) entries.add(name);
38
+ }
39
+ for (const dirPath of this.dirs) if (dirPath.startsWith(prefix) && dirPath !== p) {
40
+ const name = dirPath.slice(prefix.length).split("/")[0];
41
+ if (name) entries.add(name);
42
+ }
43
+ return [...entries];
44
+ }
45
+ async mkdir(path, options) {
46
+ const p = this.normalizePath(path);
47
+ if (this.dirs.has(p)) return;
48
+ if (options?.recursive) {
49
+ const parts = p.split("/").filter(Boolean);
50
+ let current = "";
51
+ for (const part of parts) {
52
+ current += `/${part}`;
53
+ this.dirs.add(current);
54
+ }
55
+ } else {
56
+ const parent = dirname(p);
57
+ if (parent !== "/" && !this.dirs.has(parent)) throw new Error(`ENOENT: no such directory: ${parent}`);
58
+ this.dirs.add(p);
59
+ }
60
+ }
61
+ async rm(path, options) {
62
+ const p = this.normalizePath(path);
63
+ if (this.files.has(p)) {
64
+ this.files.delete(p);
65
+ return;
66
+ }
67
+ if (!this.dirs.has(p)) throw new Error(`ENOENT: no such file or directory: ${p}`);
68
+ const prefix = p === "/" ? "/" : `${p}/`;
69
+ if (([...this.files.keys()].some((f) => f.startsWith(prefix)) || [...this.dirs].some((d) => d.startsWith(prefix) && d !== p)) && !options?.recursive) throw new Error(`ENOTEMPTY: directory not empty: ${p}`);
70
+ for (const filePath of this.files.keys()) if (filePath.startsWith(prefix)) this.files.delete(filePath);
71
+ for (const dirPath of this.dirs) if (dirPath.startsWith(prefix) || dirPath === p) this.dirs.delete(dirPath);
72
+ }
73
+ async stat(path) {
74
+ const p = this.normalizePath(path);
75
+ if (this.files.has(p)) return {
76
+ size: this.files.get(p).length,
77
+ isFile: true,
78
+ isDirectory: false
79
+ };
80
+ if (this.dirs.has(p)) return {
81
+ size: 0,
82
+ isFile: false,
83
+ isDirectory: true
84
+ };
85
+ throw new Error(`ENOENT: no such file or directory: ${p}`);
86
+ }
87
+ };
88
+ var OverlayFS = class {
89
+ overlay;
90
+ deleted = /* @__PURE__ */ new Set();
91
+ constructor(base) {
92
+ this.base = base;
93
+ this.overlay = new InMemoryFS();
94
+ }
95
+ normalizePath(path) {
96
+ return ensureLeadingSlash(path);
97
+ }
98
+ async readFile(path) {
99
+ const p = this.normalizePath(path);
100
+ if (this.deleted.has(p)) throw new Error(`ENOENT: no such file: ${p}`);
101
+ try {
102
+ return await this.overlay.readFile(p);
103
+ } catch {
104
+ return await this.base.readFile(p);
105
+ }
106
+ }
107
+ async writeFile(path, content) {
108
+ const p = this.normalizePath(path);
109
+ this.deleted.delete(p);
110
+ const dir = dirname(p);
111
+ if (dir !== "/") try {
112
+ await this.overlay.mkdir(dir, { recursive: true });
113
+ } catch {}
114
+ await this.overlay.writeFile(p, content);
115
+ }
116
+ async exists(path) {
117
+ const p = this.normalizePath(path);
118
+ if (this.deleted.has(p)) return false;
119
+ if (await this.overlay.exists(p)) return true;
120
+ return await this.base.exists(p);
121
+ }
122
+ async readdir(path) {
123
+ const p = this.normalizePath(path);
124
+ const entries = /* @__PURE__ */ new Set();
125
+ try {
126
+ for (const e of await this.base.readdir(p)) entries.add(e);
127
+ } catch {}
128
+ try {
129
+ for (const e of await this.overlay.readdir(p)) entries.add(e);
130
+ } catch {}
131
+ for (const deleted of this.deleted) {
132
+ const prefix = p === "/" ? "/" : `${p}/`;
133
+ if (deleted.startsWith(prefix)) {
134
+ const name = deleted.slice(prefix.length).split("/")[0];
135
+ if (name && !deleted.slice(prefix.length).includes("/")) entries.delete(name);
136
+ }
137
+ }
138
+ return [...entries];
139
+ }
140
+ async mkdir(path, options) {
141
+ const p = this.normalizePath(path);
142
+ this.deleted.delete(p);
143
+ await this.overlay.mkdir(p, options);
144
+ }
145
+ async rm(path, options) {
146
+ const p = this.normalizePath(path);
147
+ try {
148
+ await this.overlay.rm(p, options);
149
+ } catch {}
150
+ this.deleted.add(p);
151
+ if (options?.recursive) {
152
+ const prefix = p === "/" ? "/" : `${p}/`;
153
+ for (const deleted of [...this.deleted]) if (deleted.startsWith(prefix)) this.deleted.add(deleted);
154
+ }
155
+ }
156
+ async stat(path) {
157
+ const p = this.normalizePath(path);
158
+ if (this.deleted.has(p)) throw new Error(`ENOENT: no such file or directory: ${p}`);
159
+ try {
160
+ return await this.overlay.stat(p);
161
+ } catch {
162
+ return await this.base.stat(p);
163
+ }
164
+ }
165
+ };
166
+ var RealFS = class {
167
+ normalizedBase;
168
+ constructor(basePath = "/") {
169
+ this.basePath = basePath;
170
+ this.normalizedBase = normalize(basePath);
171
+ }
172
+ resolve(path) {
173
+ const resolved = normalize(join(this.basePath, path));
174
+ if (!resolved.startsWith(this.normalizedBase) && resolved !== this.normalizedBase) throw new Error(`EACCES: path traversal not allowed: ${path}`);
175
+ return resolved;
176
+ }
177
+ async readFile(path) {
178
+ return await nodeFs.readFile(this.resolve(path), "utf-8");
179
+ }
180
+ async writeFile(path, content) {
181
+ await nodeFs.writeFile(this.resolve(path), content, "utf-8");
182
+ }
183
+ async exists(path) {
184
+ try {
185
+ await nodeFs.access(this.resolve(path));
186
+ return true;
187
+ } catch {
188
+ return false;
189
+ }
190
+ }
191
+ async readdir(path) {
192
+ return await nodeFs.readdir(this.resolve(path));
193
+ }
194
+ async mkdir(path, options) {
195
+ await nodeFs.mkdir(this.resolve(path), options);
196
+ }
197
+ async rm(path, options) {
198
+ await nodeFs.rm(this.resolve(path), options);
199
+ }
200
+ async stat(path) {
201
+ const stats = await nodeFs.stat(this.resolve(path));
202
+ return {
203
+ size: stats.size,
204
+ isFile: stats.isFile(),
205
+ isDirectory: stats.isDirectory(),
206
+ mtime: stats.mtime
207
+ };
208
+ }
209
+ };
210
+ function createFSFromStorage(storage) {
211
+ const dirs = new Set(["/"]);
212
+ return {
213
+ async readFile(path) {
214
+ const content = await storage.getItem(path);
215
+ if (content === null) throw new Error(`ENOENT: no such file: ${path}`);
216
+ return content;
217
+ },
218
+ async writeFile(path, content) {
219
+ const dir = dirname(path);
220
+ if (dir !== "/") dirs.add(dir);
221
+ await storage.setItem(path, content);
222
+ },
223
+ async exists(path) {
224
+ if (dirs.has(path)) return true;
225
+ return await storage.getItem(path) !== null;
226
+ },
227
+ async readdir(path) {
228
+ const keys = await storage.getKeys(path);
229
+ const prefix = path === "/" ? "" : path;
230
+ const entries = /* @__PURE__ */ new Set();
231
+ for (const key of keys) if (key.startsWith(prefix)) {
232
+ const name = key.slice(prefix.length).replace(/^\//, "").split("/")[0];
233
+ if (name) entries.add(name);
234
+ }
235
+ return [...entries];
236
+ },
237
+ async mkdir(path, options) {
238
+ if (options?.recursive) {
239
+ const parts = path.split("/").filter(Boolean);
240
+ let current = "";
241
+ for (const part of parts) {
242
+ current += `/${part}`;
243
+ dirs.add(current);
244
+ }
245
+ } else dirs.add(path);
246
+ },
247
+ async rm(path) {
248
+ await storage.removeItem(path);
249
+ dirs.delete(path);
250
+ },
251
+ async stat(path) {
252
+ if (dirs.has(path)) return {
253
+ size: 0,
254
+ isFile: false,
255
+ isDirectory: true
256
+ };
257
+ const content = await storage.getItem(path);
258
+ if (content === null) throw new Error(`ENOENT: no such file or directory: ${path}`);
259
+ return {
260
+ size: content.length,
261
+ isFile: true,
262
+ isDirectory: false
263
+ };
264
+ }
265
+ };
266
+ }
267
+
268
+ //#endregion
269
+ export { createFSFromStorage as i, OverlayFS as n, RealFS as r, InMemoryFS as t };
@@ -1,2 +1,2 @@
1
- import { a as getGitStatus, c as hasUncommittedChanges, d as CloneResult, f as GitCloneError, g as isTempDir, h as cloneToTemp, i as getCurrentBranch, l as pull, m as cloneRepo, n as checkout, o as getLatestCommitHash, p as cleanupTempDir, r as fetch, s as getRemoteUrl, t as GitStatus, u as CloneOptions } from "../index-C9yyPAid.mjs";
1
+ import { a as getGitStatus, c as hasUncommittedChanges, d as CloneResult, f as GitCloneError, g as isTempDir, h as cloneToTemp, i as getCurrentBranch, l as pull, m as cloneRepo, n as checkout, o as getLatestCommitHash, p as cleanupTempDir, r as fetch, s as getRemoteUrl, t as GitStatus, u as CloneOptions } from "../index-C55JaUgw.mjs";
2
2
  export { CloneOptions, CloneResult, GitCloneError, GitStatus, checkout, cleanupTempDir, cloneRepo, cloneToTemp, fetch, getCurrentBranch, getGitStatus, getLatestCommitHash, getRemoteUrl, hasUncommittedChanges, isTempDir, pull };
@@ -1,3 +1,4 @@
1
- import { a as getLatestCommitHash, c as pull, d as cloneRepo, f as cloneToTemp, i as getGitStatus, l as GitCloneError, n as fetch, o as getRemoteUrl, p as isTempDir, r as getCurrentBranch, s as hasUncommittedChanges, t as checkout, u as cleanupTempDir } from "../git-BczcRFau.mjs";
1
+ import { a as isTempDir, i as cloneToTemp, n as cleanupTempDir, r as cloneRepo, t as GitCloneError } from "../clone-DgXhqC05.mjs";
2
+ import { a as getLatestCommitHash, c as pull, i as getGitStatus, n as fetch, o as getRemoteUrl, r as getCurrentBranch, s as hasUncommittedChanges, t as checkout } from "../git-D3qsdy9d.mjs";
2
3
 
3
4
  export { GitCloneError, checkout, cleanupTempDir, cloneRepo, cloneToTemp, fetch, getCurrentBranch, getGitStatus, getLatestCommitHash, getRemoteUrl, hasUncommittedChanges, isTempDir, pull };