clank-cli 0.1.67 → 0.1.74
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/README.md +9 -1
- package/package.json +1 -1
- package/src/AgentFiles.ts +1 -1
- package/src/ClassifyFiles.ts +9 -3
- package/src/Cli.ts +23 -23
- package/src/Consolidate.ts +250 -0
- package/src/FsUtil.ts +54 -4
- package/src/Git.ts +5 -2
- package/src/Gitignore.ts +20 -2
- package/src/Mapper.ts +47 -27
- package/src/OverlayLinks.ts +18 -18
- package/src/ScopeFromSymlink.ts +3 -2
- package/src/commands/Add.ts +142 -152
- package/src/commands/Check.ts +144 -61
- package/src/commands/Init.ts +1 -0
- package/src/commands/Link.ts +49 -32
- package/src/commands/Move.ts +2 -1
- package/src/commands/Rm.ts +2 -2
- package/src/commands/Unlink.ts +7 -2
- package/src/commands/VsCode.ts +2 -1
- package/src/commands/files/Dedupe.ts +5 -6
- package/src/commands/files/Scan.ts +21 -18
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { join, relative } from "node:path";
|
|
2
|
+
import { managedAgentDirs } from "../../AgentFiles.ts";
|
|
2
3
|
import { expandPath, loadConfig } from "../../Config.ts";
|
|
3
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
getCwd,
|
|
6
|
+
resolveSymlinkTarget,
|
|
7
|
+
toSlash,
|
|
8
|
+
walkDirectory,
|
|
9
|
+
} from "../../FsUtil.ts";
|
|
4
10
|
import { getGitContext } from "../../Git.ts";
|
|
5
11
|
import { isClankPath } from "../../Mapper.ts";
|
|
6
12
|
import { isAgentFilePath } from "./Dedupe.ts";
|
|
@@ -76,7 +82,7 @@ interface NotLinkedToOverlay {
|
|
|
76
82
|
export async function getFilesContext(
|
|
77
83
|
inputPath?: string,
|
|
78
84
|
): Promise<FilesContext> {
|
|
79
|
-
const cwd =
|
|
85
|
+
const cwd = await getCwd();
|
|
80
86
|
const gitContext = await getGitContext(cwd);
|
|
81
87
|
const targetRoot = gitContext.gitRoot;
|
|
82
88
|
const scanRoot = resolveScanRoot(targetRoot, cwd, inputPath);
|
|
@@ -146,7 +152,7 @@ function resolveScanRoot(
|
|
|
146
152
|
): string {
|
|
147
153
|
if (!input) return targetRoot;
|
|
148
154
|
const resolved = join(cwd, input);
|
|
149
|
-
const rel =
|
|
155
|
+
const rel = toSlash(relative(targetRoot, resolved));
|
|
150
156
|
if (rel.startsWith("..")) {
|
|
151
157
|
throw new Error(`Path is outside the git repository: ${input}`);
|
|
152
158
|
}
|
|
@@ -178,7 +184,7 @@ async function maybeCreateEntry(
|
|
|
178
184
|
opts: NormalizedFilesOptions,
|
|
179
185
|
filePath: string,
|
|
180
186
|
): Promise<FileEntry | null> {
|
|
181
|
-
const targetRel =
|
|
187
|
+
const targetRel = toSlash(relative(ctx.targetRoot, filePath));
|
|
182
188
|
if (!isManagedTargetPath(targetRel, opts.hidden)) return null;
|
|
183
189
|
if (!passesDepthFilter(targetRel, opts.depth)) return null;
|
|
184
190
|
|
|
@@ -187,16 +193,12 @@ async function maybeCreateEntry(
|
|
|
187
193
|
|
|
188
194
|
return {
|
|
189
195
|
absolutePath: filePath,
|
|
190
|
-
cwdRelativePath:
|
|
196
|
+
cwdRelativePath: toSlash(relative(ctx.cwd, filePath) || "."),
|
|
191
197
|
targetRelativePath: targetRel,
|
|
192
198
|
link,
|
|
193
199
|
};
|
|
194
200
|
}
|
|
195
201
|
|
|
196
|
-
function normalizeRelPath(p: string): string {
|
|
197
|
-
return p.replaceAll("\\", "/");
|
|
198
|
-
}
|
|
199
|
-
|
|
200
202
|
/** Decide whether a target-relative path is managed by clank for listing. */
|
|
201
203
|
function isManagedTargetPath(relPath: string, includeHidden: boolean): boolean {
|
|
202
204
|
if (isAgentFilePath(relPath)) return true;
|
|
@@ -220,7 +222,8 @@ async function classifyLink(
|
|
|
220
222
|
): Promise<LinkState> {
|
|
221
223
|
try {
|
|
222
224
|
const overlayPath = await resolveSymlinkTarget(filePath);
|
|
223
|
-
if (!overlayPath.startsWith(overlayRoot))
|
|
225
|
+
if (!toSlash(overlayPath).startsWith(toSlash(overlayRoot)))
|
|
226
|
+
return { kind: "unlinked" };
|
|
224
227
|
const scope = inferScopeFromOverlay(overlayPath, overlayRoot, gitContext);
|
|
225
228
|
if (!scope) return { kind: "unlinked" };
|
|
226
229
|
return { kind: "linked", overlayPath, scope };
|
|
@@ -242,7 +245,7 @@ function passesLinkFilter(
|
|
|
242
245
|
}
|
|
243
246
|
|
|
244
247
|
function isInDotAgentDir(relPath: string): boolean {
|
|
245
|
-
return
|
|
248
|
+
return managedAgentDirs.some((dir) => isInDirectory(relPath, dir));
|
|
246
249
|
}
|
|
247
250
|
|
|
248
251
|
/** Enforce a max segment count beneath the nearest `clank/` path component. */
|
|
@@ -263,16 +266,16 @@ function inferScopeFromOverlay(
|
|
|
263
266
|
overlayRoot: string,
|
|
264
267
|
gitContext: Awaited<ReturnType<typeof getGitContext>>,
|
|
265
268
|
): "global" | "project" | "worktree" | null {
|
|
266
|
-
const
|
|
267
|
-
|
|
269
|
+
const op = toSlash(overlayPath);
|
|
270
|
+
const globalPrefix = `${toSlash(join(overlayRoot, "global"))}/`;
|
|
271
|
+
if (op.startsWith(globalPrefix)) return "global";
|
|
268
272
|
|
|
269
273
|
const { projectName, worktreeName } = gitContext;
|
|
270
|
-
const
|
|
271
|
-
const
|
|
272
|
-
if (
|
|
274
|
+
const projectBase = toSlash(join(overlayRoot, "targets", projectName));
|
|
275
|
+
const worktreePrefix = `${projectBase}/worktrees/${worktreeName}/`;
|
|
276
|
+
if (op.startsWith(worktreePrefix)) return "worktree";
|
|
273
277
|
|
|
274
|
-
|
|
275
|
-
if (overlayPath.startsWith(projectPrefix)) return "project";
|
|
278
|
+
if (op.startsWith(`${projectBase}/`)) return "project";
|
|
276
279
|
|
|
277
280
|
return null;
|
|
278
281
|
}
|