@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.
- package/README.md +266 -0
- package/dist/commands/analyze.d.ts +6 -0
- package/dist/commands/analyze.d.ts.map +1 -0
- package/dist/commands/analyze.js +216 -0
- package/dist/commands/export.d.ts +6 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +64 -0
- package/dist/commands/init.d.ts +7 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +173 -0
- package/dist/commands/scope.d.ts +2 -0
- package/dist/commands/scope.d.ts.map +1 -0
- package/dist/commands/scope.js +124 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +100 -0
- package/dist/commands/sync.d.ts +6 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +83 -0
- package/dist/context/builder.d.ts +19 -0
- package/dist/context/builder.d.ts.map +1 -0
- package/dist/context/builder.js +143 -0
- package/dist/gaps/detector.d.ts +10 -0
- package/dist/gaps/detector.d.ts.map +1 -0
- package/dist/gaps/detector.js +139 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +48 -0
- package/dist/resolver/urlFetcher.d.ts +9 -0
- package/dist/resolver/urlFetcher.d.ts.map +1 -0
- package/dist/resolver/urlFetcher.js +134 -0
- package/dist/scanner/dependencies.d.ts +14 -0
- package/dist/scanner/dependencies.d.ts.map +1 -0
- package/dist/scanner/dependencies.js +199 -0
- package/dist/scanner/fileContent.d.ts +8 -0
- package/dist/scanner/fileContent.d.ts.map +1 -0
- package/dist/scanner/fileContent.js +133 -0
- package/dist/scanner/fileTree.d.ts +2 -0
- package/dist/scanner/fileTree.d.ts.map +1 -0
- package/dist/scanner/fileTree.js +152 -0
- package/dist/scanner/gitContext.d.ts +19 -0
- package/dist/scanner/gitContext.d.ts.map +1 -0
- package/dist/scanner/gitContext.js +60 -0
- package/dist/scope/autoScope.d.ts +2 -0
- package/dist/scope/autoScope.d.ts.map +1 -0
- package/dist/scope/autoScope.js +226 -0
- package/dist/scope/config.d.ts +10 -0
- package/dist/scope/config.d.ts.map +1 -0
- package/dist/scope/config.js +71 -0
- package/index.js +2 -0
- package/package.json +37 -0
- package/src/commands/analyze.ts +201 -0
- package/src/commands/export.ts +33 -0
- package/src/commands/init.ts +174 -0
- package/src/commands/scope.ts +77 -0
- package/src/commands/status.ts +67 -0
- package/src/commands/sync.ts +51 -0
- package/src/context/builder.ts +178 -0
- package/src/gaps/detector.ts +131 -0
- package/src/index.ts +54 -0
- package/src/resolver/urlFetcher.ts +119 -0
- package/src/scanner/dependencies.ts +196 -0
- package/src/scanner/fileContent.ts +121 -0
- package/src/scanner/fileTree.ts +149 -0
- package/src/scanner/gitContext.ts +74 -0
- package/src/scope/autoScope.ts +182 -0
- package/src/scope/config.ts +39 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,173 @@
|
|
|
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.initCommand = initCommand;
|
|
40
|
+
const dependencies_1 = require("../scanner/dependencies");
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const simple_git_1 = __importDefault(require("simple-git"));
|
|
44
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
45
|
+
const ora_1 = __importDefault(require("ora"));
|
|
46
|
+
const autoScope_1 = require("../scope/autoScope");
|
|
47
|
+
const config_1 = require("../scope/config");
|
|
48
|
+
const fileTree_1 = require("../scanner/fileTree");
|
|
49
|
+
const fileContent_1 = require("../scanner/fileContent");
|
|
50
|
+
const gitContext_1 = require("../scanner/gitContext");
|
|
51
|
+
const urlFetcher_1 = require("../resolver/urlFetcher");
|
|
52
|
+
const detector_1 = require("../gaps/detector");
|
|
53
|
+
const builder_1 = require("../context/builder");
|
|
54
|
+
async function initCommand(options) {
|
|
55
|
+
const projectRoot = path.resolve(options.path);
|
|
56
|
+
if (!fs.existsSync(projectRoot)) {
|
|
57
|
+
console.error(chalk_1.default.red(`Project path not found: ${projectRoot}`));
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
console.log(chalk_1.default.bold.cyan("\n cliper init\n"));
|
|
61
|
+
console.log(chalk_1.default.gray(` Project: ${projectRoot}\n`));
|
|
62
|
+
// Step 1: Load or create scope config
|
|
63
|
+
const spinner = (0, ora_1.default)("Detecting scope from git activity...").start();
|
|
64
|
+
let scopeConfig = (0, config_1.loadScopeConfig)(projectRoot);
|
|
65
|
+
// Always re-run auto-detection and merge with any manual additions
|
|
66
|
+
const autoScope = await (0, autoScope_1.autoDetectScope)(projectRoot);
|
|
67
|
+
const manualAdditions = scopeConfig.active.filter((p) => !autoScope.includes(p));
|
|
68
|
+
scopeConfig.active = [...new Set([...autoScope, ...manualAdditions])];
|
|
69
|
+
(0, config_1.saveScopeConfig)(projectRoot, scopeConfig);
|
|
70
|
+
spinner.succeed(chalk_1.default.green(`Scope detected: ${scopeConfig.active.length} paths active, ${scopeConfig.watched.length} watched`));
|
|
71
|
+
// Step 2: Generate file tree
|
|
72
|
+
const treeSpinner = (0, ora_1.default)("Building annotated file tree...").start();
|
|
73
|
+
const fileTree = (0, fileTree_1.generateFileTree)(projectRoot, scopeConfig.active, scopeConfig.watched);
|
|
74
|
+
treeSpinner.succeed(chalk_1.default.green("File tree built"));
|
|
75
|
+
// Step 3: Extract file contents
|
|
76
|
+
const contentSpinner = (0, ora_1.default)("Extracting file contents within scope...").start();
|
|
77
|
+
const files = await (0, fileContent_1.extractFileContents)(projectRoot, scopeConfig.active, scopeConfig.watched, options.maxFileSize ?? 50);
|
|
78
|
+
contentSpinner.succeed(chalk_1.default.green(`Extracted ${files.length} files`));
|
|
79
|
+
// Step 4: Git context
|
|
80
|
+
const gitSpinner = (0, ora_1.default)("Reading git context...").start();
|
|
81
|
+
const gitContext = await (0, gitContext_1.getGitContext)(projectRoot);
|
|
82
|
+
gitSpinner.succeed(gitContext.isGitRepo
|
|
83
|
+
? chalk_1.default.green(`Git: ${gitContext.branch} — ${gitContext.lastCommit?.message ?? "no commits"}`)
|
|
84
|
+
: chalk_1.default.yellow("Not a git repository"));
|
|
85
|
+
// Step 5: Resolve blocked references
|
|
86
|
+
const refSpinner = (0, ora_1.default)("Fetching blocked external references...").start();
|
|
87
|
+
const references = await (0, urlFetcher_1.resolveBlockedReferences)(projectRoot);
|
|
88
|
+
const fetched = references.filter((r) => r.status === "fetched").length;
|
|
89
|
+
const failed = references.filter((r) => r.status === "failed").length;
|
|
90
|
+
refSpinner.succeed(chalk_1.default.green(`References: ${fetched} fetched, ${failed} failed`));
|
|
91
|
+
// Step 6: Detect gaps
|
|
92
|
+
const gapSpinner = (0, ora_1.default)("Detecting gaps and undocumented patterns...").start();
|
|
93
|
+
const gaps = (0, detector_1.detectGaps)(files, projectRoot);
|
|
94
|
+
gapSpinner.succeed(gaps.length > 0
|
|
95
|
+
? chalk_1.default.yellow(`Found ${gaps.length} gaps (${gaps.filter((g) => g.severity === "high").length} high priority)`)
|
|
96
|
+
: chalk_1.default.green("No significant gaps detected"));
|
|
97
|
+
const depSpinner = (0, ora_1.default)("Mapping dependencies...").start();
|
|
98
|
+
const dependencyMap = (0, dependencies_1.buildDependencyMap)(files);
|
|
99
|
+
depSpinner.succeed(chalk_1.default.green(`Dependency map: ${dependencyMap.edges.length} edges, ${dependencyMap.externalPackages.length} external packages`));
|
|
100
|
+
// Step 7: Build context doc
|
|
101
|
+
const buildSpinner = (0, ora_1.default)("Building context document...").start();
|
|
102
|
+
const projectName = path.basename(projectRoot);
|
|
103
|
+
const contextDoc = (0, builder_1.buildContextDoc)({
|
|
104
|
+
projectRoot,
|
|
105
|
+
projectName,
|
|
106
|
+
activeScope: scopeConfig.active,
|
|
107
|
+
watchedScope: scopeConfig.watched,
|
|
108
|
+
fileTree,
|
|
109
|
+
files,
|
|
110
|
+
gitContext,
|
|
111
|
+
references,
|
|
112
|
+
gaps,
|
|
113
|
+
generatedAt: new Date().toISOString(),
|
|
114
|
+
dependencyMap: (0, dependencies_1.formatDependencyMap)(dependencyMap),
|
|
115
|
+
});
|
|
116
|
+
// Step 8: Write to disk
|
|
117
|
+
const cliperDir = (0, config_1.getCliperDir)(projectRoot);
|
|
118
|
+
if (!fs.existsSync(cliperDir))
|
|
119
|
+
fs.mkdirSync(cliperDir, { recursive: true });
|
|
120
|
+
const contextPath = path.join(cliperDir, "context.md");
|
|
121
|
+
fs.writeFileSync(contextPath, contextDoc, "utf-8");
|
|
122
|
+
buildSpinner.succeed(chalk_1.default.green("Context document built"));
|
|
123
|
+
// Auto-manage .gitignore — add anything cliper introduces that shouldn't be committed
|
|
124
|
+
const gitignorePath = path.join(projectRoot, ".gitignore");
|
|
125
|
+
const entriesToEnsure = [
|
|
126
|
+
{ check: "node_modules", line: "node_modules/" },
|
|
127
|
+
{ check: "package-lock.json", line: "package-lock.json" },
|
|
128
|
+
{ check: ".cliper/cache", line: ".cliper/cache/" },
|
|
129
|
+
{ check: ".cliper/prompt-", line: ".cliper/prompt-*.md" },
|
|
130
|
+
];
|
|
131
|
+
let gitignoreContent = fs.existsSync(gitignorePath)
|
|
132
|
+
? fs.readFileSync(gitignorePath, "utf-8")
|
|
133
|
+
: "";
|
|
134
|
+
const missingEntries = entriesToEnsure.filter((e) => !gitignoreContent.includes(e.check));
|
|
135
|
+
if (missingEntries.length > 0) {
|
|
136
|
+
const block = "\n# Cliper — auto-managed\n" + missingEntries.map((e) => e.line).join("\n") + "\n";
|
|
137
|
+
if (fs.existsSync(gitignorePath)) {
|
|
138
|
+
fs.appendFileSync(gitignorePath, block);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
fs.writeFileSync(gitignorePath, block.trimStart());
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Remove node_modules from git tracking if accidentally staged
|
|
145
|
+
try {
|
|
146
|
+
const gitInstance = (0, simple_git_1.default)(projectRoot);
|
|
147
|
+
const tracked = await gitInstance.raw(["ls-files", "node_modules"]);
|
|
148
|
+
if (tracked.trim().length > 0) {
|
|
149
|
+
await gitInstance.raw(["rm", "-r", "--cached", "node_modules/"]);
|
|
150
|
+
console.log(chalk_1.default.yellow(" ⚡ Removed node_modules from git tracking"));
|
|
151
|
+
}
|
|
152
|
+
const lockTracked = await gitInstance.raw(["ls-files", "package-lock.json"]);
|
|
153
|
+
if (lockTracked.trim().length > 0) {
|
|
154
|
+
await gitInstance.raw(["rm", "--cached", "package-lock.json"]);
|
|
155
|
+
console.log(chalk_1.default.yellow(" ⚡ Removed package-lock.json from git tracking"));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
// Not a git repo or already clean — skip silently
|
|
160
|
+
}
|
|
161
|
+
// Summary
|
|
162
|
+
const sizeKB = Math.round(Buffer.byteLength(contextDoc, "utf-8") / 1024);
|
|
163
|
+
const estimatedTokens = Math.round(contextDoc.length / 4);
|
|
164
|
+
console.log(chalk_1.default.bold.green("\n ✓ Context document ready\n"));
|
|
165
|
+
console.log(chalk_1.default.gray(` Location: ${contextPath}`));
|
|
166
|
+
console.log(chalk_1.default.gray(` Size: ${sizeKB}KB (~${estimatedTokens.toLocaleString()} tokens)`));
|
|
167
|
+
console.log(chalk_1.default.gray(` Files: ${files.length} files in context`));
|
|
168
|
+
console.log(chalk_1.default.gray(` Gaps: ${gaps.length} detected\n`));
|
|
169
|
+
console.log(chalk_1.default.cyan(" Copy to clipboard:"));
|
|
170
|
+
console.log(chalk_1.default.white(" cliper export | pbcopy # macOS"));
|
|
171
|
+
console.log(chalk_1.default.white(" cliper export | xclip # Linux\n"));
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../src/commands/scope.ts"],"names":[],"mappings":"AAIA,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwEpF"}
|
|
@@ -0,0 +1,124 @@
|
|
|
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.scopeCommand = scopeCommand;
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
42
|
+
const config_1 = require("../scope/config");
|
|
43
|
+
async function scopeCommand(action, scopePath) {
|
|
44
|
+
const projectRoot = process.cwd();
|
|
45
|
+
const config = (0, config_1.loadScopeConfig)(projectRoot);
|
|
46
|
+
switch (action) {
|
|
47
|
+
case "add": {
|
|
48
|
+
if (!scopePath) {
|
|
49
|
+
console.error(chalk_1.default.red(" Please provide a path."));
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
const normalized = path.normalize(scopePath);
|
|
53
|
+
if (!config.active.includes(normalized)) {
|
|
54
|
+
config.active.push(normalized);
|
|
55
|
+
(0, config_1.saveScopeConfig)(projectRoot, config);
|
|
56
|
+
console.log(chalk_1.default.green(`\n ✓ Added to active scope: ${normalized}\n`));
|
|
57
|
+
console.log(chalk_1.default.gray(" Run cliper sync to update the context doc.\n"));
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
console.log(chalk_1.default.yellow(`\n Already in scope: ${normalized}\n`));
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
case "watch": {
|
|
65
|
+
if (!scopePath) {
|
|
66
|
+
console.error(chalk_1.default.red(" Please provide a path."));
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
const normalized = path.normalize(scopePath);
|
|
70
|
+
if (config.watched.length >= 15) {
|
|
71
|
+
console.log(chalk_1.default.yellow("\n Watch list is capped at 15 files. Remove one first:\n"));
|
|
72
|
+
console.log(chalk_1.default.gray(" cliper scope remove <path>\n"));
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
if (!config.watched.includes(normalized)) {
|
|
76
|
+
config.watched.push(normalized);
|
|
77
|
+
(0, config_1.saveScopeConfig)(projectRoot, config);
|
|
78
|
+
console.log(chalk_1.default.green(`\n ✓ Added to watch list: ${normalized}\n`));
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
console.log(chalk_1.default.yellow(`\n Already watched: ${normalized}\n`));
|
|
82
|
+
}
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
case "remove": {
|
|
86
|
+
if (!scopePath) {
|
|
87
|
+
console.error(chalk_1.default.red(" Please provide a path."));
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
const normalized = path.normalize(scopePath);
|
|
91
|
+
config.active = config.active.filter((p) => p !== normalized);
|
|
92
|
+
config.watched = config.watched.filter((p) => p !== normalized);
|
|
93
|
+
(0, config_1.saveScopeConfig)(projectRoot, config);
|
|
94
|
+
console.log(chalk_1.default.green(`\n ✓ Removed from scope: ${normalized}\n`));
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
case "list": {
|
|
98
|
+
console.log(chalk_1.default.bold.cyan("\n Current Scope\n"));
|
|
99
|
+
if (config.active.length === 0 && config.watched.length === 0) {
|
|
100
|
+
console.log(chalk_1.default.gray(" No scope configured. Run cliper init to auto-detect.\n"));
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
if (config.active.length > 0) {
|
|
104
|
+
console.log(chalk_1.default.bold(" Active scope:"));
|
|
105
|
+
for (const p of config.active)
|
|
106
|
+
console.log(chalk_1.default.white(` • ${p}`));
|
|
107
|
+
}
|
|
108
|
+
if (config.watched.length > 0) {
|
|
109
|
+
console.log(chalk_1.default.bold("\n Watch list:"));
|
|
110
|
+
for (const p of config.watched)
|
|
111
|
+
console.log(chalk_1.default.white(` • ${p}`));
|
|
112
|
+
console.log(chalk_1.default.gray(`\n (${config.watched.length}/15 watch slots used)`));
|
|
113
|
+
}
|
|
114
|
+
console.log();
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
default: {
|
|
118
|
+
console.error(chalk_1.default.red(`\n Unknown action: ${action}`));
|
|
119
|
+
console.log(chalk_1.default.gray(" Usage: cliper scope <add|remove|watch|list> [path]\n"));
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAMA,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CA4DnD"}
|
|
@@ -0,0 +1,100 @@
|
|
|
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.statusCommand = statusCommand;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
43
|
+
const config_1 = require("../scope/config");
|
|
44
|
+
const gitContext_1 = require("../scanner/gitContext");
|
|
45
|
+
async function statusCommand() {
|
|
46
|
+
const projectRoot = process.cwd();
|
|
47
|
+
const cliperDir = (0, config_1.getCliperDir)(projectRoot);
|
|
48
|
+
const contextPath = path.join(cliperDir, "context.md");
|
|
49
|
+
const config = (0, config_1.loadScopeConfig)(projectRoot);
|
|
50
|
+
console.log(chalk_1.default.bold.cyan("\n cliper status\n"));
|
|
51
|
+
// Context doc status
|
|
52
|
+
if (!fs.existsSync(contextPath)) {
|
|
53
|
+
console.log(chalk_1.default.red(" ✗ No context doc found"));
|
|
54
|
+
console.log(chalk_1.default.gray(" Run: cliper init\n"));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const stat = fs.statSync(contextPath);
|
|
58
|
+
const ageMs = Date.now() - stat.mtime.getTime();
|
|
59
|
+
const ageHours = Math.floor(ageMs / 3600000);
|
|
60
|
+
const ageMins = Math.floor(ageMs / 60000);
|
|
61
|
+
const ageStr = ageHours > 0 ? `${ageHours}h ago` : `${ageMins}m ago`;
|
|
62
|
+
const sizeKB = Math.round(stat.size / 1024);
|
|
63
|
+
const isFresh = ageMs < 3600000; // < 1 hour
|
|
64
|
+
console.log(isFresh
|
|
65
|
+
? chalk_1.default.green(` ✓ Context doc is fresh`)
|
|
66
|
+
: chalk_1.default.yellow(` ⚡ Context doc may be stale`));
|
|
67
|
+
console.log(chalk_1.default.gray(` Last updated: ${ageStr} | Size: ${sizeKB}KB`));
|
|
68
|
+
console.log(chalk_1.default.gray(` Path: ${contextPath}`));
|
|
69
|
+
// Scope status
|
|
70
|
+
console.log(chalk_1.default.bold("\n Scope:"));
|
|
71
|
+
if (config.active.length === 0) {
|
|
72
|
+
console.log(chalk_1.default.gray(" No active scope. Run cliper init to auto-detect."));
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
for (const p of config.active)
|
|
76
|
+
console.log(chalk_1.default.white(` • ${p} `) + chalk_1.default.cyan("[active]"));
|
|
77
|
+
for (const p of config.watched)
|
|
78
|
+
console.log(chalk_1.default.white(` • ${p} `) + chalk_1.default.blue("[watched]"));
|
|
79
|
+
}
|
|
80
|
+
// Git status
|
|
81
|
+
const git = await (0, gitContext_1.getGitContext)(projectRoot);
|
|
82
|
+
if (git.isGitRepo) {
|
|
83
|
+
console.log(chalk_1.default.bold("\n Git:"));
|
|
84
|
+
console.log(chalk_1.default.gray(` Branch: ${git.branch}`));
|
|
85
|
+
if (git.lastCommit) {
|
|
86
|
+
console.log(chalk_1.default.gray(` Latest: ${git.lastCommit.hash} — ${git.lastCommit.message} (${git.lastCommit.timeAgo})`));
|
|
87
|
+
}
|
|
88
|
+
if (git.uncommittedChanges.length > 0) {
|
|
89
|
+
console.log(chalk_1.default.yellow(` Uncommitted: ${git.uncommittedChanges.length} files changed`));
|
|
90
|
+
if (ageMs > 600000) {
|
|
91
|
+
// Context is older than 10 mins and there are uncommitted changes
|
|
92
|
+
console.log(chalk_1.default.yellow("\n ⚡ Changes detected since last context update."));
|
|
93
|
+
console.log(chalk_1.default.gray(" Run: cliper sync\n"));
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
console.log();
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAOA,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAuCrE"}
|
|
@@ -0,0 +1,83 @@
|
|
|
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.syncCommand = syncCommand;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
43
|
+
const ora_1 = __importDefault(require("ora"));
|
|
44
|
+
const config_1 = require("../scope/config");
|
|
45
|
+
const init_1 = require("./init");
|
|
46
|
+
async function syncCommand(options) {
|
|
47
|
+
const projectRoot = process.cwd();
|
|
48
|
+
const contextPath = path.join((0, config_1.getCliperDir)(projectRoot), "context.md");
|
|
49
|
+
if (!fs.existsSync(contextPath)) {
|
|
50
|
+
console.log(chalk_1.default.yellow("\n No context doc found. Run cliper init first.\n"));
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
if (options.watch) {
|
|
54
|
+
console.log(chalk_1.default.cyan("\n Watching for git changes... (Ctrl+C to stop)\n"));
|
|
55
|
+
let lastHash = "";
|
|
56
|
+
const check = async () => {
|
|
57
|
+
try {
|
|
58
|
+
const { default: simpleGit } = await Promise.resolve().then(() => __importStar(require("simple-git")));
|
|
59
|
+
const git = simpleGit(projectRoot);
|
|
60
|
+
const log = await git.log({ maxCount: 1 });
|
|
61
|
+
const currentHash = log.latest?.hash ?? "";
|
|
62
|
+
if (currentHash && currentHash !== lastHash) {
|
|
63
|
+
if (lastHash !== "") {
|
|
64
|
+
console.log(chalk_1.default.yellow(`\n New commit detected: ${currentHash.slice(0, 7)} — refreshing context...\n`));
|
|
65
|
+
await (0, init_1.initCommand)({ path: projectRoot });
|
|
66
|
+
}
|
|
67
|
+
lastHash = currentHash;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// silently skip
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
await check();
|
|
75
|
+
setInterval(check, 10000); // Check every 10 seconds
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
const spinner = (0, ora_1.default)("Syncing context document...").start();
|
|
79
|
+
spinner.stop();
|
|
80
|
+
await (0, init_1.initCommand)({ path: projectRoot });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=sync.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { FileContent } from "../scanner/fileContent";
|
|
2
|
+
import { GitContext } from "../scanner/gitContext";
|
|
3
|
+
import { ResolvedReference } from "../resolver/urlFetcher";
|
|
4
|
+
import { Gap } from "../gaps/detector";
|
|
5
|
+
export interface ContextDocOptions {
|
|
6
|
+
projectRoot: string;
|
|
7
|
+
projectName: string;
|
|
8
|
+
activeScope: string[];
|
|
9
|
+
watchedScope: string[];
|
|
10
|
+
fileTree: string;
|
|
11
|
+
files: FileContent[];
|
|
12
|
+
gitContext: GitContext;
|
|
13
|
+
references: ResolvedReference[];
|
|
14
|
+
gaps: Gap[];
|
|
15
|
+
generatedAt: string;
|
|
16
|
+
dependencyMap: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function buildContextDoc(opts: ContextDocOptions): string;
|
|
19
|
+
//# sourceMappingURL=builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../src/context/builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAEvC,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,UAAU,EAAE,UAAU,CAAC;IACvB,UAAU,EAAE,iBAAiB,EAAE,CAAC;IAChC,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB;AAyGD,wBAAgB,eAAe,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAuD/D"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildContextDoc = buildContextDoc;
|
|
4
|
+
const DIVIDER = "━".repeat(50);
|
|
5
|
+
function formatGitContext(git) {
|
|
6
|
+
if (!git.isGitRepo)
|
|
7
|
+
return "Not a git repository.";
|
|
8
|
+
const lines = [];
|
|
9
|
+
lines.push(`Branch: ${git.branch}`);
|
|
10
|
+
if (git.lastCommit) {
|
|
11
|
+
lines.push(`Last commit: ${git.lastCommit.hash} — ${git.lastCommit.message} (${git.lastCommit.timeAgo})`);
|
|
12
|
+
lines.push(`Author: ${git.lastCommit.author}`);
|
|
13
|
+
}
|
|
14
|
+
if (git.uncommittedChanges.length > 0) {
|
|
15
|
+
lines.push(`\nUncommitted changes (${git.uncommittedChanges.length} files):`);
|
|
16
|
+
for (const f of git.uncommittedChanges.slice(0, 10)) {
|
|
17
|
+
lines.push(` - ${f}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (git.recentCommits.length > 0) {
|
|
21
|
+
lines.push("\nRecent commits:");
|
|
22
|
+
for (const c of git.recentCommits) {
|
|
23
|
+
lines.push(` ${c.hash} — ${c.message}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return lines.join("\n");
|
|
27
|
+
}
|
|
28
|
+
function formatFileContents(files) {
|
|
29
|
+
if (files.length === 0)
|
|
30
|
+
return "No files in scope.";
|
|
31
|
+
return files
|
|
32
|
+
.map((f) => {
|
|
33
|
+
const ext = f.relativePath.split(".").pop() ?? "";
|
|
34
|
+
const truncatedNote = f.truncated ? "\n[... truncated ...]" : "";
|
|
35
|
+
return `### ${f.relativePath}\n\`\`\`${ext}\n${f.content}${truncatedNote}\n\`\`\``;
|
|
36
|
+
})
|
|
37
|
+
.join("\n\n");
|
|
38
|
+
}
|
|
39
|
+
function formatReferences(refs) {
|
|
40
|
+
const fetched = refs.filter((r) => r.status === "fetched");
|
|
41
|
+
const failed = refs.filter((r) => r.status === "failed");
|
|
42
|
+
const lines = [];
|
|
43
|
+
if (fetched.length === 0 && failed.length === 0) {
|
|
44
|
+
return "No external references found in markdown files.";
|
|
45
|
+
}
|
|
46
|
+
for (const ref of fetched) {
|
|
47
|
+
lines.push(`#### ${ref.url}`);
|
|
48
|
+
lines.push(`Source: ${ref.source}`);
|
|
49
|
+
lines.push(`\n${ref.content}\n`);
|
|
50
|
+
}
|
|
51
|
+
if (failed.length > 0) {
|
|
52
|
+
lines.push("\n**Could not fetch:**");
|
|
53
|
+
for (const ref of failed) {
|
|
54
|
+
lines.push(` - ${ref.url} (${ref.reason})`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return lines.join("\n");
|
|
58
|
+
}
|
|
59
|
+
function formatGaps(gaps) {
|
|
60
|
+
if (gaps.length === 0)
|
|
61
|
+
return "No significant gaps detected.";
|
|
62
|
+
const bySeverity = {
|
|
63
|
+
high: gaps.filter((g) => g.severity === "high"),
|
|
64
|
+
medium: gaps.filter((g) => g.severity === "medium"),
|
|
65
|
+
low: gaps.filter((g) => g.severity === "low"),
|
|
66
|
+
};
|
|
67
|
+
const lines = [];
|
|
68
|
+
if (bySeverity.high.length > 0) {
|
|
69
|
+
lines.push("**HIGH PRIORITY**");
|
|
70
|
+
for (const g of bySeverity.high) {
|
|
71
|
+
lines.push(` ⚠️ [${g.file}${g.line ? `:${g.line}` : ""}] ${g.description}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (bySeverity.medium.length > 0) {
|
|
75
|
+
lines.push("\n**MEDIUM PRIORITY**");
|
|
76
|
+
for (const g of bySeverity.medium) {
|
|
77
|
+
lines.push(` ⚡ [${g.file}${g.line ? `:${g.line}` : ""}] ${g.description}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (bySeverity.low.length > 0) {
|
|
81
|
+
lines.push("\n**LOW PRIORITY**");
|
|
82
|
+
for (const g of bySeverity.low.slice(0, 10)) {
|
|
83
|
+
lines.push(` ℹ️ [${g.file}${g.line ? `:${g.line}` : ""}] ${g.description}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return lines.join("\n");
|
|
87
|
+
}
|
|
88
|
+
function buildContextDoc(opts) {
|
|
89
|
+
const scopeSummary = [
|
|
90
|
+
...opts.activeScope.map((s) => `${s} (active)`),
|
|
91
|
+
...opts.watchedScope.map((s) => `${s} (watched)`),
|
|
92
|
+
].join(", ") || "auto-detected";
|
|
93
|
+
return `${DIVIDER}
|
|
94
|
+
CLIPER CONTEXT DOCUMENT
|
|
95
|
+
${DIVIDER}
|
|
96
|
+
PROJECT: ${opts.projectName}
|
|
97
|
+
GENERATED: ${opts.generatedAt}
|
|
98
|
+
BRANCH: ${opts.gitContext.branch || "unknown"}
|
|
99
|
+
SCOPED TO: ${scopeSummary}
|
|
100
|
+
${DIVIDER}
|
|
101
|
+
|
|
102
|
+
## FOLDER STRUCTURE
|
|
103
|
+
|
|
104
|
+
\`\`\`
|
|
105
|
+
${opts.fileTree}
|
|
106
|
+
\`\`\`
|
|
107
|
+
|
|
108
|
+
${DIVIDER}
|
|
109
|
+
|
|
110
|
+
## GIT CONTEXT
|
|
111
|
+
|
|
112
|
+
${formatGitContext(opts.gitContext)}
|
|
113
|
+
|
|
114
|
+
${DIVIDER}
|
|
115
|
+
|
|
116
|
+
## DEPENDENCY MAP
|
|
117
|
+
|
|
118
|
+
${opts.dependencyMap}
|
|
119
|
+
|
|
120
|
+
${DIVIDER}
|
|
121
|
+
|
|
122
|
+
## KEY FILES
|
|
123
|
+
|
|
124
|
+
${formatFileContents(opts.files)}
|
|
125
|
+
|
|
126
|
+
${DIVIDER}
|
|
127
|
+
|
|
128
|
+
## BLOCKED REFERENCES (fetched locally)
|
|
129
|
+
|
|
130
|
+
${formatReferences(opts.references)}
|
|
131
|
+
|
|
132
|
+
${DIVIDER}
|
|
133
|
+
|
|
134
|
+
## DETECTED GAPS
|
|
135
|
+
|
|
136
|
+
${formatGaps(opts.gaps)}
|
|
137
|
+
|
|
138
|
+
${DIVIDER}
|
|
139
|
+
END OF CLIPER CONTEXT DOCUMENT
|
|
140
|
+
${DIVIDER}
|
|
141
|
+
`;
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=builder.js.map
|