agentln 0.1.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.
package/dist/logger.js ADDED
@@ -0,0 +1,29 @@
1
+ import pc from "picocolors";
2
+ export function createLogger(verbose) {
3
+ return {
4
+ info(msg) {
5
+ process.stdout.write(`${pc.cyan("›")} ${msg}\n`);
6
+ },
7
+ success(msg) {
8
+ process.stdout.write(`${pc.green("✓")} ${msg}\n`);
9
+ },
10
+ warn(msg) {
11
+ process.stderr.write(`${pc.yellow("!")} ${msg}\n`);
12
+ },
13
+ error(msg) {
14
+ process.stderr.write(`${pc.red("✗")} ${msg}\n`);
15
+ },
16
+ debug(msg) {
17
+ if (verbose)
18
+ process.stdout.write(`${pc.dim("·")} ${pc.dim(msg)}\n`);
19
+ },
20
+ raw(msg) {
21
+ process.stdout.write(`${msg}\n`);
22
+ },
23
+ step(label, detail) {
24
+ const head = pc.magenta(label);
25
+ process.stdout.write(detail ? `${head} ${pc.dim(detail)}\n` : `${head}\n`);
26
+ },
27
+ };
28
+ }
29
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAY5B,MAAM,UAAU,YAAY,CAAC,OAAgB;IAC3C,OAAO;QACL,IAAI,CAAC,GAAG;YACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;QACnD,CAAC;QACD,OAAO,CAAC,GAAG;YACT,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;QACpD,CAAC;QACD,IAAI,CAAC,GAAG;YACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;QACrD,CAAC;QACD,KAAK,CAAC,GAAG;YACP,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;QAClD,CAAC;QACD,KAAK,CAAC,GAAG;YACP,IAAI,OAAO;gBAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACvE,CAAC;QACD,GAAG,CAAC,GAAG;YACL,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;QACnC,CAAC;QACD,IAAI,CAAC,KAAK,EAAE,MAAM;YAChB,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;QAC7E,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { type DirState, type PlannedAction, type SourceName } from "./types.js";
2
+ export interface PlanInput {
3
+ root: string;
4
+ source: SourceName;
5
+ dirs: DirState[];
6
+ /**
7
+ * True for Case D (neither existed at root). Triggers creation of an empty
8
+ * root source file before linking.
9
+ */
10
+ bootstrapRoot: boolean;
11
+ force: boolean;
12
+ }
13
+ export interface Plan {
14
+ actions: PlannedAction[];
15
+ /** Directories that needed no changes (everything already correct). */
16
+ cleanCount: number;
17
+ /** Directories skipped because there's nothing to link in either direction. */
18
+ emptyCount: number;
19
+ }
20
+ export declare function buildPlan(input: PlanInput): Plan;
21
+ export declare function describeAction(action: PlannedAction): string;
22
+ //# sourceMappingURL=planner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner.d.ts","sourceRoot":"","sources":["../src/planner.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,QAAQ,EAEb,KAAK,aAAa,EAClB,KAAK,UAAU,EAChB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB;;;OAGG;IACH,aAAa,EAAE,OAAO,CAAC;IACvB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,IAAI;IACnB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,uEAAuE;IACvE,UAAU,EAAE,MAAM,CAAC;IACnB,+EAA+E;IAC/E,UAAU,EAAE,MAAM,CAAC;CACpB;AAUD,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CA2EhD;AAuDD,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAoB5D"}
@@ -0,0 +1,136 @@
1
+ import path from "node:path";
2
+ import { AGENTS_FILE, CLAUDE_FILE, } from "./types.js";
3
+ function linkName(source) {
4
+ return source === CLAUDE_FILE ? AGENTS_FILE : CLAUDE_FILE;
5
+ }
6
+ function entryFor(dir, name) {
7
+ return name === CLAUDE_FILE ? dir.claude : dir.agents;
8
+ }
9
+ export function buildPlan(input) {
10
+ const { root, source, dirs, bootstrapRoot, force } = input;
11
+ const actions = [];
12
+ let cleanCount = 0;
13
+ let emptyCount = 0;
14
+ const otherName = linkName(source);
15
+ if (bootstrapRoot) {
16
+ actions.push({
17
+ type: "create-root-source",
18
+ sourcePath: path.join(root, source),
19
+ });
20
+ }
21
+ for (const dir of dirs) {
22
+ const isRootDir = dir.dir === root;
23
+ const sourceEntry = entryFor(dir, source);
24
+ const linkEntry = entryFor(dir, otherName);
25
+ const sourcePresent = sourceEntry.kind === "regular-file" ||
26
+ (sourceEntry.kind === "correct-symlink" && !isRootDir) ||
27
+ // After bootstrap the root source will exist on disk by the time we run.
28
+ (isRootDir && bootstrapRoot);
29
+ const linkPresent = linkEntry.kind !== "missing";
30
+ // Nothing in this directory to manage.
31
+ if (!sourcePresent && !linkPresent) {
32
+ emptyCount++;
33
+ continue;
34
+ }
35
+ // Source exists (or will after bootstrap). Just ensure the link mirrors it.
36
+ if (sourcePresent) {
37
+ const desired = ensureLink({
38
+ sourceName: source,
39
+ linkName: otherName,
40
+ linkEntry,
41
+ dir: dir.dir,
42
+ force,
43
+ });
44
+ if (desired === "ok") {
45
+ cleanCount++;
46
+ }
47
+ else {
48
+ actions.push(desired);
49
+ }
50
+ continue;
51
+ }
52
+ // No source file in this directory but the link file exists as a regular
53
+ // file (or stale/broken symlink). Promote it to source, then link back.
54
+ if (linkEntry.kind === "regular-file" ||
55
+ linkEntry.kind === "incorrect-symlink" ||
56
+ linkEntry.kind === "broken-symlink") {
57
+ const sourcePath = path.join(dir.dir, source);
58
+ actions.push({
59
+ type: "promote-to-source",
60
+ fromPath: linkEntry.path,
61
+ toPath: sourcePath,
62
+ linkBack: true,
63
+ });
64
+ }
65
+ else {
66
+ actions.push({
67
+ type: "skip",
68
+ path: linkEntry.path,
69
+ reason: `unexpected entry kind: ${linkEntry.kind}`,
70
+ });
71
+ }
72
+ }
73
+ return { actions, cleanCount, emptyCount };
74
+ }
75
+ function ensureLink(args) {
76
+ const { sourceName, linkEntry, dir, force } = args;
77
+ const sourcePath = path.join(dir, sourceName);
78
+ const linkPath = linkEntry.path;
79
+ if (linkEntry.kind === "correct-symlink")
80
+ return "ok";
81
+ if (linkEntry.kind === "missing") {
82
+ return {
83
+ type: "create-symlink",
84
+ linkPath,
85
+ sourcePath,
86
+ replacesExisting: false,
87
+ replacesRegularFile: false,
88
+ };
89
+ }
90
+ if (linkEntry.kind === "incorrect-symlink" ||
91
+ linkEntry.kind === "broken-symlink") {
92
+ return {
93
+ type: "create-symlink",
94
+ linkPath,
95
+ sourcePath,
96
+ replacesExisting: true,
97
+ replacesRegularFile: false,
98
+ };
99
+ }
100
+ if (linkEntry.kind === "regular-file") {
101
+ return {
102
+ type: "create-symlink",
103
+ linkPath,
104
+ sourcePath,
105
+ replacesExisting: true,
106
+ replacesRegularFile: !force,
107
+ };
108
+ }
109
+ return {
110
+ type: "skip",
111
+ path: linkPath,
112
+ reason: `unexpected entry kind: ${linkEntry.kind}`,
113
+ };
114
+ }
115
+ export function describeAction(action) {
116
+ switch (action.type) {
117
+ case "create-root-source":
118
+ return `create empty source file → ${action.sourcePath}`;
119
+ case "create-symlink": {
120
+ const rel = path.relative(path.dirname(action.linkPath), action.sourcePath);
121
+ const verb = action.replacesExisting
122
+ ? action.replacesRegularFile
123
+ ? "replace regular file"
124
+ : "replace stale symlink"
125
+ : "create symlink";
126
+ return `${verb} ${action.linkPath} → ${rel}`;
127
+ }
128
+ case "promote-to-source": {
129
+ const rel = path.relative(path.dirname(action.fromPath), action.toPath);
130
+ return `rename ${action.fromPath} → ${action.toPath}, then link ${path.basename(action.fromPath)} → ${rel}`;
131
+ }
132
+ case "skip":
133
+ return `skip ${action.path} (${action.reason})`;
134
+ }
135
+ }
136
+ //# sourceMappingURL=planner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner.js","sourceRoot":"","sources":["../src/planner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { type DirState, type SourceName } from "./types.js";
2
+ export type RootCase = "only-claude" | "only-agents" | "both" | "neither";
3
+ export interface RootDecision {
4
+ source: SourceName;
5
+ bootstrapRoot: boolean;
6
+ }
7
+ export declare function classifyRoot(root: DirState): RootCase;
8
+ export declare function decideRoot(rootState: DirState, options: {
9
+ yes: boolean;
10
+ sourceFlag?: SourceName;
11
+ }): Promise<RootDecision>;
12
+ export declare function confirmPlan(message: string): Promise<boolean>;
13
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,QAAQ,EACb,KAAK,UAAU,EAChB,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,QAAQ,GAAG,aAAa,GAAG,aAAa,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1E,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,UAAU,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAOrD;AASD,wBAAsB,UAAU,CAC9B,SAAS,EAAE,QAAQ,EACnB,OAAO,EAAE;IACP,GAAG,EAAE,OAAO,CAAC;IACb,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB,GACA,OAAO,CAAC,YAAY,CAAC,CAwFvB;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAWnE"}
@@ -0,0 +1,106 @@
1
+ import prompts from "prompts";
2
+ import pc from "picocolors";
3
+ import { AGENTS_FILE, CLAUDE_FILE, } from "./types.js";
4
+ export function classifyRoot(root) {
5
+ const hasClaude = root.claude.kind !== "missing";
6
+ const hasAgents = root.agents.kind !== "missing";
7
+ if (hasClaude && hasAgents)
8
+ return "both";
9
+ if (hasClaude)
10
+ return "only-claude";
11
+ if (hasAgents)
12
+ return "only-agents";
13
+ return "neither";
14
+ }
15
+ function cancel() {
16
+ process.stdout.write(pc.dim("\nCancelled.\n"));
17
+ process.exit(0);
18
+ }
19
+ const onCancel = () => cancel();
20
+ export async function decideRoot(rootState, options) {
21
+ const rootCase = classifyRoot(rootState);
22
+ // Honour explicit --source flag without prompting.
23
+ if (options.sourceFlag) {
24
+ return {
25
+ source: options.sourceFlag,
26
+ bootstrapRoot: rootCase === "neither",
27
+ };
28
+ }
29
+ switch (rootCase) {
30
+ case "only-claude": {
31
+ if (options.yes)
32
+ return { source: CLAUDE_FILE, bootstrapRoot: false };
33
+ const { confirm } = await prompts({
34
+ type: "confirm",
35
+ name: "confirm",
36
+ message: `Found ${pc.bold(CLAUDE_FILE)} at repository root. Use ${pc.bold(CLAUDE_FILE)} as the source of truth across the repository?`,
37
+ initial: true,
38
+ }, { onCancel });
39
+ if (!confirm)
40
+ cancel();
41
+ return { source: CLAUDE_FILE, bootstrapRoot: false };
42
+ }
43
+ case "only-agents": {
44
+ if (options.yes)
45
+ return { source: AGENTS_FILE, bootstrapRoot: false };
46
+ const { confirm } = await prompts({
47
+ type: "confirm",
48
+ name: "confirm",
49
+ message: `Found ${pc.bold(AGENTS_FILE)} at repository root. Use ${pc.bold(AGENTS_FILE)} as the source of truth across the repository?`,
50
+ initial: true,
51
+ }, { onCancel });
52
+ if (!confirm)
53
+ cancel();
54
+ return { source: AGENTS_FILE, bootstrapRoot: false };
55
+ }
56
+ case "both": {
57
+ if (options.yes) {
58
+ // Without an explicit choice, default to CLAUDE.md when both exist.
59
+ return { source: CLAUDE_FILE, bootstrapRoot: false };
60
+ }
61
+ const { choice } = await prompts({
62
+ type: "select",
63
+ name: "choice",
64
+ message: `Both ${pc.bold(CLAUDE_FILE)} and ${pc.bold(AGENTS_FILE)} exist at repository root. Which one should be the source of truth for the repository?`,
65
+ choices: [
66
+ { title: `Keep ${CLAUDE_FILE}`, value: CLAUDE_FILE },
67
+ { title: `Keep ${AGENTS_FILE}`, value: AGENTS_FILE },
68
+ { title: "Cancel", value: "__cancel" },
69
+ ],
70
+ initial: 0,
71
+ }, { onCancel });
72
+ if (!choice || choice === "__cancel")
73
+ cancel();
74
+ return { source: choice, bootstrapRoot: false };
75
+ }
76
+ case "neither": {
77
+ if (options.yes)
78
+ return { source: CLAUDE_FILE, bootstrapRoot: true };
79
+ process.stdout.write(pc.dim(`No ${CLAUDE_FILE} or ${AGENTS_FILE} found at repository root.\n`));
80
+ const { choice } = await prompts({
81
+ type: "select",
82
+ name: "choice",
83
+ message: "Which file should become the repository standard?",
84
+ choices: [
85
+ { title: CLAUDE_FILE, value: CLAUDE_FILE },
86
+ { title: AGENTS_FILE, value: AGENTS_FILE },
87
+ { title: "Cancel", value: "__cancel" },
88
+ ],
89
+ initial: 0,
90
+ }, { onCancel });
91
+ if (!choice || choice === "__cancel")
92
+ cancel();
93
+ return { source: choice, bootstrapRoot: true };
94
+ }
95
+ }
96
+ }
97
+ export async function confirmPlan(message) {
98
+ const { ok } = await prompts({
99
+ type: "confirm",
100
+ name: "ok",
101
+ message,
102
+ initial: true,
103
+ }, { onCancel });
104
+ return Boolean(ok);
105
+ }
106
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { type DirState, type EntryState, type SourceName } from "./types.js";
2
+ export declare const DEFAULT_IGNORED_DIRS: Set<string>;
3
+ export interface ScanOptions {
4
+ ignoredDirs?: Set<string>;
5
+ followHiddenDirs?: boolean;
6
+ }
7
+ /**
8
+ * Classify a single CLAUDE.md/AGENTS.md candidate path. Resolves the symlink
9
+ * target without following it, so we can decide whether it already points to
10
+ * its sibling source file.
11
+ */
12
+ export declare function classifyEntry(filePath: string, expectedSiblingSource: SourceName | null): Promise<EntryState>;
13
+ /**
14
+ * Build the per-directory state for the two managed files. `source` is the
15
+ * repository-wide source-of-truth name; the other file is the link.
16
+ */
17
+ export declare function readDirState(dir: string, source: SourceName): Promise<DirState>;
18
+ /**
19
+ * Walk the repo recursively and yield every directory that contains at least
20
+ * one of the managed filenames (CLAUDE.md / AGENTS.md). Ignored directories
21
+ * are pruned cheaply.
22
+ */
23
+ export declare function scanRepository(root: string, source: SourceName, options?: ScanOptions): Promise<DirState[]>;
24
+ export declare function describeEntry(state: EntryState): string;
25
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,QAAQ,EAEb,KAAK,UAAU,EACf,KAAK,UAAU,EAChB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,oBAAoB,aAiB/B,CAAC;AAEH,MAAM,WAAW,WAAW;IAC1B,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,qBAAqB,EAAE,UAAU,GAAG,IAAI,GACvC,OAAO,CAAC,UAAU,CAAC,CAgDrB;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,QAAQ,CAAC,CAanB;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,UAAU,EAClB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,QAAQ,EAAE,CAAC,CAsCrB;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAmBvD"}
@@ -0,0 +1,147 @@
1
+ import { promises as fs } from "node:fs";
2
+ import path from "node:path";
3
+ import { AGENTS_FILE, CLAUDE_FILE, } from "./types.js";
4
+ export const DEFAULT_IGNORED_DIRS = new Set([
5
+ "node_modules",
6
+ ".git",
7
+ "dist",
8
+ "build",
9
+ ".next",
10
+ "coverage",
11
+ "vendor",
12
+ ".turbo",
13
+ ".cache",
14
+ ".parcel-cache",
15
+ ".svelte-kit",
16
+ ".nuxt",
17
+ ".output",
18
+ ".vercel",
19
+ ".idea",
20
+ ".vscode",
21
+ ]);
22
+ /**
23
+ * Classify a single CLAUDE.md/AGENTS.md candidate path. Resolves the symlink
24
+ * target without following it, so we can decide whether it already points to
25
+ * its sibling source file.
26
+ */
27
+ export async function classifyEntry(filePath, expectedSiblingSource) {
28
+ let lstat;
29
+ try {
30
+ lstat = await fs.lstat(filePath);
31
+ }
32
+ catch {
33
+ return { path: filePath, kind: "missing" };
34
+ }
35
+ if (lstat.isDirectory()) {
36
+ return { path: filePath, kind: "directory" };
37
+ }
38
+ if (lstat.isSymbolicLink()) {
39
+ let target;
40
+ try {
41
+ target = await fs.readlink(filePath);
42
+ }
43
+ catch {
44
+ return { path: filePath, kind: "broken-symlink" };
45
+ }
46
+ let stat;
47
+ try {
48
+ stat = await fs.stat(filePath);
49
+ }
50
+ catch {
51
+ return { path: filePath, kind: "broken-symlink", linkTarget: target };
52
+ }
53
+ if (!stat.isFile()) {
54
+ return { path: filePath, kind: "incorrect-symlink", linkTarget: target };
55
+ }
56
+ if (expectedSiblingSource) {
57
+ // We accept either the bare filename or "./<filename>" as correct.
58
+ const normalised = target.replace(/^\.[\\/]/, "");
59
+ if (normalised === expectedSiblingSource) {
60
+ return { path: filePath, kind: "correct-symlink", linkTarget: target };
61
+ }
62
+ return { path: filePath, kind: "incorrect-symlink", linkTarget: target };
63
+ }
64
+ return { path: filePath, kind: "incorrect-symlink", linkTarget: target };
65
+ }
66
+ if (lstat.isFile()) {
67
+ return { path: filePath, kind: "regular-file" };
68
+ }
69
+ return { path: filePath, kind: "other" };
70
+ }
71
+ /**
72
+ * Build the per-directory state for the two managed files. `source` is the
73
+ * repository-wide source-of-truth name; the other file is the link.
74
+ */
75
+ export async function readDirState(dir, source) {
76
+ const linkName = source === CLAUDE_FILE ? AGENTS_FILE : CLAUDE_FILE;
77
+ const [claude, agents] = await Promise.all([
78
+ classifyEntry(path.join(dir, CLAUDE_FILE), source === CLAUDE_FILE ? null : linkName === CLAUDE_FILE ? source : null),
79
+ classifyEntry(path.join(dir, AGENTS_FILE), source === AGENTS_FILE ? null : linkName === AGENTS_FILE ? source : null),
80
+ ]);
81
+ return { dir, claude, agents };
82
+ }
83
+ /**
84
+ * Walk the repo recursively and yield every directory that contains at least
85
+ * one of the managed filenames (CLAUDE.md / AGENTS.md). Ignored directories
86
+ * are pruned cheaply.
87
+ */
88
+ export async function scanRepository(root, source, options = {}) {
89
+ const ignored = options.ignoredDirs ?? DEFAULT_IGNORED_DIRS;
90
+ const results = [];
91
+ async function walk(dir, isRoot) {
92
+ let entries;
93
+ try {
94
+ entries = await fs.readdir(dir, { withFileTypes: true });
95
+ }
96
+ catch {
97
+ return;
98
+ }
99
+ let hasClaude = false;
100
+ let hasAgents = false;
101
+ const childDirs = [];
102
+ for (const entry of entries) {
103
+ if (entry.isDirectory()) {
104
+ if (ignored.has(entry.name))
105
+ continue;
106
+ if (!options.followHiddenDirs && entry.name.startsWith("."))
107
+ continue;
108
+ childDirs.push(path.join(dir, entry.name));
109
+ }
110
+ else if (entry.isFile() || entry.isSymbolicLink()) {
111
+ if (entry.name === CLAUDE_FILE)
112
+ hasClaude = true;
113
+ else if (entry.name === AGENTS_FILE)
114
+ hasAgents = true;
115
+ }
116
+ }
117
+ if (isRoot || hasClaude || hasAgents) {
118
+ results.push(await readDirState(dir, source));
119
+ }
120
+ for (const child of childDirs) {
121
+ await walk(child, false);
122
+ }
123
+ }
124
+ await walk(root, true);
125
+ return results;
126
+ }
127
+ export function describeEntry(state) {
128
+ switch (state.kind) {
129
+ case "missing":
130
+ return "missing";
131
+ case "regular-file":
132
+ return "regular file";
133
+ case "correct-symlink":
134
+ return `symlink → ${state.linkTarget ?? "?"} (current)`;
135
+ case "incorrect-symlink":
136
+ return `symlink → ${state.linkTarget ?? "?"} (stale)`;
137
+ case "broken-symlink":
138
+ return `broken symlink → ${state.linkTarget ?? "?"}`;
139
+ case "directory":
140
+ return "directory (unexpected)";
141
+ case "other":
142
+ return "non-regular file (unexpected)";
143
+ default:
144
+ return "unknown";
145
+ }
146
+ }
147
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ export declare const CLAUDE_FILE = "CLAUDE.md";
2
+ export declare const AGENTS_FILE = "AGENTS.md";
3
+ export type SourceName = typeof CLAUDE_FILE | typeof AGENTS_FILE;
4
+ export interface CliOptions {
5
+ root: string;
6
+ yes: boolean;
7
+ dryRun: boolean;
8
+ force: boolean;
9
+ verbose: boolean;
10
+ help: boolean;
11
+ version: boolean;
12
+ source?: SourceName;
13
+ copyFallback: boolean;
14
+ noCopyFallback: boolean;
15
+ }
16
+ export type EntryKind = "missing" | "regular-file" | "correct-symlink" | "incorrect-symlink" | "broken-symlink" | "directory" | "other";
17
+ export interface EntryState {
18
+ /** Absolute path to the file. */
19
+ path: string;
20
+ kind: EntryKind;
21
+ /** For symlinks, the raw link target (relative or absolute as stored). */
22
+ linkTarget?: string;
23
+ }
24
+ export interface DirState {
25
+ /** Absolute directory path. */
26
+ dir: string;
27
+ claude: EntryState;
28
+ agents: EntryState;
29
+ }
30
+ export type PlannedAction = {
31
+ type: "create-symlink";
32
+ /** The link file we will create (e.g. AGENTS.md in some dir). */
33
+ linkPath: string;
34
+ /** The source file the link should point at (absolute path). */
35
+ sourcePath: string;
36
+ /** Whether the link file currently exists and must be removed first. */
37
+ replacesExisting: boolean;
38
+ /** Whether existing entry is a regular file (vs a stale symlink). */
39
+ replacesRegularFile: boolean;
40
+ } | {
41
+ type: "promote-to-source";
42
+ /** Existing file that will be renamed (e.g. AGENTS.md in a folder where CLAUDE.md is source). */
43
+ fromPath: string;
44
+ /** New name for that file (e.g. CLAUDE.md). */
45
+ toPath: string;
46
+ /** Then create symlink at fromPath -> toPath. */
47
+ linkBack: true;
48
+ } | {
49
+ type: "create-root-source";
50
+ /** Create an empty source file at the repository root. */
51
+ sourcePath: string;
52
+ } | {
53
+ type: "skip";
54
+ reason: string;
55
+ path: string;
56
+ };
57
+ export interface ActionResult {
58
+ action: PlannedAction;
59
+ ok: boolean;
60
+ message: string;
61
+ fellBackToCopy?: boolean;
62
+ }
63
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,cAAc,CAAC;AACvC,eAAO,MAAM,WAAW,cAAc,CAAC;AAEvC,MAAM,MAAM,UAAU,GAAG,OAAO,WAAW,GAAG,OAAO,WAAW,CAAC;AAEjE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,MAAM,SAAS,GACjB,SAAS,GACT,cAAc,GACd,iBAAiB,GACjB,mBAAmB,GACnB,gBAAgB,GAChB,WAAW,GACX,OAAO,CAAC;AAEZ,MAAM,WAAW,UAAU;IACzB,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,QAAQ;IACvB,+BAA+B;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,UAAU,CAAC;CACpB;AAED,MAAM,MAAM,aAAa,GACrB;IACE,IAAI,EAAE,gBAAgB,CAAC;IACvB,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,UAAU,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,gBAAgB,EAAE,OAAO,CAAC;IAC1B,qEAAqE;IACrE,mBAAmB,EAAE,OAAO,CAAC;CAC9B,GACD;IACE,IAAI,EAAE,mBAAmB,CAAC;IAC1B,iGAAiG;IACjG,QAAQ,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,QAAQ,EAAE,IAAI,CAAC;CAChB,GACD;IACE,IAAI,EAAE,oBAAoB,CAAC;IAC3B,0DAA0D;IAC1D,UAAU,EAAE,MAAM,CAAC;CACpB,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEN,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,aAAa,CAAC;IACtB,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ export const CLAUDE_FILE = "CLAUDE.md";
2
+ export const AGENTS_FILE = "AGENTS.md";
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,WAAW,CAAC;AACvC,MAAM,CAAC,MAAM,WAAW,GAAG,WAAW,CAAC"}