@midhunxavier/code-flow 0.0.0-stage → 0.1.0-preview.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (284) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +122 -2
  3. package/bin/codeflow.mjs +8 -0
  4. package/bin/launcher.mjs +127 -0
  5. package/dist/remote-host.json +1 -0
  6. package/licenses/inter.txt +92 -0
  7. package/licenses/preact.txt +21 -0
  8. package/licenses/signals-core.txt +21 -0
  9. package/licenses/signals.txt +21 -0
  10. package/licenses/typescript-notices.txt +193 -0
  11. package/licenses/typescript.txt +55 -0
  12. package/licenses/uqr.txt +22 -0
  13. package/licenses/xterm-fit.txt +19 -0
  14. package/licenses/xterm.txt +21 -0
  15. package/package.json +34 -4
  16. package/public/assets/browser-7XI52A6V.js +8 -0
  17. package/public/assets/changes-EYFPASEI.js +1 -0
  18. package/public/assets/chunk-7H3ZLTKA.js +2 -0
  19. package/public/assets/chunk-L7TUCIYF.js +1 -0
  20. package/public/assets/chunk-LLMQG23J.js +163 -0
  21. package/public/assets/main-KIRM2OEK.js +1 -0
  22. package/public/assets/settings-QJZVW22Y.js +9 -0
  23. package/public/assets/styles-615EBB20.css +32 -0
  24. package/public/assets/terminal-A2FI2NAX.js +62 -0
  25. package/public/assets.json +1 -0
  26. package/public/bundle-meta.json +1 -0
  27. package/public/docs/.nojekyll +0 -0
  28. package/public/docs/accessibility.html +19 -0
  29. package/public/docs/acp-agents.html +117 -0
  30. package/public/docs/agent-containers.html +79 -0
  31. package/public/docs/api.html +1130 -0
  32. package/public/docs/app.js +342 -0
  33. package/public/docs/application-improvements.html +275 -0
  34. package/public/docs/architecture-explorer.html +19 -0
  35. package/public/docs/architecture.html +149 -0
  36. package/public/docs/auto-team.html +142 -0
  37. package/public/docs/automations.html +109 -0
  38. package/public/docs/checkpoint-review.html +37 -0
  39. package/public/docs/code-hosts.html +35 -0
  40. package/public/docs/code-intelligence.html +35 -0
  41. package/public/docs/configuration.html +346 -0
  42. package/public/docs/context-inspection.html +23 -0
  43. package/public/docs/coordinated-changes.html +28 -0
  44. package/public/docs/deferred-runs.html +25 -0
  45. package/public/docs/dependency-discovery.html +19 -0
  46. package/public/docs/documentation.html +84 -0
  47. package/public/docs/dynamic-teams-evaluation.html +174 -0
  48. package/public/docs/dynamic-teams-implementation-plan.html +882 -0
  49. package/public/docs/dynamic-teams-implementation-review-1.html +141 -0
  50. package/public/docs/dynamic-teams-plan-review-0.html +204 -0
  51. package/public/docs/extensions.html +42 -0
  52. package/public/docs/external-sources.html +96 -0
  53. package/public/docs/filesystem-policy.html +26 -0
  54. package/public/docs/filtered-tasks.html +44 -0
  55. package/public/docs/font-license.txt +92 -0
  56. package/public/docs/getting-started.html +118 -0
  57. package/public/docs/github-review-threads.html +26 -0
  58. package/public/docs/github.html +157 -0
  59. package/public/docs/help.html +69 -0
  60. package/public/docs/index.html +77 -0
  61. package/public/docs/installation.html +74 -0
  62. package/public/docs/launch-profiles.html +48 -0
  63. package/public/docs/maintenance.html +60 -0
  64. package/public/docs/memory-claims.html +31 -0
  65. package/public/docs/memory-storage.html +58 -0
  66. package/public/docs/notifications.html +39 -0
  67. package/public/docs/patterns.html +195 -0
  68. package/public/docs/performance-results.html +210 -0
  69. package/public/docs/performance.html +166 -0
  70. package/public/docs/project-conventions.html +22 -0
  71. package/public/docs/project-first-navigation-plan.html +587 -0
  72. package/public/docs/project-teams-implementation-plan.html +772 -0
  73. package/public/docs/project-teams.html +99 -0
  74. package/public/docs/provider-compatibility.html +20 -0
  75. package/public/docs/releasing.html +61 -0
  76. package/public/docs/remote-workers.html +64 -0
  77. package/public/docs/review-inbox.html +26 -0
  78. package/public/docs/run-storage.html +23 -0
  79. package/public/docs/runs.html +141 -0
  80. package/public/docs/search.json +1 -0
  81. package/public/docs/security.html +133 -0
  82. package/public/docs/shared-projects.html +31 -0
  83. package/public/docs/ssh-projects.html +60 -0
  84. package/public/docs/style.css +768 -0
  85. package/public/docs/task-reruns.html +30 -0
  86. package/public/docs/team-collaboration.html +379 -0
  87. package/public/docs/verification.html +22 -0
  88. package/public/docs/vscode.html +53 -0
  89. package/public/docs/worker-permission-verification.html +122 -0
  90. package/public/index.html +17 -0
  91. package/scripts/check-node.mjs +7 -0
  92. package/scripts/codeflow.mjs +55 -0
  93. package/scripts/pty.py +273 -0
  94. package/src/acp-connections.js +110 -0
  95. package/src/adapters/acp-presets.js +37 -0
  96. package/src/adapters/acp-types.js +0 -0
  97. package/src/adapters/acp.js +328 -0
  98. package/src/adapters/agy-auth.js +67 -0
  99. package/src/adapters/agy-isolation.js +223 -0
  100. package/src/adapters/agy.js +297 -0
  101. package/src/adapters/claude.js +220 -0
  102. package/src/adapters/codex-app-server.js +518 -0
  103. package/src/adapters/codex.js +299 -0
  104. package/src/adapters/errors.js +57 -0
  105. package/src/adapters/index.js +91 -0
  106. package/src/adapters/managed-permissions.js +37 -0
  107. package/src/adapters/model-discovery.js +100 -0
  108. package/src/adapters/process.js +418 -0
  109. package/src/adapters/team-tools.js +102 -0
  110. package/src/adapters/types.js +0 -0
  111. package/src/agent-container.js +155 -0
  112. package/src/approvals.js +121 -0
  113. package/src/architecture.js +456 -0
  114. package/src/assets.js +44 -0
  115. package/src/automation.js +901 -0
  116. package/src/certificate-renewal.js +75 -0
  117. package/src/chat-handoff.js +55 -0
  118. package/src/checkpoint-review.js +72 -0
  119. package/src/checks.js +303 -0
  120. package/src/code-host-git.js +102 -0
  121. package/src/code-hosts-api.js +99 -0
  122. package/src/code-hosts.js +482 -0
  123. package/src/code-intelligence-worker.mjs +452 -0
  124. package/src/code-intelligence.js +141 -0
  125. package/src/collab/api.js +365 -0
  126. package/src/collab/checkpoints.js +198 -0
  127. package/src/collab/connections.js +139 -0
  128. package/src/collab/host-execution.js +347 -0
  129. package/src/collab/hub-client.js +210 -0
  130. package/src/collab/link-api.js +229 -0
  131. package/src/collab/link.js +595 -0
  132. package/src/collab/model.js +496 -0
  133. package/src/collab/runner.js +1014 -0
  134. package/src/collab/store.js +1452 -0
  135. package/src/collab/terminals.js +361 -0
  136. package/src/collaboration-reviews.js +116 -0
  137. package/src/config.js +48 -0
  138. package/src/context-budget.js +14 -0
  139. package/src/context-inspection.js +204 -0
  140. package/src/context.js +154 -0
  141. package/src/conventions.js +283 -0
  142. package/src/coordinated-api.js +247 -0
  143. package/src/deferred-launch.js +82 -0
  144. package/src/deferred-runs.js +515 -0
  145. package/src/dependency-health.js +35 -0
  146. package/src/diff.js +43 -0
  147. package/src/docs-help.js +316 -0
  148. package/src/doctor.js +232 -0
  149. package/src/engine.js +4366 -0
  150. package/src/env.js +44 -0
  151. package/src/experience.js +50 -0
  152. package/src/extensions.js +144 -0
  153. package/src/filesystem-access.js +107 -0
  154. package/src/filesystem-policy.js +238 -0
  155. package/src/filtered-task-limits.js +93 -0
  156. package/src/filtered-tasks-api.js +53 -0
  157. package/src/filtered-tasks.js +576 -0
  158. package/src/fs.js +57 -0
  159. package/src/git.js +626 -0
  160. package/src/github-review-threads.js +181 -0
  161. package/src/github.js +538 -0
  162. package/src/http.js +69 -0
  163. package/src/improve-settings.js +38 -0
  164. package/src/improve.js +187 -0
  165. package/src/integrations.js +373 -0
  166. package/src/integrity.js +259 -0
  167. package/src/journey-api.js +77 -0
  168. package/src/journey-replay.js +65 -0
  169. package/src/journey-store.js +97 -0
  170. package/src/journeys.js +60 -0
  171. package/src/json.js +81 -0
  172. package/src/launch-profiles.js +292 -0
  173. package/src/learnings.js +80 -0
  174. package/src/log.js +39 -0
  175. package/src/maintenance.js +335 -0
  176. package/src/memory-analysis.js +182 -0
  177. package/src/memory-claims.js +153 -0
  178. package/src/memory-sqlite.js +236 -0
  179. package/src/memory.js +552 -0
  180. package/src/merge-validation.js +58 -0
  181. package/src/model-catalog.js +238 -0
  182. package/src/model-research.js +91 -0
  183. package/src/notes.js +176 -0
  184. package/src/notifications.js +413 -0
  185. package/src/patterns/auto-team-model.js +212 -0
  186. package/src/patterns/auto-team.js +659 -0
  187. package/src/patterns/council.js +199 -0
  188. package/src/patterns/debate.js +188 -0
  189. package/src/patterns/findings.js +141 -0
  190. package/src/patterns/index.js +19 -0
  191. package/src/patterns/loop.js +158 -0
  192. package/src/patterns/pipeline.js +125 -0
  193. package/src/patterns/prompts.js +181 -0
  194. package/src/patterns/race.js +147 -0
  195. package/src/patterns/schemas.js +40 -0
  196. package/src/patterns/solo.js +49 -0
  197. package/src/patterns/supervisor.js +235 -0
  198. package/src/patterns/task-draft.js +29 -0
  199. package/src/patterns/tdd.js +231 -0
  200. package/src/patterns/team-strategies.js +67 -0
  201. package/src/performance.js +43 -0
  202. package/src/persistence-status.js +35 -0
  203. package/src/phone-sessions.js +96 -0
  204. package/src/preview-overlay.js +383 -0
  205. package/src/preview.js +219 -0
  206. package/src/privacy.js +23 -0
  207. package/src/project-report.js +22 -0
  208. package/src/project-team-model.js +178 -0
  209. package/src/project-team-policy.js +42 -0
  210. package/src/project-team-store.js +213 -0
  211. package/src/project-teams-api.js +36 -0
  212. package/src/project-teams.js +551 -0
  213. package/src/projects.js +286 -0
  214. package/src/provider-eligibility.js +9 -0
  215. package/src/readiness.js +98 -0
  216. package/src/remote-tls.js +66 -0
  217. package/src/remote-workers/bundles.js +198 -0
  218. package/src/remote-workers/client.js +332 -0
  219. package/src/remote-workers/durability.js +37 -0
  220. package/src/remote-workers/protocol.js +68 -0
  221. package/src/remote-workers/stdio.js +138 -0
  222. package/src/remote-workers/worker.js +304 -0
  223. package/src/remote.js +204 -0
  224. package/src/repo-config.js +201 -0
  225. package/src/repo-coordination.js +732 -0
  226. package/src/repo-tree.js +106 -0
  227. package/src/retention-policy.js +466 -0
  228. package/src/review-inbox.js +38 -0
  229. package/src/routing.js +49 -0
  230. package/src/run-analysis.js +111 -0
  231. package/src/run-cold-store.js +231 -0
  232. package/src/run-environment.js +15 -0
  233. package/src/run-history.js +91 -0
  234. package/src/run-log.js +160 -0
  235. package/src/run-permissions.js +110 -0
  236. package/src/run-projection.js +75 -0
  237. package/src/run-recovery.js +53 -0
  238. package/src/run-status.js +54 -0
  239. package/src/serve.js +138 -0
  240. package/src/server.js +2738 -0
  241. package/src/shared-access.js +103 -0
  242. package/src/shared-accounts.js +301 -0
  243. package/src/shared-api.js +239 -0
  244. package/src/shell.js +346 -0
  245. package/src/ship.js +344 -0
  246. package/src/slots.js +74 -0
  247. package/src/snapshot.js +388 -0
  248. package/src/source-context.js +17 -0
  249. package/src/sse-writer.js +70 -0
  250. package/src/ssh-projects/bootstrap.mjs +95 -0
  251. package/src/ssh-projects/config.js +45 -0
  252. package/src/ssh-projects/gateway.js +143 -0
  253. package/src/ssh-projects/manager.js +320 -0
  254. package/src/ssh-projects/team-autostart.mjs +93 -0
  255. package/src/ssh-projects/team-remove.mjs +69 -0
  256. package/src/ssh-projects/team-status.mjs +39 -0
  257. package/src/ssh-projects/transport.js +116 -0
  258. package/src/stats.js +139 -0
  259. package/src/store.js +544 -0
  260. package/src/stream.js +91 -0
  261. package/src/sweeps.js +241 -0
  262. package/src/tailscale.js +101 -0
  263. package/src/task-draft.js +23 -0
  264. package/src/team-evaluation.js +242 -0
  265. package/src/team-mailbox.js +160 -0
  266. package/src/team-memory.js +84 -0
  267. package/src/team-rerun-graph.js +15 -0
  268. package/src/team-reruns.js +130 -0
  269. package/src/team-scheduler.js +121 -0
  270. package/src/team-template-store.js +98 -0
  271. package/src/team-templates.js +117 -0
  272. package/src/team-tool-client.mjs +79 -0
  273. package/src/team-tools.js +176 -0
  274. package/src/teams.js +0 -0
  275. package/src/templates.js +62 -0
  276. package/src/transcript.js +134 -0
  277. package/src/verification-integrity.js +27 -0
  278. package/src/verification.js +183 -0
  279. package/src/watch.js +195 -0
  280. package/src/work-queue.js +47 -0
  281. package/src/workflow-control.js +83 -0
  282. package/src/workspace-api.js +207 -0
  283. package/src/workspace-changes.js +61 -0
  284. package/src/workspace.js +146 -0
@@ -0,0 +1,201 @@
1
+ import { closeSync, constants, existsSync, fstatSync, lstatSync, mkdirSync, openSync, readSync, realpathSync, renameSync, unlinkSync, writeSync } from "node:fs";
2
+ import { randomBytes } from "node:crypto";
3
+ import { lstat, readdir, readFile, realpath, writeFile } from "node:fs/promises";
4
+ import { basename, dirname, join, resolve, sep } from "node:path";
5
+ import { COPIED_FILES, git, gitWithInput, worktreeGit } from "./git.js";
6
+ const CONFIG_PATH = ".codeflow/config.json";
7
+ async function readRepoConfig(repo) {
8
+ const file = join(repo, CONFIG_PATH);
9
+ if (!existsSync(file)) return { config: {}, found: false };
10
+ try {
11
+ const raw = JSON.parse(await readFile(file, "utf8"));
12
+ const config = {};
13
+ const str = (v) => typeof v === "string" && v.trim() ? v.trim() : void 0;
14
+ config.check = str(raw.check);
15
+ config.setup = str(raw.setup);
16
+ if (Array.isArray(raw.copy)) config.copy = raw.copy.filter((p) => typeof p === "string" && !!p.trim());
17
+ if (raw.run && str(raw.run.command)) config.run = { command: str(raw.run.command), port: Number(raw.run.port) || void 0 };
18
+ if (raw.models && typeof raw.models === "object") config.models = raw.models;
19
+ if (raw.limits && typeof raw.limits === "object") {
20
+ const positive = (v) => Number.isFinite(Number(v)) && Number(v) > 0 ? Number(v) : void 0;
21
+ const steps = positive(raw.limits.maxSteps);
22
+ config.limits = { maxMinutes: positive(raw.limits.maxMinutes), maxSteps: steps === void 0 ? void 0 : Math.max(1, Math.round(steps)) };
23
+ }
24
+ if (["safe", "standard", "trusted"].includes(raw.trust)) config.trust = raw.trust;
25
+ if (typeof raw.image === "string" && /^[\w./:@-]{1,200}$/.test(raw.image.trim())) config.image = raw.image.trim();
26
+ if (typeof raw.learn === "boolean") config.learn = raw.learn;
27
+ if (typeof raw.prove === "boolean") config.prove = raw.prove;
28
+ return { config, found: true };
29
+ } catch (err) {
30
+ return { config: {}, found: true, error: `${CONFIG_PATH}: ${err.message}` };
31
+ }
32
+ }
33
+ async function copyIntoWorktree(repo, worktree, patterns) {
34
+ const copied = [];
35
+ const refused = [];
36
+ const root = await realpath(repo);
37
+ const destination = resolve(worktree);
38
+ const destinationRoot = await realpath(worktree);
39
+ const candidates = /* @__PURE__ */ new Set();
40
+ for (const raw of patterns) {
41
+ const pattern = raw.replace(/\\/g, "/").replace(/^\.\//, "");
42
+ if (!pattern || pattern.startsWith("/") || pattern.includes("\0") || pattern.split("/").some((part) => !part || part === ".." || part === ".")) continue;
43
+ for (const rel of await expand(repo, pattern)) {
44
+ const from = join(repo, rel);
45
+ const info = await lstat(from).catch(() => null);
46
+ if (!info) continue;
47
+ if (info.isSymbolicLink()) {
48
+ refused.push({ path: rel, why: "it's a symbolic link" });
49
+ continue;
50
+ }
51
+ if (!info.isFile()) continue;
52
+ const real = await realpath(from).catch(() => "");
53
+ if (!real.startsWith(root + sep)) {
54
+ refused.push({ path: rel, why: "it's outside the repository" });
55
+ continue;
56
+ }
57
+ candidates.add(rel);
58
+ }
59
+ }
60
+ const ignored = new Set(
61
+ candidates.size ? (await gitWithInput(["check-ignore", "--stdin", "-z"], repo, [...candidates].join("\0") + "\0")).stdout.split("\0").filter(Boolean) : []
62
+ );
63
+ for (const rel of candidates) {
64
+ if (!ignored.has(rel)) {
65
+ refused.push({ path: rel, why: "git doesn't ignore it, so it would be committed with the agents' work" });
66
+ continue;
67
+ }
68
+ const result = copyWithoutLinks(root, destination, destinationRoot, rel);
69
+ if (result === "copied") copied.push(rel);
70
+ else if (result !== "exists") refused.push({ path: rel, why: result });
71
+ }
72
+ await recordCopied(repo, worktree, copied);
73
+ return { copied, refused };
74
+ }
75
+ function copyWithoutLinks(sourceRoot, destination, destinationRoot, rel, opts = {}) {
76
+ let from;
77
+ let to;
78
+ let created;
79
+ const target = join(destinationRoot, rel);
80
+ let output = target;
81
+ try {
82
+ if (lstatSync(destination).isSymbolicLink() || !lstatSync(destination).isDirectory() || realpathSync(destination) !== destinationRoot) return "the worktree root is a symbolic link or has changed";
83
+ verifyParents(sourceRoot, dirname(opts.sourcePath ?? rel), false);
84
+ verifyParents(destinationRoot, dirname(rel), true);
85
+ const source = join(sourceRoot, opts.sourcePath ?? rel);
86
+ const sourceInfo = lstatSync(source);
87
+ if (sourceInfo.isSymbolicLink()) return "it's a symbolic link";
88
+ if (!sourceInfo.isFile() || !realpathSync(source).startsWith(sourceRoot + sep)) return "it's outside the repository or isn't a regular file";
89
+ from = openSync(source, constants.O_RDONLY | constants.O_NOFOLLOW);
90
+ if (!sameFile(sourceInfo, fstatSync(from))) return "the source file changed while preparing the copy";
91
+ const existing = statIfPresent(target);
92
+ if (existing?.isSymbolicLink()) return "the destination is a symbolic link";
93
+ if (existing && !existing.isFile()) return "the destination isn't a regular file";
94
+ if (existing && !opts.overwrite) return "exists";
95
+ if (opts.overwrite) output = `${target}.codeflow-copy-${randomBytes(10).toString("hex")}`;
96
+ to = openSync(output, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 384);
97
+ created = fstatSync(to);
98
+ verifyParents(destinationRoot, dirname(rel), false);
99
+ if (!sameFile(created, lstatSync(output))) throw new Error("the destination changed while preparing the copy");
100
+ const buffer = Buffer.allocUnsafe(64 * 1024);
101
+ let bytes;
102
+ while (bytes = readSync(from, buffer, 0, buffer.length, null)) {
103
+ let written = 0;
104
+ while (written < bytes) written += writeSync(to, buffer, written, bytes - written);
105
+ }
106
+ if (output !== target) {
107
+ closeSync(to);
108
+ to = void 0;
109
+ verifyParents(destinationRoot, dirname(rel), false);
110
+ if (statIfPresent(target)?.isSymbolicLink()) throw new Error("the destination is a symbolic link");
111
+ renameSync(output, target);
112
+ }
113
+ return "copied";
114
+ } catch (error) {
115
+ if (!created && error.code === "EEXIST") return "exists";
116
+ if (created && sameFile(created, statIfPresent(output))) {
117
+ try {
118
+ unlinkSync(output);
119
+ } catch {
120
+ }
121
+ }
122
+ return error.message;
123
+ } finally {
124
+ if (from !== void 0) closeSync(from);
125
+ if (to !== void 0) closeSync(to);
126
+ }
127
+ }
128
+ function verifyParents(root, relative, create) {
129
+ let path = root;
130
+ const expectedRoot = lstatSync(root);
131
+ if (!expectedRoot.isDirectory() || expectedRoot.isSymbolicLink()) throw new Error("the copy root is not a regular directory");
132
+ for (const part of relative === "." ? [] : relative.split(sep)) {
133
+ path = join(path, part);
134
+ if (create) {
135
+ try {
136
+ mkdirSync(path, { mode: 448 });
137
+ } catch (error) {
138
+ if (error.code !== "EEXIST") throw error;
139
+ }
140
+ }
141
+ const info = lstatSync(path);
142
+ if (info.isSymbolicLink()) throw new Error(`a parent directory is a symbolic link at \`${path.slice(root.length + 1).split(sep).join("/")}\``);
143
+ if (!info.isDirectory() || realpathSync(path) !== path) throw new Error("a parent directory is outside the copy root or isn't a directory");
144
+ }
145
+ if (!sameFile(expectedRoot, lstatSync(root))) throw new Error("the copy root changed while preparing the copy");
146
+ }
147
+ function statIfPresent(path) {
148
+ try {
149
+ return lstatSync(path);
150
+ } catch (error) {
151
+ if (error.code !== "ENOENT") throw error;
152
+ }
153
+ }
154
+ const sameFile = (a, b) => !!b && a.dev === b.dev && a.ino === b.ino;
155
+ async function recordCopied(repo, worktree, copied) {
156
+ if (!copied.length) return;
157
+ const at = await worktreeGit(repo, worktree).catch(() => void 0);
158
+ if (!at) return;
159
+ const res = await git(["rev-parse", "--git-path", COPIED_FILES], at);
160
+ if (res.code !== 0 || !res.stdout.trim()) return;
161
+ const file = resolve(worktree, res.stdout.trim());
162
+ const known = (await readFile(file, "utf8").catch(() => "")).split("\0").filter(Boolean);
163
+ await writeFile(file, [.../* @__PURE__ */ new Set([...known, ...copied])].map((p) => `${p}\0`).join(""));
164
+ }
165
+ async function copyFileInside(root, rel, from, opts = {}) {
166
+ const parts = rel.split(/[\\/]+/).filter((p) => p && p !== ".");
167
+ if (!parts.length || parts.includes("..") || /^[\\/]|^[a-z]:/i.test(rel)) return { copied: false, why: `\`${rel}\` isn't a path inside the worktree` };
168
+ try {
169
+ const [realRoot, sourceRoot] = await Promise.all([realpath(root), realpath(dirname(from))]);
170
+ const result = copyWithoutLinks(sourceRoot, resolve(root), realRoot, parts.join("/"), { sourcePath: basename(from), overwrite: opts.overwrite !== false });
171
+ return result === "copied" ? { copied: true } : { copied: false, ...result === "exists" ? {} : { why: result } };
172
+ } catch (error) {
173
+ return { copied: false, why: error.message };
174
+ }
175
+ }
176
+ async function expand(repo, pattern) {
177
+ if (!pattern.includes("*")) return [pattern];
178
+ const parts = pattern.split("/");
179
+ let current = [""];
180
+ for (const part of parts) {
181
+ const next = [];
182
+ for (const base of current) {
183
+ if (!part.includes("*")) {
184
+ next.push(base ? `${base}/${part}` : part);
185
+ continue;
186
+ }
187
+ const re = new RegExp(`^${part.split("*").map(escape).join("[^/]*")}$`);
188
+ const entries = await readdir(join(repo, base)).catch(() => []);
189
+ for (const e of entries) if (re.test(e)) next.push(base ? `${base}/${e}` : e);
190
+ }
191
+ current = next;
192
+ }
193
+ return current;
194
+ }
195
+ const escape = (s) => s.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
196
+ export {
197
+ CONFIG_PATH,
198
+ copyFileInside,
199
+ copyIntoWorktree,
200
+ readRepoConfig
201
+ };