@cliperhq/cliper 1.0.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.
Files changed (68) hide show
  1. package/README.md +266 -0
  2. package/dist/commands/analyze.d.ts +6 -0
  3. package/dist/commands/analyze.d.ts.map +1 -0
  4. package/dist/commands/analyze.js +216 -0
  5. package/dist/commands/export.d.ts +6 -0
  6. package/dist/commands/export.d.ts.map +1 -0
  7. package/dist/commands/export.js +64 -0
  8. package/dist/commands/init.d.ts +7 -0
  9. package/dist/commands/init.d.ts.map +1 -0
  10. package/dist/commands/init.js +173 -0
  11. package/dist/commands/scope.d.ts +2 -0
  12. package/dist/commands/scope.d.ts.map +1 -0
  13. package/dist/commands/scope.js +124 -0
  14. package/dist/commands/status.d.ts +2 -0
  15. package/dist/commands/status.d.ts.map +1 -0
  16. package/dist/commands/status.js +100 -0
  17. package/dist/commands/sync.d.ts +6 -0
  18. package/dist/commands/sync.d.ts.map +1 -0
  19. package/dist/commands/sync.js +83 -0
  20. package/dist/context/builder.d.ts +19 -0
  21. package/dist/context/builder.d.ts.map +1 -0
  22. package/dist/context/builder.js +143 -0
  23. package/dist/gaps/detector.d.ts +10 -0
  24. package/dist/gaps/detector.d.ts.map +1 -0
  25. package/dist/gaps/detector.js +139 -0
  26. package/dist/index.d.ts +3 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +48 -0
  29. package/dist/resolver/urlFetcher.d.ts +9 -0
  30. package/dist/resolver/urlFetcher.d.ts.map +1 -0
  31. package/dist/resolver/urlFetcher.js +134 -0
  32. package/dist/scanner/dependencies.d.ts +14 -0
  33. package/dist/scanner/dependencies.d.ts.map +1 -0
  34. package/dist/scanner/dependencies.js +199 -0
  35. package/dist/scanner/fileContent.d.ts +8 -0
  36. package/dist/scanner/fileContent.d.ts.map +1 -0
  37. package/dist/scanner/fileContent.js +133 -0
  38. package/dist/scanner/fileTree.d.ts +2 -0
  39. package/dist/scanner/fileTree.d.ts.map +1 -0
  40. package/dist/scanner/fileTree.js +152 -0
  41. package/dist/scanner/gitContext.d.ts +19 -0
  42. package/dist/scanner/gitContext.d.ts.map +1 -0
  43. package/dist/scanner/gitContext.js +60 -0
  44. package/dist/scope/autoScope.d.ts +2 -0
  45. package/dist/scope/autoScope.d.ts.map +1 -0
  46. package/dist/scope/autoScope.js +226 -0
  47. package/dist/scope/config.d.ts +10 -0
  48. package/dist/scope/config.d.ts.map +1 -0
  49. package/dist/scope/config.js +71 -0
  50. package/index.js +2 -0
  51. package/package.json +37 -0
  52. package/src/commands/analyze.ts +201 -0
  53. package/src/commands/export.ts +33 -0
  54. package/src/commands/init.ts +174 -0
  55. package/src/commands/scope.ts +77 -0
  56. package/src/commands/status.ts +67 -0
  57. package/src/commands/sync.ts +51 -0
  58. package/src/context/builder.ts +178 -0
  59. package/src/gaps/detector.ts +131 -0
  60. package/src/index.ts +54 -0
  61. package/src/resolver/urlFetcher.ts +119 -0
  62. package/src/scanner/dependencies.ts +196 -0
  63. package/src/scanner/fileContent.ts +121 -0
  64. package/src/scanner/fileTree.ts +149 -0
  65. package/src/scanner/gitContext.ts +74 -0
  66. package/src/scope/autoScope.ts +182 -0
  67. package/src/scope/config.ts +39 -0
  68. package/tsconfig.json +19 -0
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.extractFileContents = extractFileContents;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const glob_1 = require("glob");
43
+ const ignore_1 = __importDefault(require("ignore"));
44
+ const MAX_TOTAL_CHARS = 150000;
45
+ const BINARY_EXTENSIONS = new Set([
46
+ ".png", ".jpg", ".jpeg", ".gif", ".svg", ".ico", ".webp",
47
+ ".pdf", ".zip", ".tar", ".gz", ".exe", ".bin", ".wasm",
48
+ ".ttf", ".woff", ".woff2", ".eot", ".mp4", ".mp3",
49
+ ]);
50
+ const PRIORITY_EXTENSIONS = [
51
+ ".ts", ".tsx", ".js", ".jsx", ".py", ".rs", ".go",
52
+ ".java", ".kt", ".swift", ".rb", ".php", ".cs",
53
+ ".json", ".yaml", ".yml", ".toml", ".env.example",
54
+ ".md", ".mdx", ".sql", ".graphql", ".prisma",
55
+ ];
56
+ function isBinary(filePath) {
57
+ const ext = path.extname(filePath).toLowerCase();
58
+ return BINARY_EXTENSIONS.has(ext);
59
+ }
60
+ function getPriority(filePath) {
61
+ const ext = path.extname(filePath).toLowerCase();
62
+ const idx = PRIORITY_EXTENSIONS.indexOf(ext);
63
+ return idx === -1 ? 999 : idx;
64
+ }
65
+ async function extractFileContents(projectRoot, activeScope, watchedScope, maxFileSizeKB = 50) {
66
+ const MAX_FILE_SIZE_BYTES = maxFileSizeKB * 1024;
67
+ const ig = (0, ignore_1.default)();
68
+ const gitignorePath = path.join(projectRoot, ".gitignore");
69
+ if (fs.existsSync(gitignorePath)) {
70
+ ig.add(fs.readFileSync(gitignorePath, "utf-8"));
71
+ }
72
+ const allPaths = new Set();
73
+ // Collect files from active scope and watched scope
74
+ for (const scopePath of [...activeScope, ...watchedScope]) {
75
+ const fullScopePath = path.join(projectRoot, scopePath);
76
+ if (!fs.existsSync(fullScopePath))
77
+ continue;
78
+ const stat = fs.statSync(fullScopePath);
79
+ if (stat.isFile()) {
80
+ allPaths.add(scopePath);
81
+ }
82
+ else if (stat.isDirectory()) {
83
+ const files = await (0, glob_1.glob)("**/*", {
84
+ cwd: fullScopePath,
85
+ nodir: true,
86
+ ignore: ["node_modules/**", ".git/**", "dist/**", "build/**"],
87
+ });
88
+ for (const f of files) {
89
+ const rel = path.join(scopePath, f);
90
+ if (!ig.ignores(rel))
91
+ allPaths.add(rel);
92
+ }
93
+ }
94
+ }
95
+ // Sort by priority
96
+ const sortedPaths = Array.from(allPaths).sort((a, b) => getPriority(a) - getPriority(b));
97
+ const results = [];
98
+ let totalChars = 0;
99
+ for (const relativePath of sortedPaths) {
100
+ if (totalChars >= MAX_TOTAL_CHARS)
101
+ break;
102
+ if (isBinary(relativePath))
103
+ continue;
104
+ const fullPath = path.join(projectRoot, relativePath);
105
+ if (!fs.existsSync(fullPath))
106
+ continue;
107
+ const stat = fs.statSync(fullPath);
108
+ if (stat.size > MAX_FILE_SIZE_BYTES) {
109
+ results.push({
110
+ relativePath,
111
+ content: `[File too large to include: ${Math.round(stat.size / 1024)}KB]`,
112
+ truncated: true,
113
+ size: stat.size,
114
+ });
115
+ continue;
116
+ }
117
+ try {
118
+ let content = fs.readFileSync(fullPath, "utf-8");
119
+ let truncated = false;
120
+ if (totalChars + content.length > MAX_TOTAL_CHARS) {
121
+ content = content.slice(0, MAX_TOTAL_CHARS - totalChars);
122
+ truncated = true;
123
+ }
124
+ totalChars += content.length;
125
+ results.push({ relativePath, content, truncated, size: stat.size });
126
+ }
127
+ catch {
128
+ // Skip files that can't be read
129
+ }
130
+ }
131
+ return results;
132
+ }
133
+ //# sourceMappingURL=fileContent.js.map
@@ -0,0 +1,2 @@
1
+ export declare function generateFileTree(projectRoot: string, activeScope: string[], watchedScope: string[]): string;
2
+ //# sourceMappingURL=fileTree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileTree.d.ts","sourceRoot":"","sources":["../../src/scanner/fileTree.ts"],"names":[],"mappings":"AA0IA,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EAAE,EACrB,YAAY,EAAE,MAAM,EAAE,GACrB,MAAM,CAMR"}
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.generateFileTree = generateFileTree;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const ignore_1 = __importDefault(require("ignore"));
43
+ const IGNORE_DIRS = new Set([
44
+ "node_modules", ".git", "dist", "build", ".next", ".nuxt",
45
+ "coverage", ".cache", "__pycache__", ".pytest_cache", "vendor",
46
+ ".cliper",
47
+ ]);
48
+ function loadGitignore(projectRoot) {
49
+ const ig = (0, ignore_1.default)();
50
+ const gitignorePath = path.join(projectRoot, ".gitignore");
51
+ if (fs.existsSync(gitignorePath)) {
52
+ ig.add(fs.readFileSync(gitignorePath, "utf-8"));
53
+ }
54
+ return ig;
55
+ }
56
+ function getModifiedTime(filePath) {
57
+ try {
58
+ return fs.statSync(filePath).mtime;
59
+ }
60
+ catch {
61
+ return undefined;
62
+ }
63
+ }
64
+ function buildTree(dirPath, projectRoot, activeScope, watchedScope, ig, depth = 0, maxDepth = 4) {
65
+ if (depth > maxDepth)
66
+ return [];
67
+ let entries;
68
+ try {
69
+ entries = fs.readdirSync(dirPath, { withFileTypes: true });
70
+ }
71
+ catch {
72
+ return [];
73
+ }
74
+ const nodes = [];
75
+ for (const entry of entries) {
76
+ const fullPath = path.join(dirPath, entry.name);
77
+ const relativePath = path.relative(projectRoot, fullPath);
78
+ if (IGNORE_DIRS.has(entry.name))
79
+ continue;
80
+ if (ig.ignores(relativePath))
81
+ continue;
82
+ if (entry.name.startsWith(".") && entry.name !== ".env.example")
83
+ continue;
84
+ const inScope = activeScope.some((s) => relativePath.startsWith(s) || s.startsWith(relativePath));
85
+ const watched = watchedScope.some((s) => relativePath.startsWith(s) || relativePath === s);
86
+ const node = {
87
+ name: entry.name,
88
+ isDir: entry.isDirectory(),
89
+ inScope,
90
+ watched,
91
+ relativePath,
92
+ modifiedAt: entry.isFile() ? getModifiedTime(fullPath) : undefined,
93
+ };
94
+ if (entry.isDirectory()) {
95
+ node.children = buildTree(fullPath, projectRoot, activeScope, watchedScope, ig, depth + 1, maxDepth);
96
+ }
97
+ nodes.push(node);
98
+ }
99
+ return nodes.sort((a, b) => {
100
+ if (a.isDir !== b.isDir)
101
+ return a.isDir ? -1 : 1;
102
+ return a.name.localeCompare(b.name);
103
+ });
104
+ }
105
+ function formatTimeAgo(date) {
106
+ const diff = Date.now() - date.getTime();
107
+ const mins = Math.floor(diff / 60000);
108
+ const hours = Math.floor(diff / 3600000);
109
+ const days = Math.floor(diff / 86400000);
110
+ if (mins < 60)
111
+ return `${mins}m ago`;
112
+ if (hours < 24)
113
+ return `${hours}h ago`;
114
+ return `${days}d ago`;
115
+ }
116
+ function renderTree(nodes, prefix = "", isRoot = false) {
117
+ const lines = [];
118
+ for (let i = 0; i < nodes.length; i++) {
119
+ const node = nodes[i];
120
+ const isLast = i === nodes.length - 1;
121
+ const connector = isLast ? "└── " : "├── ";
122
+ const childPrefix = prefix + (isLast ? " " : "│ ");
123
+ let annotation = "";
124
+ if (node.inScope)
125
+ annotation += " ← ACTIVE SCOPE";
126
+ else if (node.watched)
127
+ annotation += " ← WATCHED";
128
+ let timeAnnotation = "";
129
+ if (node.modifiedAt && !node.isDir) {
130
+ timeAnnotation = ` (${formatTimeAgo(node.modifiedAt)})`;
131
+ }
132
+ if (node.isDir && !node.inScope && !node.watched && !isRoot) {
133
+ const childCount = node.children?.length ?? 0;
134
+ lines.push(`${prefix}${connector}${node.name}/${annotation || ` ← out of scope (${childCount} items)`}`);
135
+ }
136
+ else {
137
+ lines.push(`${prefix}${connector}${node.name}${node.isDir ? "/" : ""}${annotation}${timeAnnotation}`);
138
+ if (node.children && node.children.length > 0 && (node.inScope || node.watched || isRoot)) {
139
+ lines.push(renderTree(node.children, childPrefix));
140
+ }
141
+ }
142
+ }
143
+ return lines.filter(Boolean).join("\n");
144
+ }
145
+ function generateFileTree(projectRoot, activeScope, watchedScope) {
146
+ const ig = loadGitignore(projectRoot);
147
+ const projectName = path.basename(projectRoot);
148
+ const nodes = buildTree(projectRoot, projectRoot, activeScope, watchedScope, ig, 0);
149
+ const tree = renderTree(nodes, "", true);
150
+ return `${projectName}/\n${tree}`;
151
+ }
152
+ //# sourceMappingURL=fileTree.js.map
@@ -0,0 +1,19 @@
1
+ export interface GitContext {
2
+ branch: string;
3
+ lastCommit: {
4
+ hash: string;
5
+ message: string;
6
+ author: string;
7
+ date: string;
8
+ timeAgo: string;
9
+ } | null;
10
+ recentCommits: Array<{
11
+ hash: string;
12
+ message: string;
13
+ date: string;
14
+ }>;
15
+ uncommittedChanges: string[];
16
+ isGitRepo: boolean;
17
+ }
18
+ export declare function getGitContext(projectRoot: string): Promise<GitContext>;
19
+ //# sourceMappingURL=gitContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitContext.d.ts","sourceRoot":"","sources":["../../src/scanner/gitContext.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE;QACV,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,GAAG,IAAI,CAAC;IACT,aAAa,EAAE,KAAK,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IACH,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,SAAS,EAAE,OAAO,CAAC;CACpB;AAYD,wBAAsB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA2C5E"}
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getGitContext = getGitContext;
7
+ const simple_git_1 = __importDefault(require("simple-git"));
8
+ function timeAgo(dateStr) {
9
+ const diff = Date.now() - new Date(dateStr).getTime();
10
+ const mins = Math.floor(diff / 60000);
11
+ const hours = Math.floor(diff / 3600000);
12
+ const days = Math.floor(diff / 86400000);
13
+ if (mins < 60)
14
+ return `${mins} minutes ago`;
15
+ if (hours < 24)
16
+ return `${hours} hours ago`;
17
+ return `${days} days ago`;
18
+ }
19
+ async function getGitContext(projectRoot) {
20
+ const git = (0, simple_git_1.default)(projectRoot);
21
+ try {
22
+ const isRepo = await git.checkIsRepo();
23
+ if (!isRepo) {
24
+ return { branch: "", lastCommit: null, recentCommits: [], uncommittedChanges: [], isGitRepo: false };
25
+ }
26
+ const [branch, log, status] = await Promise.all([
27
+ git.revparse(["--abbrev-ref", "HEAD"]),
28
+ git.log({ maxCount: 5 }),
29
+ git.status(),
30
+ ]);
31
+ const [latest, ...rest] = log.all;
32
+ return {
33
+ isGitRepo: true,
34
+ branch: branch.trim(),
35
+ lastCommit: latest
36
+ ? {
37
+ hash: latest.hash.slice(0, 7),
38
+ message: latest.message,
39
+ author: latest.author_name,
40
+ date: latest.date,
41
+ timeAgo: timeAgo(latest.date),
42
+ }
43
+ : null,
44
+ recentCommits: rest.map((c) => ({
45
+ hash: c.hash.slice(0, 7),
46
+ message: c.message,
47
+ date: c.date,
48
+ })),
49
+ uncommittedChanges: [
50
+ ...status.modified,
51
+ ...status.created,
52
+ ...status.deleted,
53
+ ],
54
+ };
55
+ }
56
+ catch {
57
+ return { branch: "", lastCommit: null, recentCommits: [], uncommittedChanges: [], isGitRepo: false };
58
+ }
59
+ }
60
+ //# sourceMappingURL=gitContext.js.map
@@ -0,0 +1,2 @@
1
+ export declare function autoDetectScope(projectRoot: string): Promise<string[]>;
2
+ //# sourceMappingURL=autoScope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autoScope.d.ts","sourceRoot":"","sources":["../../src/scope/autoScope.ts"],"names":[],"mappings":"AAqIA,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAgD5E"}
@@ -0,0 +1,226 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.autoDetectScope = autoDetectScope;
40
+ const simple_git_1 = __importDefault(require("simple-git"));
41
+ const path = __importStar(require("path"));
42
+ const fs = __importStar(require("fs"));
43
+ const glob_1 = require("glob");
44
+ // Files always included regardless of scope
45
+ const ALWAYS_INCLUDE = [
46
+ "package.json",
47
+ "package-lock.json",
48
+ "yarn.lock",
49
+ "pnpm-lock.yaml",
50
+ "tsconfig.json",
51
+ "Cargo.toml",
52
+ "Cargo.lock",
53
+ "go.mod",
54
+ "go.sum",
55
+ "requirements.txt",
56
+ "pyproject.toml",
57
+ "README.md",
58
+ ".env.example",
59
+ "docker-compose.yml",
60
+ "Dockerfile",
61
+ ];
62
+ function detectProjectType(projectRoot) {
63
+ if (fs.existsSync(path.join(projectRoot, "Cargo.toml")))
64
+ return "rust";
65
+ if (fs.existsSync(path.join(projectRoot, "package.json")))
66
+ return "node";
67
+ if (fs.existsSync(path.join(projectRoot, "pyproject.toml")) ||
68
+ fs.existsSync(path.join(projectRoot, "requirements.txt")))
69
+ return "python";
70
+ if (fs.existsSync(path.join(projectRoot, "go.mod")))
71
+ return "go";
72
+ return "unknown";
73
+ }
74
+ function parseRustWorkspaceMembers(projectRoot) {
75
+ const cargoPath = path.join(projectRoot, "Cargo.toml");
76
+ if (!fs.existsSync(cargoPath))
77
+ return [];
78
+ try {
79
+ const content = fs.readFileSync(cargoPath, "utf-8");
80
+ // Parse [workspace] members = [...] from Cargo.toml
81
+ const workspaceMatch = content.match(/\[workspace\][\s\S]*?members\s*=\s*\[([\s\S]*?)\]/);
82
+ if (!workspaceMatch)
83
+ return [];
84
+ const membersRaw = workspaceMatch[1];
85
+ return membersRaw
86
+ .split(",")
87
+ .map((m) => m.replace(/["'\s]/g, "").trim())
88
+ .filter((m) => m.length > 0 && !m.startsWith("#"))
89
+ .map((m) => m.replace(/\/\*$/, "").replace(/\*$/, "").trim()); // strip glob wildcards
90
+ }
91
+ catch {
92
+ return [];
93
+ }
94
+ }
95
+ async function getRustScope(projectRoot) {
96
+ const scope = new Set();
97
+ // Parse workspace members from Cargo.toml
98
+ const members = parseRustWorkspaceMembers(projectRoot);
99
+ if (members.length > 0) {
100
+ // It's a workspace — include src/ of each member
101
+ for (const member of members) {
102
+ const memberSrc = path.join(member, "src");
103
+ const fullMemberSrc = path.join(projectRoot, memberSrc);
104
+ if (fs.existsSync(fullMemberSrc)) {
105
+ scope.add(memberSrc);
106
+ }
107
+ // Also include member Cargo.toml
108
+ const memberCargo = path.join(member, "Cargo.toml");
109
+ if (fs.existsSync(path.join(projectRoot, memberCargo))) {
110
+ scope.add(memberCargo);
111
+ }
112
+ }
113
+ }
114
+ else {
115
+ // Single crate — just include src/
116
+ const srcPath = path.join(projectRoot, "src");
117
+ if (fs.existsSync(srcPath))
118
+ scope.add("src");
119
+ }
120
+ // Also catch any */src dirs not listed in workspace (safety net)
121
+ const allSrcDirs = await (0, glob_1.glob)("*/src", {
122
+ cwd: projectRoot,
123
+ ignore: ["node_modules/**", ".git/**", "target/**"],
124
+ });
125
+ for (const s of allSrcDirs)
126
+ scope.add(s);
127
+ return Array.from(scope);
128
+ }
129
+ async function getNodeScope(projectRoot) {
130
+ const scope = new Set();
131
+ const srcPath = path.join(projectRoot, "src");
132
+ if (fs.existsSync(srcPath))
133
+ scope.add("src");
134
+ // Check for monorepo patterns (packages/, apps/, libs/)
135
+ for (const dir of ["packages", "apps", "libs"]) {
136
+ const fullPath = path.join(projectRoot, dir);
137
+ if (fs.existsSync(fullPath))
138
+ scope.add(dir);
139
+ }
140
+ return Array.from(scope);
141
+ }
142
+ async function getPythonScope(projectRoot) {
143
+ const scope = new Set();
144
+ // Python projects typically have a src/ or a package dir matching project name
145
+ const srcPath = path.join(projectRoot, "src");
146
+ if (fs.existsSync(srcPath))
147
+ scope.add("src");
148
+ // Look for dirs with __init__.py
149
+ const initFiles = await (0, glob_1.glob)("*/__init__.py", {
150
+ cwd: projectRoot,
151
+ ignore: ["node_modules/**", ".git/**", "venv/**", ".venv/**"],
152
+ });
153
+ for (const f of initFiles)
154
+ scope.add(path.dirname(f));
155
+ return Array.from(scope);
156
+ }
157
+ async function getGoScope(projectRoot) {
158
+ const scope = new Set();
159
+ const internalPath = path.join(projectRoot, "internal");
160
+ const pkgPath = path.join(projectRoot, "pkg");
161
+ const cmdPath = path.join(projectRoot, "cmd");
162
+ if (fs.existsSync(internalPath))
163
+ scope.add("internal");
164
+ if (fs.existsSync(pkgPath))
165
+ scope.add("pkg");
166
+ if (fs.existsSync(cmdPath))
167
+ scope.add("cmd");
168
+ return Array.from(scope);
169
+ }
170
+ async function autoDetectScope(projectRoot) {
171
+ const git = (0, simple_git_1.default)(projectRoot);
172
+ const autoScope = new Set();
173
+ const projectType = detectProjectType(projectRoot);
174
+ // Step 1: Detect language-specific source dirs
175
+ let langScope = [];
176
+ switch (projectType) {
177
+ case "rust":
178
+ langScope = await getRustScope(projectRoot);
179
+ break;
180
+ case "node":
181
+ langScope = await getNodeScope(projectRoot);
182
+ break;
183
+ case "python":
184
+ langScope = await getPythonScope(projectRoot);
185
+ break;
186
+ case "go":
187
+ langScope = await getGoScope(projectRoot);
188
+ break;
189
+ default: {
190
+ const srcPath = path.join(projectRoot, "src");
191
+ if (fs.existsSync(srcPath))
192
+ langScope = ["src"];
193
+ }
194
+ }
195
+ for (const s of langScope)
196
+ autoScope.add(s);
197
+ // Step 2: Layer git activity on top — add dirs of recently modified files
198
+ try {
199
+ const log = await git.raw([
200
+ "log", "--since=7 days ago", "--name-only", "--pretty=format:", "--diff-filter=AM"
201
+ ]);
202
+ const recentFiles = log
203
+ .split("\n")
204
+ .map((l) => l.trim())
205
+ .filter((l) => l.length > 0);
206
+ for (const file of recentFiles) {
207
+ const fullPath = path.join(projectRoot, file);
208
+ if (fs.existsSync(fullPath)) {
209
+ const dir = path.dirname(file);
210
+ if (dir !== ".")
211
+ autoScope.add(dir);
212
+ }
213
+ }
214
+ }
215
+ catch {
216
+ // Not a git repo or no recent commits — lang scope is enough
217
+ }
218
+ // Step 3: Always include root-level config files
219
+ for (const file of ALWAYS_INCLUDE) {
220
+ const fullPath = path.join(projectRoot, file);
221
+ if (fs.existsSync(fullPath))
222
+ autoScope.add(file);
223
+ }
224
+ return Array.from(autoScope).filter((s) => s !== "." && s.length > 0);
225
+ }
226
+ //# sourceMappingURL=autoScope.js.map
@@ -0,0 +1,10 @@
1
+ export interface ScopeConfig {
2
+ active: string[];
3
+ watched: string[];
4
+ updatedAt: string;
5
+ }
6
+ export declare function getCliperDir(projectRoot: string): string;
7
+ export declare function getScopeConfigPath(projectRoot: string): string;
8
+ export declare function loadScopeConfig(projectRoot: string): ScopeConfig;
9
+ export declare function saveScopeConfig(projectRoot: string, config: ScopeConfig): void;
10
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/scope/config.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAQD,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,CAQhE;AAED,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAK9E"}