@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.
- package/LICENSE +21 -0
- package/README.md +122 -2
- package/bin/codeflow.mjs +8 -0
- package/bin/launcher.mjs +127 -0
- package/dist/remote-host.json +1 -0
- package/licenses/inter.txt +92 -0
- package/licenses/preact.txt +21 -0
- package/licenses/signals-core.txt +21 -0
- package/licenses/signals.txt +21 -0
- package/licenses/typescript-notices.txt +193 -0
- package/licenses/typescript.txt +55 -0
- package/licenses/uqr.txt +22 -0
- package/licenses/xterm-fit.txt +19 -0
- package/licenses/xterm.txt +21 -0
- package/package.json +34 -4
- package/public/assets/browser-7XI52A6V.js +8 -0
- package/public/assets/changes-EYFPASEI.js +1 -0
- package/public/assets/chunk-7H3ZLTKA.js +2 -0
- package/public/assets/chunk-L7TUCIYF.js +1 -0
- package/public/assets/chunk-LLMQG23J.js +163 -0
- package/public/assets/main-KIRM2OEK.js +1 -0
- package/public/assets/settings-QJZVW22Y.js +9 -0
- package/public/assets/styles-615EBB20.css +32 -0
- package/public/assets/terminal-A2FI2NAX.js +62 -0
- package/public/assets.json +1 -0
- package/public/bundle-meta.json +1 -0
- package/public/docs/.nojekyll +0 -0
- package/public/docs/accessibility.html +19 -0
- package/public/docs/acp-agents.html +117 -0
- package/public/docs/agent-containers.html +79 -0
- package/public/docs/api.html +1130 -0
- package/public/docs/app.js +342 -0
- package/public/docs/application-improvements.html +275 -0
- package/public/docs/architecture-explorer.html +19 -0
- package/public/docs/architecture.html +149 -0
- package/public/docs/auto-team.html +142 -0
- package/public/docs/automations.html +109 -0
- package/public/docs/checkpoint-review.html +37 -0
- package/public/docs/code-hosts.html +35 -0
- package/public/docs/code-intelligence.html +35 -0
- package/public/docs/configuration.html +346 -0
- package/public/docs/context-inspection.html +23 -0
- package/public/docs/coordinated-changes.html +28 -0
- package/public/docs/deferred-runs.html +25 -0
- package/public/docs/dependency-discovery.html +19 -0
- package/public/docs/documentation.html +84 -0
- package/public/docs/dynamic-teams-evaluation.html +174 -0
- package/public/docs/dynamic-teams-implementation-plan.html +882 -0
- package/public/docs/dynamic-teams-implementation-review-1.html +141 -0
- package/public/docs/dynamic-teams-plan-review-0.html +204 -0
- package/public/docs/extensions.html +42 -0
- package/public/docs/external-sources.html +96 -0
- package/public/docs/filesystem-policy.html +26 -0
- package/public/docs/filtered-tasks.html +44 -0
- package/public/docs/font-license.txt +92 -0
- package/public/docs/getting-started.html +118 -0
- package/public/docs/github-review-threads.html +26 -0
- package/public/docs/github.html +157 -0
- package/public/docs/help.html +69 -0
- package/public/docs/index.html +77 -0
- package/public/docs/installation.html +74 -0
- package/public/docs/launch-profiles.html +48 -0
- package/public/docs/maintenance.html +60 -0
- package/public/docs/memory-claims.html +31 -0
- package/public/docs/memory-storage.html +58 -0
- package/public/docs/notifications.html +39 -0
- package/public/docs/patterns.html +195 -0
- package/public/docs/performance-results.html +210 -0
- package/public/docs/performance.html +166 -0
- package/public/docs/project-conventions.html +22 -0
- package/public/docs/project-first-navigation-plan.html +587 -0
- package/public/docs/project-teams-implementation-plan.html +772 -0
- package/public/docs/project-teams.html +99 -0
- package/public/docs/provider-compatibility.html +20 -0
- package/public/docs/releasing.html +61 -0
- package/public/docs/remote-workers.html +64 -0
- package/public/docs/review-inbox.html +26 -0
- package/public/docs/run-storage.html +23 -0
- package/public/docs/runs.html +141 -0
- package/public/docs/search.json +1 -0
- package/public/docs/security.html +133 -0
- package/public/docs/shared-projects.html +31 -0
- package/public/docs/ssh-projects.html +60 -0
- package/public/docs/style.css +768 -0
- package/public/docs/task-reruns.html +30 -0
- package/public/docs/team-collaboration.html +379 -0
- package/public/docs/verification.html +22 -0
- package/public/docs/vscode.html +53 -0
- package/public/docs/worker-permission-verification.html +122 -0
- package/public/index.html +17 -0
- package/scripts/check-node.mjs +7 -0
- package/scripts/codeflow.mjs +55 -0
- package/scripts/pty.py +273 -0
- package/src/acp-connections.js +110 -0
- package/src/adapters/acp-presets.js +37 -0
- package/src/adapters/acp-types.js +0 -0
- package/src/adapters/acp.js +328 -0
- package/src/adapters/agy-auth.js +67 -0
- package/src/adapters/agy-isolation.js +223 -0
- package/src/adapters/agy.js +297 -0
- package/src/adapters/claude.js +220 -0
- package/src/adapters/codex-app-server.js +518 -0
- package/src/adapters/codex.js +299 -0
- package/src/adapters/errors.js +57 -0
- package/src/adapters/index.js +91 -0
- package/src/adapters/managed-permissions.js +37 -0
- package/src/adapters/model-discovery.js +100 -0
- package/src/adapters/process.js +418 -0
- package/src/adapters/team-tools.js +102 -0
- package/src/adapters/types.js +0 -0
- package/src/agent-container.js +155 -0
- package/src/approvals.js +121 -0
- package/src/architecture.js +456 -0
- package/src/assets.js +44 -0
- package/src/automation.js +901 -0
- package/src/certificate-renewal.js +75 -0
- package/src/chat-handoff.js +55 -0
- package/src/checkpoint-review.js +72 -0
- package/src/checks.js +303 -0
- package/src/code-host-git.js +102 -0
- package/src/code-hosts-api.js +99 -0
- package/src/code-hosts.js +482 -0
- package/src/code-intelligence-worker.mjs +452 -0
- package/src/code-intelligence.js +141 -0
- package/src/collab/api.js +365 -0
- package/src/collab/checkpoints.js +198 -0
- package/src/collab/connections.js +139 -0
- package/src/collab/host-execution.js +347 -0
- package/src/collab/hub-client.js +210 -0
- package/src/collab/link-api.js +229 -0
- package/src/collab/link.js +595 -0
- package/src/collab/model.js +496 -0
- package/src/collab/runner.js +1014 -0
- package/src/collab/store.js +1452 -0
- package/src/collab/terminals.js +361 -0
- package/src/collaboration-reviews.js +116 -0
- package/src/config.js +48 -0
- package/src/context-budget.js +14 -0
- package/src/context-inspection.js +204 -0
- package/src/context.js +154 -0
- package/src/conventions.js +283 -0
- package/src/coordinated-api.js +247 -0
- package/src/deferred-launch.js +82 -0
- package/src/deferred-runs.js +515 -0
- package/src/dependency-health.js +35 -0
- package/src/diff.js +43 -0
- package/src/docs-help.js +316 -0
- package/src/doctor.js +232 -0
- package/src/engine.js +4366 -0
- package/src/env.js +44 -0
- package/src/experience.js +50 -0
- package/src/extensions.js +144 -0
- package/src/filesystem-access.js +107 -0
- package/src/filesystem-policy.js +238 -0
- package/src/filtered-task-limits.js +93 -0
- package/src/filtered-tasks-api.js +53 -0
- package/src/filtered-tasks.js +576 -0
- package/src/fs.js +57 -0
- package/src/git.js +626 -0
- package/src/github-review-threads.js +181 -0
- package/src/github.js +538 -0
- package/src/http.js +69 -0
- package/src/improve-settings.js +38 -0
- package/src/improve.js +187 -0
- package/src/integrations.js +373 -0
- package/src/integrity.js +259 -0
- package/src/journey-api.js +77 -0
- package/src/journey-replay.js +65 -0
- package/src/journey-store.js +97 -0
- package/src/journeys.js +60 -0
- package/src/json.js +81 -0
- package/src/launch-profiles.js +292 -0
- package/src/learnings.js +80 -0
- package/src/log.js +39 -0
- package/src/maintenance.js +335 -0
- package/src/memory-analysis.js +182 -0
- package/src/memory-claims.js +153 -0
- package/src/memory-sqlite.js +236 -0
- package/src/memory.js +552 -0
- package/src/merge-validation.js +58 -0
- package/src/model-catalog.js +238 -0
- package/src/model-research.js +91 -0
- package/src/notes.js +176 -0
- package/src/notifications.js +413 -0
- package/src/patterns/auto-team-model.js +212 -0
- package/src/patterns/auto-team.js +659 -0
- package/src/patterns/council.js +199 -0
- package/src/patterns/debate.js +188 -0
- package/src/patterns/findings.js +141 -0
- package/src/patterns/index.js +19 -0
- package/src/patterns/loop.js +158 -0
- package/src/patterns/pipeline.js +125 -0
- package/src/patterns/prompts.js +181 -0
- package/src/patterns/race.js +147 -0
- package/src/patterns/schemas.js +40 -0
- package/src/patterns/solo.js +49 -0
- package/src/patterns/supervisor.js +235 -0
- package/src/patterns/task-draft.js +29 -0
- package/src/patterns/tdd.js +231 -0
- package/src/patterns/team-strategies.js +67 -0
- package/src/performance.js +43 -0
- package/src/persistence-status.js +35 -0
- package/src/phone-sessions.js +96 -0
- package/src/preview-overlay.js +383 -0
- package/src/preview.js +219 -0
- package/src/privacy.js +23 -0
- package/src/project-report.js +22 -0
- package/src/project-team-model.js +178 -0
- package/src/project-team-policy.js +42 -0
- package/src/project-team-store.js +213 -0
- package/src/project-teams-api.js +36 -0
- package/src/project-teams.js +551 -0
- package/src/projects.js +286 -0
- package/src/provider-eligibility.js +9 -0
- package/src/readiness.js +98 -0
- package/src/remote-tls.js +66 -0
- package/src/remote-workers/bundles.js +198 -0
- package/src/remote-workers/client.js +332 -0
- package/src/remote-workers/durability.js +37 -0
- package/src/remote-workers/protocol.js +68 -0
- package/src/remote-workers/stdio.js +138 -0
- package/src/remote-workers/worker.js +304 -0
- package/src/remote.js +204 -0
- package/src/repo-config.js +201 -0
- package/src/repo-coordination.js +732 -0
- package/src/repo-tree.js +106 -0
- package/src/retention-policy.js +466 -0
- package/src/review-inbox.js +38 -0
- package/src/routing.js +49 -0
- package/src/run-analysis.js +111 -0
- package/src/run-cold-store.js +231 -0
- package/src/run-environment.js +15 -0
- package/src/run-history.js +91 -0
- package/src/run-log.js +160 -0
- package/src/run-permissions.js +110 -0
- package/src/run-projection.js +75 -0
- package/src/run-recovery.js +53 -0
- package/src/run-status.js +54 -0
- package/src/serve.js +138 -0
- package/src/server.js +2738 -0
- package/src/shared-access.js +103 -0
- package/src/shared-accounts.js +301 -0
- package/src/shared-api.js +239 -0
- package/src/shell.js +346 -0
- package/src/ship.js +344 -0
- package/src/slots.js +74 -0
- package/src/snapshot.js +388 -0
- package/src/source-context.js +17 -0
- package/src/sse-writer.js +70 -0
- package/src/ssh-projects/bootstrap.mjs +95 -0
- package/src/ssh-projects/config.js +45 -0
- package/src/ssh-projects/gateway.js +143 -0
- package/src/ssh-projects/manager.js +320 -0
- package/src/ssh-projects/team-autostart.mjs +93 -0
- package/src/ssh-projects/team-remove.mjs +69 -0
- package/src/ssh-projects/team-status.mjs +39 -0
- package/src/ssh-projects/transport.js +116 -0
- package/src/stats.js +139 -0
- package/src/store.js +544 -0
- package/src/stream.js +91 -0
- package/src/sweeps.js +241 -0
- package/src/tailscale.js +101 -0
- package/src/task-draft.js +23 -0
- package/src/team-evaluation.js +242 -0
- package/src/team-mailbox.js +160 -0
- package/src/team-memory.js +84 -0
- package/src/team-rerun-graph.js +15 -0
- package/src/team-reruns.js +130 -0
- package/src/team-scheduler.js +121 -0
- package/src/team-template-store.js +98 -0
- package/src/team-templates.js +117 -0
- package/src/team-tool-client.mjs +79 -0
- package/src/team-tools.js +176 -0
- package/src/teams.js +0 -0
- package/src/templates.js +62 -0
- package/src/transcript.js +134 -0
- package/src/verification-integrity.js +27 -0
- package/src/verification.js +183 -0
- package/src/watch.js +195 -0
- package/src/work-queue.js +47 -0
- package/src/workflow-control.js +83 -0
- package/src/workspace-api.js +207 -0
- package/src/workspace-changes.js +61 -0
- 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
|
+
};
|