prjct-cli 1.16.0 → 1.18.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/CHANGELOG.md +92 -1
- package/core/__tests__/domain/bm25.test.ts +225 -0
- package/core/__tests__/domain/change-propagator.test.ts +100 -0
- package/core/__tests__/domain/file-hasher.test.ts +146 -0
- package/core/__tests__/domain/file-ranker.test.ts +169 -0
- package/core/__tests__/domain/git-cochange.test.ts +121 -0
- package/core/__tests__/domain/import-graph.test.ts +156 -0
- package/core/agentic/smart-context.ts +33 -2
- package/core/commands/analysis.ts +9 -2
- package/core/commands/command-data.ts +3 -1
- package/core/commands/commands.ts +1 -0
- package/core/domain/bm25.ts +525 -0
- package/core/domain/change-propagator.ts +162 -0
- package/core/domain/file-hasher.ts +296 -0
- package/core/domain/file-ranker.ts +151 -0
- package/core/domain/git-cochange.ts +250 -0
- package/core/domain/import-graph.ts +315 -0
- package/core/index.ts +1 -0
- package/core/services/sync-service.ts +133 -2
- package/core/services/watch-service.ts +1 -1
- package/core/types/index.ts +1 -0
- package/core/types/project-sync.ts +20 -0
- package/dist/bin/prjct.mjs +1238 -374
- package/package.json +1 -1
package/dist/bin/prjct.mjs
CHANGED
|
@@ -16,10 +16,10 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
16
16
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
17
17
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
18
18
|
});
|
|
19
|
-
var __glob = (map) => (
|
|
20
|
-
var fn = map[
|
|
19
|
+
var __glob = (map) => (path73) => {
|
|
20
|
+
var fn = map[path73];
|
|
21
21
|
if (fn) return fn();
|
|
22
|
-
throw new Error("Module not found in bundle: " +
|
|
22
|
+
throw new Error("Module not found in bundle: " + path73);
|
|
23
23
|
};
|
|
24
24
|
var __esm = (fn, res) => function __init() {
|
|
25
25
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
@@ -4051,7 +4051,7 @@ var init_cache = __esm({
|
|
|
4051
4051
|
import { Database } from "bun:sqlite";
|
|
4052
4052
|
import fs15 from "node:fs";
|
|
4053
4053
|
import path14 from "node:path";
|
|
4054
|
-
var migrations, PrjctDatabase, prjctDb;
|
|
4054
|
+
var migrations, PrjctDatabase, prjctDb, database_default;
|
|
4055
4055
|
var init_database = __esm({
|
|
4056
4056
|
"core/storage/database.ts"() {
|
|
4057
4057
|
"use strict";
|
|
@@ -4482,6 +4482,7 @@ var init_database = __esm({
|
|
|
4482
4482
|
}
|
|
4483
4483
|
};
|
|
4484
4484
|
prjctDb = new PrjctDatabase();
|
|
4485
|
+
database_default = prjctDb;
|
|
4485
4486
|
}
|
|
4486
4487
|
});
|
|
4487
4488
|
|
|
@@ -6575,11 +6576,11 @@ async function runSignaturesTool(args2, projectPath) {
|
|
|
6575
6576
|
}
|
|
6576
6577
|
};
|
|
6577
6578
|
}
|
|
6578
|
-
const
|
|
6579
|
-
const
|
|
6580
|
-
const fullPath =
|
|
6579
|
+
const fs61 = await import("node:fs/promises");
|
|
6580
|
+
const path73 = await import("node:path");
|
|
6581
|
+
const fullPath = path73.isAbsolute(filePath) ? filePath : path73.join(projectPath, filePath);
|
|
6581
6582
|
try {
|
|
6582
|
-
const stat = await
|
|
6583
|
+
const stat = await fs61.stat(fullPath);
|
|
6583
6584
|
if (stat.isDirectory()) {
|
|
6584
6585
|
const results = await extractDirectorySignatures(filePath, projectPath, {
|
|
6585
6586
|
recursive: args2.includes("--recursive") || args2.includes("-r")
|
|
@@ -6646,11 +6647,11 @@ async function runSummaryTool(args2, projectPath) {
|
|
|
6646
6647
|
}
|
|
6647
6648
|
};
|
|
6648
6649
|
}
|
|
6649
|
-
const
|
|
6650
|
-
const
|
|
6651
|
-
const fullPath =
|
|
6650
|
+
const fs61 = await import("node:fs/promises");
|
|
6651
|
+
const path73 = await import("node:path");
|
|
6652
|
+
const fullPath = path73.isAbsolute(targetPath) ? targetPath : path73.join(projectPath, targetPath);
|
|
6652
6653
|
try {
|
|
6653
|
-
const stat = await
|
|
6654
|
+
const stat = await fs61.stat(fullPath);
|
|
6654
6655
|
if (stat.isDirectory()) {
|
|
6655
6656
|
const results = await summarizeDirectory(targetPath, projectPath, {
|
|
6656
6657
|
recursive: args2.includes("--recursive") || args2.includes("-r")
|
|
@@ -21767,16 +21768,16 @@ var init_onboarding = __esm({
|
|
|
21767
21768
|
* Detect project type from file system
|
|
21768
21769
|
*/
|
|
21769
21770
|
async detectProjectType() {
|
|
21770
|
-
const
|
|
21771
|
-
const
|
|
21771
|
+
const fs61 = await import("node:fs/promises");
|
|
21772
|
+
const path73 = await import("node:path");
|
|
21772
21773
|
try {
|
|
21773
|
-
const files = await
|
|
21774
|
+
const files = await fs61.readdir(this.projectPath);
|
|
21774
21775
|
if (files.includes("turbo.json") || files.includes("lerna.json") || files.includes("nx.json")) {
|
|
21775
21776
|
return "monorepo";
|
|
21776
21777
|
}
|
|
21777
21778
|
if (files.includes("package.json")) {
|
|
21778
|
-
const pkgPath =
|
|
21779
|
-
const pkgContent = await
|
|
21779
|
+
const pkgPath = path73.join(this.projectPath, "package.json");
|
|
21780
|
+
const pkgContent = await fs61.readFile(pkgPath, "utf-8");
|
|
21780
21781
|
const pkg = JSON.parse(pkgContent);
|
|
21781
21782
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
21782
21783
|
if (pkg.bin) return "cli-tool";
|
|
@@ -21812,32 +21813,32 @@ var init_onboarding = __esm({
|
|
|
21812
21813
|
* Detect installed AI agents from config files
|
|
21813
21814
|
*/
|
|
21814
21815
|
async detectInstalledAgents() {
|
|
21815
|
-
const
|
|
21816
|
-
const
|
|
21816
|
+
const fs61 = await import("node:fs/promises");
|
|
21817
|
+
const path73 = await import("node:path");
|
|
21817
21818
|
const os22 = await import("node:os");
|
|
21818
21819
|
const agents = [];
|
|
21819
21820
|
try {
|
|
21820
|
-
await
|
|
21821
|
+
await fs61.access(path73.join(os22.homedir(), ".claude"));
|
|
21821
21822
|
agents.push("claude");
|
|
21822
21823
|
} catch {
|
|
21823
21824
|
}
|
|
21824
21825
|
try {
|
|
21825
|
-
await
|
|
21826
|
+
await fs61.access(path73.join(this.projectPath, ".cursorrules"));
|
|
21826
21827
|
agents.push("cursor");
|
|
21827
21828
|
} catch {
|
|
21828
21829
|
}
|
|
21829
21830
|
try {
|
|
21830
|
-
await
|
|
21831
|
+
await fs61.access(path73.join(this.projectPath, ".windsurfrules"));
|
|
21831
21832
|
agents.push("windsurf");
|
|
21832
21833
|
} catch {
|
|
21833
21834
|
}
|
|
21834
21835
|
try {
|
|
21835
|
-
await
|
|
21836
|
+
await fs61.access(path73.join(this.projectPath, ".github", "copilot-instructions.md"));
|
|
21836
21837
|
agents.push("copilot");
|
|
21837
21838
|
} catch {
|
|
21838
21839
|
}
|
|
21839
21840
|
try {
|
|
21840
|
-
await
|
|
21841
|
+
await fs61.access(path73.join(os22.homedir(), ".gemini"));
|
|
21841
21842
|
agents.push("gemini");
|
|
21842
21843
|
} catch {
|
|
21843
21844
|
}
|
|
@@ -21847,17 +21848,17 @@ var init_onboarding = __esm({
|
|
|
21847
21848
|
* Detect tech stack from project files
|
|
21848
21849
|
*/
|
|
21849
21850
|
async detectStack() {
|
|
21850
|
-
const
|
|
21851
|
-
const
|
|
21851
|
+
const fs61 = await import("node:fs/promises");
|
|
21852
|
+
const path73 = await import("node:path");
|
|
21852
21853
|
const stack = {
|
|
21853
21854
|
language: "Unknown",
|
|
21854
21855
|
technologies: []
|
|
21855
21856
|
};
|
|
21856
21857
|
try {
|
|
21857
|
-
const files = await
|
|
21858
|
+
const files = await fs61.readdir(this.projectPath);
|
|
21858
21859
|
if (files.includes("package.json")) {
|
|
21859
|
-
const pkgPath =
|
|
21860
|
-
const pkgContent = await
|
|
21860
|
+
const pkgPath = path73.join(this.projectPath, "package.json");
|
|
21861
|
+
const pkgContent = await fs61.readFile(pkgPath, "utf-8");
|
|
21861
21862
|
const pkg = JSON.parse(pkgContent);
|
|
21862
21863
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
21863
21864
|
stack.language = deps.typescript ? "TypeScript" : "JavaScript";
|
|
@@ -22983,7 +22984,10 @@ var init_analysis2 = __esm({
|
|
|
22983
22984
|
if (!isNonInteractive) {
|
|
22984
22985
|
output_default.spin("Analyzing changes...");
|
|
22985
22986
|
}
|
|
22986
|
-
const result2 = await syncService.sync(projectPath, {
|
|
22987
|
+
const result2 = await syncService.sync(projectPath, {
|
|
22988
|
+
aiTools: options.aiTools,
|
|
22989
|
+
full: options.full
|
|
22990
|
+
});
|
|
22987
22991
|
if (!result2.success) {
|
|
22988
22992
|
if (isNonInteractive) {
|
|
22989
22993
|
console.log(JSON.stringify({ success: false, error: result2.error || "Sync failed" }));
|
|
@@ -23097,7 +23101,10 @@ ${formatFullDiff(diff)}`);
|
|
|
23097
23101
|
return this.showSyncResult(result2, startTime);
|
|
23098
23102
|
}
|
|
23099
23103
|
output_default.spin("Syncing project...");
|
|
23100
|
-
const result = await syncService.sync(projectPath, {
|
|
23104
|
+
const result = await syncService.sync(projectPath, {
|
|
23105
|
+
aiTools: options.aiTools,
|
|
23106
|
+
full: options.full
|
|
23107
|
+
});
|
|
23101
23108
|
if (!result.success) {
|
|
23102
23109
|
output_default.fail(result.error || "Sync failed");
|
|
23103
23110
|
return { success: false, error: result.error };
|
|
@@ -24082,8 +24089,8 @@ Generated: ${(/* @__PURE__ */ new Date()).toLocaleString()}
|
|
|
24082
24089
|
const globalPath2 = path_manager_default.getGlobalProjectPath(projectId);
|
|
24083
24090
|
const specsPath2 = path45.join(globalPath2, "planning", "specs");
|
|
24084
24091
|
try {
|
|
24085
|
-
const
|
|
24086
|
-
const files = await
|
|
24092
|
+
const fs61 = await import("node:fs/promises");
|
|
24093
|
+
const files = await fs61.readdir(specsPath2);
|
|
24087
24094
|
const specs = files.filter((f) => f.endsWith(".md") && f !== ".gitkeep");
|
|
24088
24095
|
if (specs.length === 0) {
|
|
24089
24096
|
output_default.warn("no specs yet");
|
|
@@ -25010,9 +25017,765 @@ var init_ai_tools = __esm({
|
|
|
25010
25017
|
}
|
|
25011
25018
|
});
|
|
25012
25019
|
|
|
25013
|
-
// core/
|
|
25020
|
+
// core/domain/bm25.ts
|
|
25014
25021
|
import fs46 from "node:fs/promises";
|
|
25015
25022
|
import path49 from "node:path";
|
|
25023
|
+
function splitIdentifier(identifier) {
|
|
25024
|
+
return identifier.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/[-_./]/g, " ").toLowerCase().split(/\s+/).filter((w) => w.length > 1);
|
|
25025
|
+
}
|
|
25026
|
+
function tokenizeFile(content, filePath) {
|
|
25027
|
+
const tokens = [];
|
|
25028
|
+
const pathParts = filePath.replace(/\.[^.]+$/, "").split(/[/\\]/).filter(Boolean);
|
|
25029
|
+
for (const part of pathParts) {
|
|
25030
|
+
tokens.push(...splitIdentifier(part));
|
|
25031
|
+
}
|
|
25032
|
+
const exportPatterns = [
|
|
25033
|
+
/export\s+(?:async\s+)?function\s+(\w+)/g,
|
|
25034
|
+
/export\s+class\s+(\w+)/g,
|
|
25035
|
+
/export\s+interface\s+(\w+)/g,
|
|
25036
|
+
/export\s+type\s+(\w+)/g,
|
|
25037
|
+
/export\s+(?:const|let|var)\s+(\w+)/g,
|
|
25038
|
+
/export\s+default\s+(?:class|function)\s+(\w+)/g
|
|
25039
|
+
];
|
|
25040
|
+
for (const pattern of exportPatterns) {
|
|
25041
|
+
let match;
|
|
25042
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
25043
|
+
if (match[1]) {
|
|
25044
|
+
tokens.push(...splitIdentifier(match[1]));
|
|
25045
|
+
}
|
|
25046
|
+
}
|
|
25047
|
+
}
|
|
25048
|
+
const declPatterns = [
|
|
25049
|
+
/(?:async\s+)?function\s+(\w+)/g,
|
|
25050
|
+
/class\s+(\w+)/g,
|
|
25051
|
+
/interface\s+(\w+)/g,
|
|
25052
|
+
/type\s+(\w+)\s*=/g
|
|
25053
|
+
];
|
|
25054
|
+
for (const pattern of declPatterns) {
|
|
25055
|
+
let match;
|
|
25056
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
25057
|
+
if (match[1]) {
|
|
25058
|
+
tokens.push(...splitIdentifier(match[1]));
|
|
25059
|
+
}
|
|
25060
|
+
}
|
|
25061
|
+
}
|
|
25062
|
+
const importPattern = /(?:from|import)\s+['"]([^'"]+)['"]/g;
|
|
25063
|
+
let importMatch;
|
|
25064
|
+
while ((importMatch = importPattern.exec(content)) !== null) {
|
|
25065
|
+
const source = importMatch[1];
|
|
25066
|
+
if (source.startsWith(".") || source.startsWith("@/")) {
|
|
25067
|
+
tokens.push(...splitIdentifier(source));
|
|
25068
|
+
} else {
|
|
25069
|
+
const pkgName = source.startsWith("@") ? source.split("/").slice(0, 2).join("/") : source.split("/")[0];
|
|
25070
|
+
tokens.push(...splitIdentifier(pkgName));
|
|
25071
|
+
}
|
|
25072
|
+
}
|
|
25073
|
+
const singleLineComments = /\/\/\s*(.+)/g;
|
|
25074
|
+
let commentMatch;
|
|
25075
|
+
while ((commentMatch = singleLineComments.exec(content)) !== null) {
|
|
25076
|
+
const words = commentMatch[1].toLowerCase().split(/\s+/).filter((w) => w.length > 2);
|
|
25077
|
+
tokens.push(...words);
|
|
25078
|
+
}
|
|
25079
|
+
const multiLineComments = /\/\*\*?([\s\S]*?)\*\//g;
|
|
25080
|
+
let multiMatch;
|
|
25081
|
+
while ((multiMatch = multiLineComments.exec(content)) !== null) {
|
|
25082
|
+
const words = multiMatch[1].replace(/@\w+/g, "").replace(/\*/g, "").toLowerCase().split(/\s+/).filter((w) => w.length > 2 && /^[a-z]+$/.test(w));
|
|
25083
|
+
tokens.push(...words);
|
|
25084
|
+
}
|
|
25085
|
+
return tokens.filter((t) => t.length > 1 && !STOP_WORDS.has(t) && /^[a-z][a-z0-9]*$/.test(t));
|
|
25086
|
+
}
|
|
25087
|
+
async function listFiles2(dir, projectPath) {
|
|
25088
|
+
const files = [];
|
|
25089
|
+
const entries = await fs46.readdir(dir, { withFileTypes: true });
|
|
25090
|
+
for (const entry of entries) {
|
|
25091
|
+
if (SKIP_DIRS.has(entry.name)) continue;
|
|
25092
|
+
const fullPath = path49.join(dir, entry.name);
|
|
25093
|
+
if (entry.isDirectory()) {
|
|
25094
|
+
files.push(...await listFiles2(fullPath, projectPath));
|
|
25095
|
+
} else if (entry.isFile()) {
|
|
25096
|
+
const ext = path49.extname(entry.name).toLowerCase();
|
|
25097
|
+
if (INDEXABLE_EXTENSIONS.has(ext)) {
|
|
25098
|
+
files.push(path49.relative(projectPath, fullPath));
|
|
25099
|
+
}
|
|
25100
|
+
}
|
|
25101
|
+
}
|
|
25102
|
+
return files;
|
|
25103
|
+
}
|
|
25104
|
+
async function buildIndex(projectPath) {
|
|
25105
|
+
const files = await listFiles2(projectPath, projectPath);
|
|
25106
|
+
const documents = {};
|
|
25107
|
+
const invertedIndex = {};
|
|
25108
|
+
let totalLength = 0;
|
|
25109
|
+
const BATCH_SIZE = 50;
|
|
25110
|
+
for (let i = 0; i < files.length; i += BATCH_SIZE) {
|
|
25111
|
+
const batch = files.slice(i, i + BATCH_SIZE);
|
|
25112
|
+
const results = await Promise.all(
|
|
25113
|
+
batch.map(async (filePath) => {
|
|
25114
|
+
try {
|
|
25115
|
+
const content = await fs46.readFile(path49.join(projectPath, filePath), "utf-8");
|
|
25116
|
+
const tokens = tokenizeFile(content, filePath);
|
|
25117
|
+
return { filePath, tokens };
|
|
25118
|
+
} catch {
|
|
25119
|
+
return { filePath, tokens: [] };
|
|
25120
|
+
}
|
|
25121
|
+
})
|
|
25122
|
+
);
|
|
25123
|
+
for (const { filePath, tokens } of results) {
|
|
25124
|
+
if (tokens.length === 0) continue;
|
|
25125
|
+
documents[filePath] = { tokens, length: tokens.length };
|
|
25126
|
+
totalLength += tokens.length;
|
|
25127
|
+
const tfMap = /* @__PURE__ */ new Map();
|
|
25128
|
+
for (const token of tokens) {
|
|
25129
|
+
tfMap.set(token, (tfMap.get(token) || 0) + 1);
|
|
25130
|
+
}
|
|
25131
|
+
for (const [token, tf] of tfMap) {
|
|
25132
|
+
if (!invertedIndex[token]) {
|
|
25133
|
+
invertedIndex[token] = [];
|
|
25134
|
+
}
|
|
25135
|
+
invertedIndex[token].push({ path: filePath, tf });
|
|
25136
|
+
}
|
|
25137
|
+
}
|
|
25138
|
+
}
|
|
25139
|
+
const totalDocs = Object.keys(documents).length;
|
|
25140
|
+
return {
|
|
25141
|
+
documents,
|
|
25142
|
+
invertedIndex,
|
|
25143
|
+
avgDocLength: totalDocs > 0 ? totalLength / totalDocs : 0,
|
|
25144
|
+
totalDocs,
|
|
25145
|
+
builtAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
25146
|
+
};
|
|
25147
|
+
}
|
|
25148
|
+
function saveIndex(projectId, index) {
|
|
25149
|
+
const storable = {
|
|
25150
|
+
invertedIndex: index.invertedIndex,
|
|
25151
|
+
avgDocLength: index.avgDocLength,
|
|
25152
|
+
totalDocs: index.totalDocs,
|
|
25153
|
+
builtAt: index.builtAt,
|
|
25154
|
+
// Store document lengths (needed for scoring) but not full token lists
|
|
25155
|
+
docLengths: Object.fromEntries(Object.entries(index.documents).map(([p, d]) => [p, d.length]))
|
|
25156
|
+
};
|
|
25157
|
+
database_default.setDoc(projectId, INDEX_KEY, storable);
|
|
25158
|
+
}
|
|
25159
|
+
async function indexProject(projectPath, projectId) {
|
|
25160
|
+
const index = await buildIndex(projectPath);
|
|
25161
|
+
saveIndex(projectId, index);
|
|
25162
|
+
return index;
|
|
25163
|
+
}
|
|
25164
|
+
var INDEXABLE_EXTENSIONS, STOP_WORDS, SKIP_DIRS, INDEX_KEY;
|
|
25165
|
+
var init_bm25 = __esm({
|
|
25166
|
+
"core/domain/bm25.ts"() {
|
|
25167
|
+
"use strict";
|
|
25168
|
+
init_database();
|
|
25169
|
+
INDEXABLE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
25170
|
+
".ts",
|
|
25171
|
+
".tsx",
|
|
25172
|
+
".js",
|
|
25173
|
+
".jsx",
|
|
25174
|
+
".mjs",
|
|
25175
|
+
".cjs",
|
|
25176
|
+
".py",
|
|
25177
|
+
".go",
|
|
25178
|
+
".rs",
|
|
25179
|
+
".java",
|
|
25180
|
+
".cs",
|
|
25181
|
+
".rb",
|
|
25182
|
+
".php",
|
|
25183
|
+
".vue",
|
|
25184
|
+
".svelte"
|
|
25185
|
+
]);
|
|
25186
|
+
STOP_WORDS = /* @__PURE__ */ new Set([
|
|
25187
|
+
"the",
|
|
25188
|
+
"a",
|
|
25189
|
+
"an",
|
|
25190
|
+
"is",
|
|
25191
|
+
"are",
|
|
25192
|
+
"was",
|
|
25193
|
+
"were",
|
|
25194
|
+
"be",
|
|
25195
|
+
"been",
|
|
25196
|
+
"being",
|
|
25197
|
+
"have",
|
|
25198
|
+
"has",
|
|
25199
|
+
"had",
|
|
25200
|
+
"do",
|
|
25201
|
+
"does",
|
|
25202
|
+
"did",
|
|
25203
|
+
"will",
|
|
25204
|
+
"would",
|
|
25205
|
+
"could",
|
|
25206
|
+
"should",
|
|
25207
|
+
"may",
|
|
25208
|
+
"might",
|
|
25209
|
+
"shall",
|
|
25210
|
+
"can",
|
|
25211
|
+
"of",
|
|
25212
|
+
"in",
|
|
25213
|
+
"to",
|
|
25214
|
+
"for",
|
|
25215
|
+
"with",
|
|
25216
|
+
"on",
|
|
25217
|
+
"at",
|
|
25218
|
+
"from",
|
|
25219
|
+
"by",
|
|
25220
|
+
"as",
|
|
25221
|
+
"or",
|
|
25222
|
+
"and",
|
|
25223
|
+
"but",
|
|
25224
|
+
"if",
|
|
25225
|
+
"not",
|
|
25226
|
+
"no",
|
|
25227
|
+
"so",
|
|
25228
|
+
"up",
|
|
25229
|
+
"out",
|
|
25230
|
+
"this",
|
|
25231
|
+
"that",
|
|
25232
|
+
"it",
|
|
25233
|
+
"its",
|
|
25234
|
+
"all",
|
|
25235
|
+
"any",
|
|
25236
|
+
// Code noise
|
|
25237
|
+
"import",
|
|
25238
|
+
"export",
|
|
25239
|
+
"default",
|
|
25240
|
+
"const",
|
|
25241
|
+
"let",
|
|
25242
|
+
"var",
|
|
25243
|
+
"function",
|
|
25244
|
+
"class",
|
|
25245
|
+
"interface",
|
|
25246
|
+
"type",
|
|
25247
|
+
"return",
|
|
25248
|
+
"new",
|
|
25249
|
+
"true",
|
|
25250
|
+
"false",
|
|
25251
|
+
"null",
|
|
25252
|
+
"undefined",
|
|
25253
|
+
"void",
|
|
25254
|
+
"async",
|
|
25255
|
+
"await",
|
|
25256
|
+
"static",
|
|
25257
|
+
"public",
|
|
25258
|
+
"private",
|
|
25259
|
+
"protected",
|
|
25260
|
+
"readonly",
|
|
25261
|
+
"string",
|
|
25262
|
+
"number",
|
|
25263
|
+
"boolean",
|
|
25264
|
+
"object",
|
|
25265
|
+
"array"
|
|
25266
|
+
]);
|
|
25267
|
+
SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
25268
|
+
"node_modules",
|
|
25269
|
+
".git",
|
|
25270
|
+
"dist",
|
|
25271
|
+
"build",
|
|
25272
|
+
"out",
|
|
25273
|
+
".next",
|
|
25274
|
+
"coverage",
|
|
25275
|
+
".cache",
|
|
25276
|
+
".turbo",
|
|
25277
|
+
".vercel",
|
|
25278
|
+
"__pycache__",
|
|
25279
|
+
"vendor",
|
|
25280
|
+
"target"
|
|
25281
|
+
]);
|
|
25282
|
+
__name(splitIdentifier, "splitIdentifier");
|
|
25283
|
+
__name(tokenizeFile, "tokenizeFile");
|
|
25284
|
+
__name(listFiles2, "listFiles");
|
|
25285
|
+
__name(buildIndex, "buildIndex");
|
|
25286
|
+
INDEX_KEY = "bm25-index";
|
|
25287
|
+
__name(saveIndex, "saveIndex");
|
|
25288
|
+
__name(indexProject, "indexProject");
|
|
25289
|
+
}
|
|
25290
|
+
});
|
|
25291
|
+
|
|
25292
|
+
// core/domain/import-graph.ts
|
|
25293
|
+
import fs47 from "node:fs/promises";
|
|
25294
|
+
import path50 from "node:path";
|
|
25295
|
+
function extractImportSources(content) {
|
|
25296
|
+
const sources = [];
|
|
25297
|
+
let match;
|
|
25298
|
+
const regex = new RegExp(IMPORT_REGEX.source, "g");
|
|
25299
|
+
while ((match = regex.exec(content)) !== null) {
|
|
25300
|
+
const source = match[1];
|
|
25301
|
+
if (source.startsWith(".") || source.startsWith("@/")) {
|
|
25302
|
+
sources.push(source);
|
|
25303
|
+
}
|
|
25304
|
+
}
|
|
25305
|
+
return sources;
|
|
25306
|
+
}
|
|
25307
|
+
async function resolveImport2(source, fromFile, projectPath) {
|
|
25308
|
+
let basePath;
|
|
25309
|
+
if (source.startsWith("@/")) {
|
|
25310
|
+
basePath = path50.join(projectPath, "src", source.slice(2));
|
|
25311
|
+
} else {
|
|
25312
|
+
const fromDir = path50.dirname(path50.join(projectPath, fromFile));
|
|
25313
|
+
basePath = path50.resolve(fromDir, source);
|
|
25314
|
+
}
|
|
25315
|
+
for (const ext of RESOLVE_EXTENSIONS) {
|
|
25316
|
+
const fullPath = basePath + ext;
|
|
25317
|
+
try {
|
|
25318
|
+
const stat = await fs47.stat(fullPath);
|
|
25319
|
+
if (stat.isFile()) {
|
|
25320
|
+
return path50.relative(projectPath, fullPath);
|
|
25321
|
+
}
|
|
25322
|
+
} catch {
|
|
25323
|
+
}
|
|
25324
|
+
}
|
|
25325
|
+
return null;
|
|
25326
|
+
}
|
|
25327
|
+
async function listFiles3(dir, projectPath) {
|
|
25328
|
+
const files = [];
|
|
25329
|
+
const entries = await fs47.readdir(dir, { withFileTypes: true });
|
|
25330
|
+
for (const entry of entries) {
|
|
25331
|
+
if (SKIP_DIRS2.has(entry.name)) continue;
|
|
25332
|
+
const fullPath = path50.join(dir, entry.name);
|
|
25333
|
+
if (entry.isDirectory()) {
|
|
25334
|
+
files.push(...await listFiles3(fullPath, projectPath));
|
|
25335
|
+
} else if (entry.isFile()) {
|
|
25336
|
+
const ext = path50.extname(entry.name).toLowerCase();
|
|
25337
|
+
if (INDEXABLE_EXTENSIONS2.has(ext)) {
|
|
25338
|
+
files.push(path50.relative(projectPath, fullPath));
|
|
25339
|
+
}
|
|
25340
|
+
}
|
|
25341
|
+
}
|
|
25342
|
+
return files;
|
|
25343
|
+
}
|
|
25344
|
+
async function buildGraph(projectPath) {
|
|
25345
|
+
const files = await listFiles3(projectPath, projectPath);
|
|
25346
|
+
const forward = {};
|
|
25347
|
+
const reverse = {};
|
|
25348
|
+
let edgeCount = 0;
|
|
25349
|
+
const BATCH_SIZE = 50;
|
|
25350
|
+
for (let i = 0; i < files.length; i += BATCH_SIZE) {
|
|
25351
|
+
const batch = files.slice(i, i + BATCH_SIZE);
|
|
25352
|
+
const results = await Promise.all(
|
|
25353
|
+
batch.map(async (filePath) => {
|
|
25354
|
+
try {
|
|
25355
|
+
const content = await fs47.readFile(path50.join(projectPath, filePath), "utf-8");
|
|
25356
|
+
const sources = extractImportSources(content);
|
|
25357
|
+
const resolved = [];
|
|
25358
|
+
for (const source of sources) {
|
|
25359
|
+
const target = await resolveImport2(source, filePath, projectPath);
|
|
25360
|
+
if (target && target !== filePath) {
|
|
25361
|
+
resolved.push(target);
|
|
25362
|
+
}
|
|
25363
|
+
}
|
|
25364
|
+
return { filePath, imports: resolved };
|
|
25365
|
+
} catch {
|
|
25366
|
+
return { filePath, imports: [] };
|
|
25367
|
+
}
|
|
25368
|
+
})
|
|
25369
|
+
);
|
|
25370
|
+
for (const { filePath, imports } of results) {
|
|
25371
|
+
if (imports.length === 0) continue;
|
|
25372
|
+
forward[filePath] = imports;
|
|
25373
|
+
edgeCount += imports.length;
|
|
25374
|
+
for (const target of imports) {
|
|
25375
|
+
if (!reverse[target]) reverse[target] = [];
|
|
25376
|
+
reverse[target].push(filePath);
|
|
25377
|
+
}
|
|
25378
|
+
}
|
|
25379
|
+
}
|
|
25380
|
+
return {
|
|
25381
|
+
forward,
|
|
25382
|
+
reverse,
|
|
25383
|
+
fileCount: files.length,
|
|
25384
|
+
edgeCount,
|
|
25385
|
+
builtAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
25386
|
+
};
|
|
25387
|
+
}
|
|
25388
|
+
function saveGraph(projectId, graph) {
|
|
25389
|
+
database_default.setDoc(projectId, INDEX_KEY2, graph);
|
|
25390
|
+
}
|
|
25391
|
+
function loadGraph(projectId) {
|
|
25392
|
+
return database_default.getDoc(projectId, INDEX_KEY2);
|
|
25393
|
+
}
|
|
25394
|
+
async function indexImports(projectPath, projectId) {
|
|
25395
|
+
const graph = await buildGraph(projectPath);
|
|
25396
|
+
saveGraph(projectId, graph);
|
|
25397
|
+
return graph;
|
|
25398
|
+
}
|
|
25399
|
+
var INDEXABLE_EXTENSIONS2, SKIP_DIRS2, RESOLVE_EXTENSIONS, IMPORT_REGEX, INDEX_KEY2;
|
|
25400
|
+
var init_import_graph = __esm({
|
|
25401
|
+
"core/domain/import-graph.ts"() {
|
|
25402
|
+
"use strict";
|
|
25403
|
+
init_database();
|
|
25404
|
+
INDEXABLE_EXTENSIONS2 = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
25405
|
+
SKIP_DIRS2 = /* @__PURE__ */ new Set([
|
|
25406
|
+
"node_modules",
|
|
25407
|
+
".git",
|
|
25408
|
+
"dist",
|
|
25409
|
+
"build",
|
|
25410
|
+
"out",
|
|
25411
|
+
".next",
|
|
25412
|
+
"coverage",
|
|
25413
|
+
".cache",
|
|
25414
|
+
".turbo",
|
|
25415
|
+
".vercel"
|
|
25416
|
+
]);
|
|
25417
|
+
RESOLVE_EXTENSIONS = ["", ".ts", ".tsx", ".js", ".jsx", "/index.ts", "/index.js"];
|
|
25418
|
+
IMPORT_REGEX = /(?:import|from)\s+['"]([^'"]+)['"]/g;
|
|
25419
|
+
__name(extractImportSources, "extractImportSources");
|
|
25420
|
+
__name(resolveImport2, "resolveImport");
|
|
25421
|
+
__name(listFiles3, "listFiles");
|
|
25422
|
+
__name(buildGraph, "buildGraph");
|
|
25423
|
+
INDEX_KEY2 = "import-graph";
|
|
25424
|
+
__name(saveGraph, "saveGraph");
|
|
25425
|
+
__name(loadGraph, "loadGraph");
|
|
25426
|
+
__name(indexImports, "indexImports");
|
|
25427
|
+
}
|
|
25428
|
+
});
|
|
25429
|
+
|
|
25430
|
+
// core/domain/change-propagator.ts
|
|
25431
|
+
function propagateChanges(diff, projectId) {
|
|
25432
|
+
const directlyChanged = [...diff.added, ...diff.modified];
|
|
25433
|
+
const directSet = new Set(directlyChanged);
|
|
25434
|
+
const affected = /* @__PURE__ */ new Set();
|
|
25435
|
+
const graph = loadGraph(projectId);
|
|
25436
|
+
if (graph) {
|
|
25437
|
+
for (const changedFile of directlyChanged) {
|
|
25438
|
+
const importers = graph.reverse[changedFile];
|
|
25439
|
+
if (importers) {
|
|
25440
|
+
for (const importer of importers) {
|
|
25441
|
+
if (!directSet.has(importer)) {
|
|
25442
|
+
affected.add(importer);
|
|
25443
|
+
}
|
|
25444
|
+
}
|
|
25445
|
+
}
|
|
25446
|
+
}
|
|
25447
|
+
}
|
|
25448
|
+
const affectedByImports = Array.from(affected);
|
|
25449
|
+
const allAffected = [...directlyChanged, ...affectedByImports];
|
|
25450
|
+
return {
|
|
25451
|
+
directlyChanged,
|
|
25452
|
+
affectedByImports,
|
|
25453
|
+
deleted: diff.deleted,
|
|
25454
|
+
allAffected
|
|
25455
|
+
};
|
|
25456
|
+
}
|
|
25457
|
+
function affectedDomains(changedFiles) {
|
|
25458
|
+
const domains = /* @__PURE__ */ new Set();
|
|
25459
|
+
for (const file of changedFiles) {
|
|
25460
|
+
const lower = file.toLowerCase();
|
|
25461
|
+
if (lower.endsWith(".tsx") || lower.endsWith(".jsx") || lower.endsWith(".css") || lower.endsWith(".scss") || lower.endsWith(".vue") || lower.endsWith(".svelte") || lower.includes("/components/") || lower.includes("/pages/") || lower.includes("/app/")) {
|
|
25462
|
+
domains.add("frontend");
|
|
25463
|
+
domains.add("uxui");
|
|
25464
|
+
}
|
|
25465
|
+
if (lower.includes(".test.") || lower.includes(".spec.") || lower.includes("__tests__") || lower.includes("/test/")) {
|
|
25466
|
+
domains.add("testing");
|
|
25467
|
+
}
|
|
25468
|
+
if (lower.includes("dockerfile") || lower.includes("docker-compose") || lower.includes(".dockerignore") || lower.includes(".github/") || lower.includes("ci/") || lower.includes("cd/")) {
|
|
25469
|
+
domains.add("devops");
|
|
25470
|
+
}
|
|
25471
|
+
if (lower.endsWith(".sql") || lower.includes("prisma") || lower.includes("drizzle") || lower.includes("migration") || lower.includes("/db/")) {
|
|
25472
|
+
domains.add("database");
|
|
25473
|
+
}
|
|
25474
|
+
if ((lower.endsWith(".ts") || lower.endsWith(".js")) && !lower.includes(".test.") && !lower.includes(".spec.") && !lower.endsWith(".d.ts")) {
|
|
25475
|
+
domains.add("backend");
|
|
25476
|
+
}
|
|
25477
|
+
}
|
|
25478
|
+
return domains;
|
|
25479
|
+
}
|
|
25480
|
+
var init_change_propagator = __esm({
|
|
25481
|
+
"core/domain/change-propagator.ts"() {
|
|
25482
|
+
"use strict";
|
|
25483
|
+
init_import_graph();
|
|
25484
|
+
__name(propagateChanges, "propagateChanges");
|
|
25485
|
+
__name(affectedDomains, "affectedDomains");
|
|
25486
|
+
}
|
|
25487
|
+
});
|
|
25488
|
+
|
|
25489
|
+
// core/domain/file-hasher.ts
|
|
25490
|
+
import fs48 from "node:fs/promises";
|
|
25491
|
+
import path51 from "node:path";
|
|
25492
|
+
async function listProjectFiles(dir, projectPath) {
|
|
25493
|
+
const files = [];
|
|
25494
|
+
const entries = await fs48.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
25495
|
+
for (const entry of entries) {
|
|
25496
|
+
const name = String(entry.name);
|
|
25497
|
+
if (SKIP_DIRS3.has(name)) continue;
|
|
25498
|
+
if (name.startsWith(".") && name !== ".env.example") continue;
|
|
25499
|
+
const fullPath = path51.join(dir, name);
|
|
25500
|
+
if (entry.isDirectory()) {
|
|
25501
|
+
files.push(...await listProjectFiles(fullPath, projectPath));
|
|
25502
|
+
} else if (entry.isFile()) {
|
|
25503
|
+
const ext = path51.extname(name).toLowerCase();
|
|
25504
|
+
if (INDEXABLE_EXTENSIONS3.has(ext)) {
|
|
25505
|
+
files.push(path51.relative(projectPath, fullPath));
|
|
25506
|
+
}
|
|
25507
|
+
}
|
|
25508
|
+
}
|
|
25509
|
+
return files;
|
|
25510
|
+
}
|
|
25511
|
+
function hashContent(content) {
|
|
25512
|
+
if (typeof Bun !== "undefined" && Bun.hash) {
|
|
25513
|
+
return `xxh64:${Bun.hash(content).toString(36)}`;
|
|
25514
|
+
}
|
|
25515
|
+
let h = 2166136261;
|
|
25516
|
+
for (let i = 0; i < content.length; i++) {
|
|
25517
|
+
h ^= content.charCodeAt(i);
|
|
25518
|
+
h = Math.imul(h, 16777619);
|
|
25519
|
+
}
|
|
25520
|
+
return `fnv1a:${(h >>> 0).toString(36)}`;
|
|
25521
|
+
}
|
|
25522
|
+
async function computeHashes(projectPath) {
|
|
25523
|
+
const filePaths = await listProjectFiles(projectPath, projectPath);
|
|
25524
|
+
const hashes = /* @__PURE__ */ new Map();
|
|
25525
|
+
const BATCH_SIZE = 100;
|
|
25526
|
+
for (let i = 0; i < filePaths.length; i += BATCH_SIZE) {
|
|
25527
|
+
const batch = filePaths.slice(i, i + BATCH_SIZE);
|
|
25528
|
+
const results = await Promise.all(
|
|
25529
|
+
batch.map(async (filePath) => {
|
|
25530
|
+
try {
|
|
25531
|
+
const fullPath = path51.join(projectPath, filePath);
|
|
25532
|
+
const [content, stat] = await Promise.all([
|
|
25533
|
+
fs48.readFile(fullPath, "utf-8"),
|
|
25534
|
+
fs48.stat(fullPath)
|
|
25535
|
+
]);
|
|
25536
|
+
return {
|
|
25537
|
+
path: filePath,
|
|
25538
|
+
hash: hashContent(content),
|
|
25539
|
+
size: stat.size,
|
|
25540
|
+
mtime: stat.mtime.toISOString()
|
|
25541
|
+
};
|
|
25542
|
+
} catch {
|
|
25543
|
+
return null;
|
|
25544
|
+
}
|
|
25545
|
+
})
|
|
25546
|
+
);
|
|
25547
|
+
for (const result of results) {
|
|
25548
|
+
if (result) {
|
|
25549
|
+
hashes.set(result.path, result);
|
|
25550
|
+
}
|
|
25551
|
+
}
|
|
25552
|
+
}
|
|
25553
|
+
return hashes;
|
|
25554
|
+
}
|
|
25555
|
+
function diffHashes(current, stored) {
|
|
25556
|
+
const added = [];
|
|
25557
|
+
const modified = [];
|
|
25558
|
+
const unchanged = [];
|
|
25559
|
+
for (const [filePath, currentHash] of current) {
|
|
25560
|
+
const storedHash = stored.get(filePath);
|
|
25561
|
+
if (!storedHash) {
|
|
25562
|
+
added.push(filePath);
|
|
25563
|
+
} else if (storedHash.hash !== currentHash.hash) {
|
|
25564
|
+
modified.push(filePath);
|
|
25565
|
+
} else {
|
|
25566
|
+
unchanged.push(filePath);
|
|
25567
|
+
}
|
|
25568
|
+
}
|
|
25569
|
+
const deleted = [];
|
|
25570
|
+
for (const filePath of stored.keys()) {
|
|
25571
|
+
if (!current.has(filePath)) {
|
|
25572
|
+
deleted.push(filePath);
|
|
25573
|
+
}
|
|
25574
|
+
}
|
|
25575
|
+
return { added, modified, deleted, unchanged };
|
|
25576
|
+
}
|
|
25577
|
+
function saveHashes(projectId, hashes) {
|
|
25578
|
+
const db = database_default.getDb(projectId);
|
|
25579
|
+
db.transaction(() => {
|
|
25580
|
+
db.prepare("DELETE FROM index_checksums").run();
|
|
25581
|
+
const insert = db.prepare(
|
|
25582
|
+
"INSERT INTO index_checksums (path, checksum, size, mtime) VALUES (?, ?, ?, ?)"
|
|
25583
|
+
);
|
|
25584
|
+
for (const [, hash] of hashes) {
|
|
25585
|
+
insert.run(hash.path, hash.hash, hash.size, hash.mtime);
|
|
25586
|
+
}
|
|
25587
|
+
})();
|
|
25588
|
+
database_default.setDoc(projectId, "file-hashes-meta", {
|
|
25589
|
+
fileCount: hashes.size,
|
|
25590
|
+
builtAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
25591
|
+
});
|
|
25592
|
+
}
|
|
25593
|
+
function loadHashes(projectId) {
|
|
25594
|
+
const hashes = /* @__PURE__ */ new Map();
|
|
25595
|
+
try {
|
|
25596
|
+
const rows = database_default.query(
|
|
25597
|
+
projectId,
|
|
25598
|
+
"SELECT path, checksum, size, mtime FROM index_checksums"
|
|
25599
|
+
);
|
|
25600
|
+
for (const row of rows) {
|
|
25601
|
+
hashes.set(row.path, {
|
|
25602
|
+
path: row.path,
|
|
25603
|
+
hash: row.checksum,
|
|
25604
|
+
size: row.size || 0,
|
|
25605
|
+
mtime: row.mtime || ""
|
|
25606
|
+
});
|
|
25607
|
+
}
|
|
25608
|
+
} catch {
|
|
25609
|
+
}
|
|
25610
|
+
return hashes;
|
|
25611
|
+
}
|
|
25612
|
+
async function detectChanges(projectPath, projectId) {
|
|
25613
|
+
const [currentHashes, storedHashes] = await Promise.all([
|
|
25614
|
+
computeHashes(projectPath),
|
|
25615
|
+
Promise.resolve(loadHashes(projectId))
|
|
25616
|
+
]);
|
|
25617
|
+
const diff = diffHashes(currentHashes, storedHashes);
|
|
25618
|
+
return { diff, currentHashes };
|
|
25619
|
+
}
|
|
25620
|
+
function hasHashRegistry(projectId) {
|
|
25621
|
+
return database_default.hasDoc(projectId, "file-hashes-meta");
|
|
25622
|
+
}
|
|
25623
|
+
var INDEXABLE_EXTENSIONS3, SKIP_DIRS3;
|
|
25624
|
+
var init_file_hasher = __esm({
|
|
25625
|
+
"core/domain/file-hasher.ts"() {
|
|
25626
|
+
"use strict";
|
|
25627
|
+
init_database();
|
|
25628
|
+
INDEXABLE_EXTENSIONS3 = /* @__PURE__ */ new Set([
|
|
25629
|
+
".ts",
|
|
25630
|
+
".tsx",
|
|
25631
|
+
".js",
|
|
25632
|
+
".jsx",
|
|
25633
|
+
".mjs",
|
|
25634
|
+
".cjs",
|
|
25635
|
+
".json",
|
|
25636
|
+
".md",
|
|
25637
|
+
".css",
|
|
25638
|
+
".scss",
|
|
25639
|
+
".html",
|
|
25640
|
+
".vue",
|
|
25641
|
+
".svelte",
|
|
25642
|
+
".py",
|
|
25643
|
+
".go",
|
|
25644
|
+
".rs",
|
|
25645
|
+
".yaml",
|
|
25646
|
+
".yml",
|
|
25647
|
+
".toml"
|
|
25648
|
+
]);
|
|
25649
|
+
SKIP_DIRS3 = /* @__PURE__ */ new Set([
|
|
25650
|
+
"node_modules",
|
|
25651
|
+
".git",
|
|
25652
|
+
"dist",
|
|
25653
|
+
"build",
|
|
25654
|
+
"out",
|
|
25655
|
+
".next",
|
|
25656
|
+
"coverage",
|
|
25657
|
+
".cache",
|
|
25658
|
+
".turbo",
|
|
25659
|
+
".vercel",
|
|
25660
|
+
".prjct"
|
|
25661
|
+
]);
|
|
25662
|
+
__name(listProjectFiles, "listProjectFiles");
|
|
25663
|
+
__name(hashContent, "hashContent");
|
|
25664
|
+
__name(computeHashes, "computeHashes");
|
|
25665
|
+
__name(diffHashes, "diffHashes");
|
|
25666
|
+
__name(saveHashes, "saveHashes");
|
|
25667
|
+
__name(loadHashes, "loadHashes");
|
|
25668
|
+
__name(detectChanges, "detectChanges");
|
|
25669
|
+
__name(hasHashRegistry, "hasHashRegistry");
|
|
25670
|
+
}
|
|
25671
|
+
});
|
|
25672
|
+
|
|
25673
|
+
// core/domain/git-cochange.ts
|
|
25674
|
+
import { exec as execCallback7 } from "node:child_process";
|
|
25675
|
+
import { promisify as promisify15 } from "node:util";
|
|
25676
|
+
async function parseGitLog(projectPath, maxCommits = 100) {
|
|
25677
|
+
try {
|
|
25678
|
+
const { stdout } = await exec14(
|
|
25679
|
+
`git log --name-only --pretty=format:'---COMMIT---' -${maxCommits}`,
|
|
25680
|
+
{ cwd: projectPath, maxBuffer: 10 * 1024 * 1024 }
|
|
25681
|
+
);
|
|
25682
|
+
const commits = [];
|
|
25683
|
+
let currentFiles = null;
|
|
25684
|
+
for (const line of stdout.split("\n")) {
|
|
25685
|
+
const trimmed = line.trim();
|
|
25686
|
+
if (trimmed === "---COMMIT---") {
|
|
25687
|
+
if (currentFiles && currentFiles.size > 0 && currentFiles.size <= MAX_FILES_PER_COMMIT) {
|
|
25688
|
+
commits.push(currentFiles);
|
|
25689
|
+
}
|
|
25690
|
+
currentFiles = /* @__PURE__ */ new Set();
|
|
25691
|
+
} else if (trimmed && currentFiles) {
|
|
25692
|
+
if (isSourceFile(trimmed)) {
|
|
25693
|
+
currentFiles.add(trimmed);
|
|
25694
|
+
}
|
|
25695
|
+
}
|
|
25696
|
+
}
|
|
25697
|
+
if (currentFiles && currentFiles.size > 0 && currentFiles.size <= MAX_FILES_PER_COMMIT) {
|
|
25698
|
+
commits.push(currentFiles);
|
|
25699
|
+
}
|
|
25700
|
+
return commits;
|
|
25701
|
+
} catch {
|
|
25702
|
+
return [];
|
|
25703
|
+
}
|
|
25704
|
+
}
|
|
25705
|
+
function isSourceFile(filePath) {
|
|
25706
|
+
const sourceExtensions = /\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|cs|rb|php|vue|svelte)$/i;
|
|
25707
|
+
return sourceExtensions.test(filePath) && !filePath.includes("node_modules/");
|
|
25708
|
+
}
|
|
25709
|
+
async function buildMatrix(projectPath, maxCommits = 100) {
|
|
25710
|
+
const commitSets = await parseGitLog(projectPath, maxCommits);
|
|
25711
|
+
const fileCommitCount = /* @__PURE__ */ new Map();
|
|
25712
|
+
const pairCount = /* @__PURE__ */ new Map();
|
|
25713
|
+
for (const files of commitSets) {
|
|
25714
|
+
const fileArray = Array.from(files);
|
|
25715
|
+
for (const file of fileArray) {
|
|
25716
|
+
fileCommitCount.set(file, (fileCommitCount.get(file) || 0) + 1);
|
|
25717
|
+
}
|
|
25718
|
+
for (let i = 0; i < fileArray.length; i++) {
|
|
25719
|
+
for (let j = i + 1; j < fileArray.length; j++) {
|
|
25720
|
+
const key = pairKey(fileArray[i], fileArray[j]);
|
|
25721
|
+
pairCount.set(key, (pairCount.get(key) || 0) + 1);
|
|
25722
|
+
}
|
|
25723
|
+
}
|
|
25724
|
+
}
|
|
25725
|
+
const matrix = {};
|
|
25726
|
+
for (const [key, count] of pairCount) {
|
|
25727
|
+
const [fileA, fileB] = key.split("\0");
|
|
25728
|
+
const countA = fileCommitCount.get(fileA) || 0;
|
|
25729
|
+
const countB = fileCommitCount.get(fileB) || 0;
|
|
25730
|
+
if (countA < MIN_FILE_OCCURRENCES || countB < MIN_FILE_OCCURRENCES) continue;
|
|
25731
|
+
const unionCount = countA + countB - count;
|
|
25732
|
+
const similarity = unionCount > 0 ? count / unionCount : 0;
|
|
25733
|
+
if (similarity < MIN_SIMILARITY) continue;
|
|
25734
|
+
if (!matrix[fileA]) matrix[fileA] = {};
|
|
25735
|
+
if (!matrix[fileB]) matrix[fileB] = {};
|
|
25736
|
+
matrix[fileA][fileB] = similarity;
|
|
25737
|
+
matrix[fileB][fileA] = similarity;
|
|
25738
|
+
}
|
|
25739
|
+
return {
|
|
25740
|
+
matrix,
|
|
25741
|
+
commitsAnalyzed: commitSets.length,
|
|
25742
|
+
filesAnalyzed: fileCommitCount.size,
|
|
25743
|
+
builtAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
25744
|
+
};
|
|
25745
|
+
}
|
|
25746
|
+
function pairKey(a, b) {
|
|
25747
|
+
return a < b ? `${a}\0${b}` : `${b}\0${a}`;
|
|
25748
|
+
}
|
|
25749
|
+
function saveMatrix(projectId, index) {
|
|
25750
|
+
database_default.setDoc(projectId, INDEX_KEY3, index);
|
|
25751
|
+
}
|
|
25752
|
+
async function indexCoChanges(projectPath, projectId, maxCommits = 100) {
|
|
25753
|
+
const index = await buildMatrix(projectPath, maxCommits);
|
|
25754
|
+
saveMatrix(projectId, index);
|
|
25755
|
+
return index;
|
|
25756
|
+
}
|
|
25757
|
+
var exec14, MIN_SIMILARITY, MIN_FILE_OCCURRENCES, MAX_FILES_PER_COMMIT, INDEX_KEY3;
|
|
25758
|
+
var init_git_cochange = __esm({
|
|
25759
|
+
"core/domain/git-cochange.ts"() {
|
|
25760
|
+
"use strict";
|
|
25761
|
+
init_database();
|
|
25762
|
+
exec14 = promisify15(execCallback7);
|
|
25763
|
+
MIN_SIMILARITY = 0.1;
|
|
25764
|
+
MIN_FILE_OCCURRENCES = 2;
|
|
25765
|
+
MAX_FILES_PER_COMMIT = 30;
|
|
25766
|
+
__name(parseGitLog, "parseGitLog");
|
|
25767
|
+
__name(isSourceFile, "isSourceFile");
|
|
25768
|
+
__name(buildMatrix, "buildMatrix");
|
|
25769
|
+
__name(pairKey, "pairKey");
|
|
25770
|
+
INDEX_KEY3 = "cochange-index";
|
|
25771
|
+
__name(saveMatrix, "saveMatrix");
|
|
25772
|
+
__name(indexCoChanges, "indexCoChanges");
|
|
25773
|
+
}
|
|
25774
|
+
});
|
|
25775
|
+
|
|
25776
|
+
// core/services/context-generator.ts
|
|
25777
|
+
import fs49 from "node:fs/promises";
|
|
25778
|
+
import path52 from "node:path";
|
|
25016
25779
|
var ContextFileGenerator;
|
|
25017
25780
|
var init_context_generator = __esm({
|
|
25018
25781
|
"core/services/context-generator.ts"() {
|
|
@@ -25037,10 +25800,10 @@ var init_context_generator = __esm({
|
|
|
25037
25800
|
async writeWithPreservation(filePath, content) {
|
|
25038
25801
|
let finalContent = content;
|
|
25039
25802
|
try {
|
|
25040
|
-
const existingContent = await
|
|
25803
|
+
const existingContent = await fs49.readFile(filePath, "utf-8");
|
|
25041
25804
|
const validation = validatePreserveBlocks(existingContent);
|
|
25042
25805
|
if (!validation.valid) {
|
|
25043
|
-
const filename =
|
|
25806
|
+
const filename = path52.basename(filePath);
|
|
25044
25807
|
console.warn(`\u26A0\uFE0F ${filename} has invalid preserve blocks:`);
|
|
25045
25808
|
for (const error of validation.errors) {
|
|
25046
25809
|
console.warn(` ${error}`);
|
|
@@ -25049,13 +25812,13 @@ var init_context_generator = __esm({
|
|
|
25049
25812
|
finalContent = mergePreservedSections(content, existingContent);
|
|
25050
25813
|
} catch {
|
|
25051
25814
|
}
|
|
25052
|
-
await
|
|
25815
|
+
await fs49.writeFile(filePath, finalContent, "utf-8");
|
|
25053
25816
|
}
|
|
25054
25817
|
/**
|
|
25055
25818
|
* Generate all context files in parallel
|
|
25056
25819
|
*/
|
|
25057
25820
|
async generate(git, stats, commands, agents, sources) {
|
|
25058
|
-
const contextPath =
|
|
25821
|
+
const contextPath = path52.join(this.config.globalPath, "context");
|
|
25059
25822
|
await Promise.all([
|
|
25060
25823
|
this.generateClaudeMd(contextPath, git, stats, commands, agents, sources),
|
|
25061
25824
|
this.generateNowMd(contextPath),
|
|
@@ -25155,7 +25918,7 @@ Load from \`~/.prjct-cli/projects/${this.config.projectId}/agents/\`:
|
|
|
25155
25918
|
**Workflow**: ${workflowAgents.join(", ")}
|
|
25156
25919
|
**Domain**: ${domainAgents.join(", ") || "none"}
|
|
25157
25920
|
`;
|
|
25158
|
-
const claudePath =
|
|
25921
|
+
const claudePath = path52.join(contextPath, "CLAUDE.md");
|
|
25159
25922
|
await this.writeWithPreservation(claudePath, content);
|
|
25160
25923
|
}
|
|
25161
25924
|
/**
|
|
@@ -25164,8 +25927,8 @@ Load from \`~/.prjct-cli/projects/${this.config.projectId}/agents/\`:
|
|
|
25164
25927
|
async generateNowMd(contextPath) {
|
|
25165
25928
|
let currentTask = null;
|
|
25166
25929
|
try {
|
|
25167
|
-
const statePath =
|
|
25168
|
-
const state = JSON.parse(await
|
|
25930
|
+
const statePath = path52.join(this.config.globalPath, "storage", "state.json");
|
|
25931
|
+
const state = JSON.parse(await fs49.readFile(statePath, "utf-8"));
|
|
25169
25932
|
currentTask = state.currentTask;
|
|
25170
25933
|
} catch {
|
|
25171
25934
|
}
|
|
@@ -25181,7 +25944,7 @@ _No active task_
|
|
|
25181
25944
|
|
|
25182
25945
|
Use \`p. task "description"\` to start working.
|
|
25183
25946
|
`;
|
|
25184
|
-
await this.writeWithPreservation(
|
|
25947
|
+
await this.writeWithPreservation(path52.join(contextPath, "now.md"), content);
|
|
25185
25948
|
}
|
|
25186
25949
|
/**
|
|
25187
25950
|
* Generate next.md - task queue
|
|
@@ -25189,15 +25952,15 @@ Use \`p. task "description"\` to start working.
|
|
|
25189
25952
|
async generateNextMd(contextPath) {
|
|
25190
25953
|
let queue = { tasks: [] };
|
|
25191
25954
|
try {
|
|
25192
|
-
const queuePath =
|
|
25193
|
-
queue = JSON.parse(await
|
|
25955
|
+
const queuePath = path52.join(this.config.globalPath, "storage", "queue.json");
|
|
25956
|
+
queue = JSON.parse(await fs49.readFile(queuePath, "utf-8"));
|
|
25194
25957
|
} catch {
|
|
25195
25958
|
}
|
|
25196
25959
|
const content = `# NEXT
|
|
25197
25960
|
|
|
25198
25961
|
${queue.tasks.length > 0 ? queue.tasks.map((t, i) => `${i + 1}. ${t.description}${t.priority ? ` [${t.priority}]` : ""}`).join("\n") : "_Empty queue_"}
|
|
25199
25962
|
`;
|
|
25200
|
-
await this.writeWithPreservation(
|
|
25963
|
+
await this.writeWithPreservation(path52.join(contextPath, "next.md"), content);
|
|
25201
25964
|
}
|
|
25202
25965
|
/**
|
|
25203
25966
|
* Generate ideas.md - captured ideas
|
|
@@ -25205,15 +25968,15 @@ ${queue.tasks.length > 0 ? queue.tasks.map((t, i) => `${i + 1}. ${t.description}
|
|
|
25205
25968
|
async generateIdeasMd(contextPath) {
|
|
25206
25969
|
let ideas = { ideas: [] };
|
|
25207
25970
|
try {
|
|
25208
|
-
const ideasPath =
|
|
25209
|
-
ideas = JSON.parse(await
|
|
25971
|
+
const ideasPath = path52.join(this.config.globalPath, "storage", "ideas.json");
|
|
25972
|
+
ideas = JSON.parse(await fs49.readFile(ideasPath, "utf-8"));
|
|
25210
25973
|
} catch {
|
|
25211
25974
|
}
|
|
25212
25975
|
const content = `# IDEAS
|
|
25213
25976
|
|
|
25214
25977
|
${ideas.ideas.length > 0 ? ideas.ideas.map((i) => `- ${i.text}${i.priority ? ` [${i.priority}]` : ""}`).join("\n") : "_No ideas captured yet_"}
|
|
25215
25978
|
`;
|
|
25216
|
-
await this.writeWithPreservation(
|
|
25979
|
+
await this.writeWithPreservation(path52.join(contextPath, "ideas.md"), content);
|
|
25217
25980
|
}
|
|
25218
25981
|
/**
|
|
25219
25982
|
* Generate shipped.md - completed features
|
|
@@ -25223,8 +25986,8 @@ ${ideas.ideas.length > 0 ? ideas.ideas.map((i) => `- ${i.text}${i.priority ? ` [
|
|
|
25223
25986
|
shipped: []
|
|
25224
25987
|
};
|
|
25225
25988
|
try {
|
|
25226
|
-
const shippedPath =
|
|
25227
|
-
shipped = JSON.parse(await
|
|
25989
|
+
const shippedPath = path52.join(this.config.globalPath, "storage", "shipped.json");
|
|
25990
|
+
shipped = JSON.parse(await fs49.readFile(shippedPath, "utf-8"));
|
|
25228
25991
|
} catch {
|
|
25229
25992
|
}
|
|
25230
25993
|
const content = `# SHIPPED \u{1F680}
|
|
@@ -25233,7 +25996,7 @@ ${shipped.shipped.length > 0 ? shipped.shipped.slice(-10).map((s) => `- **${s.na
|
|
|
25233
25996
|
|
|
25234
25997
|
**Total shipped:** ${shipped.shipped.length}
|
|
25235
25998
|
`;
|
|
25236
|
-
await this.writeWithPreservation(
|
|
25999
|
+
await this.writeWithPreservation(path52.join(contextPath, "shipped.md"), content);
|
|
25237
26000
|
}
|
|
25238
26001
|
// ==========================================================================
|
|
25239
26002
|
// MONOREPO SUPPORT
|
|
@@ -25262,9 +26025,9 @@ ${shipped.shipped.length > 0 ? shipped.shipped.slice(-10).map((s) => `- **${s.na
|
|
|
25262
26025
|
commands,
|
|
25263
26026
|
agents
|
|
25264
26027
|
);
|
|
25265
|
-
const claudePath =
|
|
26028
|
+
const claudePath = path52.join(pkg.path, "CLAUDE.md");
|
|
25266
26029
|
await this.writeWithPreservation(claudePath, content);
|
|
25267
|
-
generatedFiles.push(
|
|
26030
|
+
generatedFiles.push(path52.relative(this.config.projectPath, claudePath));
|
|
25268
26031
|
}
|
|
25269
26032
|
return generatedFiles;
|
|
25270
26033
|
}
|
|
@@ -25277,8 +26040,8 @@ ${shipped.shipped.length > 0 ? shipped.shipped.slice(-10).map((s) => `- **${s.na
|
|
|
25277
26040
|
let pkgVersion = stats.version;
|
|
25278
26041
|
let pkgName = pkg.name;
|
|
25279
26042
|
try {
|
|
25280
|
-
const pkgJsonPath =
|
|
25281
|
-
const pkgJson = JSON.parse(await
|
|
26043
|
+
const pkgJsonPath = path52.join(pkg.path, "package.json");
|
|
26044
|
+
const pkgJson = JSON.parse(await fs49.readFile(pkgJsonPath, "utf-8"));
|
|
25282
26045
|
pkgVersion = pkgJson.version || stats.version;
|
|
25283
26046
|
pkgName = pkgJson.name || pkg.name;
|
|
25284
26047
|
} catch {
|
|
@@ -25343,8 +26106,8 @@ Load from \`~/.prjct-cli/projects/${this.config.projectId}/agents/\`:
|
|
|
25343
26106
|
});
|
|
25344
26107
|
|
|
25345
26108
|
// core/services/local-state-generator.ts
|
|
25346
|
-
import
|
|
25347
|
-
import
|
|
26109
|
+
import fs50 from "node:fs/promises";
|
|
26110
|
+
import path53 from "node:path";
|
|
25348
26111
|
var LOCAL_STATE_FILENAME, LocalStateGenerator, localStateGenerator;
|
|
25349
26112
|
var init_local_state_generator = __esm({
|
|
25350
26113
|
"core/services/local-state-generator.ts"() {
|
|
@@ -25359,17 +26122,17 @@ var init_local_state_generator = __esm({
|
|
|
25359
26122
|
* Generate .prjct-state.md in the project root
|
|
25360
26123
|
*/
|
|
25361
26124
|
async generate(projectPath, state) {
|
|
25362
|
-
const filePath =
|
|
26125
|
+
const filePath = path53.join(projectPath, LOCAL_STATE_FILENAME);
|
|
25363
26126
|
const content = this.toMarkdown(state);
|
|
25364
|
-
await
|
|
26127
|
+
await fs50.writeFile(filePath, content, "utf-8");
|
|
25365
26128
|
}
|
|
25366
26129
|
/**
|
|
25367
26130
|
* Remove local state file
|
|
25368
26131
|
*/
|
|
25369
26132
|
async remove(projectPath) {
|
|
25370
|
-
const filePath =
|
|
26133
|
+
const filePath = path53.join(projectPath, LOCAL_STATE_FILENAME);
|
|
25371
26134
|
try {
|
|
25372
|
-
await
|
|
26135
|
+
await fs50.unlink(filePath);
|
|
25373
26136
|
} catch (error) {
|
|
25374
26137
|
if (!isNotFoundError(error)) throw error;
|
|
25375
26138
|
}
|
|
@@ -25378,9 +26141,9 @@ var init_local_state_generator = __esm({
|
|
|
25378
26141
|
* Check if local state file exists
|
|
25379
26142
|
*/
|
|
25380
26143
|
async exists(projectPath) {
|
|
25381
|
-
const filePath =
|
|
26144
|
+
const filePath = path53.join(projectPath, LOCAL_STATE_FILENAME);
|
|
25382
26145
|
try {
|
|
25383
|
-
await
|
|
26146
|
+
await fs50.access(filePath);
|
|
25384
26147
|
return true;
|
|
25385
26148
|
} catch {
|
|
25386
26149
|
return false;
|
|
@@ -25459,11 +26222,11 @@ var init_local_state_generator = __esm({
|
|
|
25459
26222
|
});
|
|
25460
26223
|
|
|
25461
26224
|
// core/services/skill-lock.ts
|
|
25462
|
-
import
|
|
26225
|
+
import fs51 from "node:fs/promises";
|
|
25463
26226
|
import os14 from "node:os";
|
|
25464
|
-
import
|
|
26227
|
+
import path54 from "node:path";
|
|
25465
26228
|
function getLockFilePath() {
|
|
25466
|
-
return
|
|
26229
|
+
return path54.join(os14.homedir(), ".prjct-cli", "skills", LOCK_FILE_NAME);
|
|
25467
26230
|
}
|
|
25468
26231
|
function createEmptyLockFile() {
|
|
25469
26232
|
return {
|
|
@@ -25474,7 +26237,7 @@ function createEmptyLockFile() {
|
|
|
25474
26237
|
}
|
|
25475
26238
|
async function read() {
|
|
25476
26239
|
try {
|
|
25477
|
-
const content = await
|
|
26240
|
+
const content = await fs51.readFile(getLockFilePath(), "utf-8");
|
|
25478
26241
|
return JSON.parse(content);
|
|
25479
26242
|
} catch {
|
|
25480
26243
|
return createEmptyLockFile();
|
|
@@ -25482,9 +26245,9 @@ async function read() {
|
|
|
25482
26245
|
}
|
|
25483
26246
|
async function write(lockFile) {
|
|
25484
26247
|
const lockPath = getLockFilePath();
|
|
25485
|
-
await
|
|
26248
|
+
await fs51.mkdir(path54.dirname(lockPath), { recursive: true });
|
|
25486
26249
|
lockFile.generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
25487
|
-
await
|
|
26250
|
+
await fs51.writeFile(lockPath, JSON.stringify(lockFile, null, 2), "utf-8");
|
|
25488
26251
|
}
|
|
25489
26252
|
async function addEntry(entry) {
|
|
25490
26253
|
const lockFile = await read();
|
|
@@ -25536,15 +26299,15 @@ var init_skill_lock = __esm({
|
|
|
25536
26299
|
});
|
|
25537
26300
|
|
|
25538
26301
|
// core/services/skill-installer.ts
|
|
25539
|
-
import { exec as
|
|
25540
|
-
import
|
|
26302
|
+
import { exec as execCallback8 } from "node:child_process";
|
|
26303
|
+
import fs52 from "node:fs/promises";
|
|
25541
26304
|
import os15 from "node:os";
|
|
25542
|
-
import
|
|
25543
|
-
import { promisify as
|
|
26305
|
+
import path55 from "node:path";
|
|
26306
|
+
import { promisify as promisify16 } from "node:util";
|
|
25544
26307
|
import { glob } from "glob";
|
|
25545
26308
|
function parseSource(source) {
|
|
25546
26309
|
if (source.startsWith("./") || source.startsWith("/") || source.startsWith("~")) {
|
|
25547
|
-
const resolvedPath = source.startsWith("~") ?
|
|
26310
|
+
const resolvedPath = source.startsWith("~") ? path55.join(os15.homedir(), source.slice(1)) : path55.resolve(source);
|
|
25548
26311
|
return {
|
|
25549
26312
|
type: "local",
|
|
25550
26313
|
localPath: resolvedPath,
|
|
@@ -25582,22 +26345,22 @@ function parseSource(source) {
|
|
|
25582
26345
|
async function discoverSkills(dir) {
|
|
25583
26346
|
const skills = [];
|
|
25584
26347
|
try {
|
|
25585
|
-
const rootSkill =
|
|
25586
|
-
await
|
|
25587
|
-
const dirName =
|
|
26348
|
+
const rootSkill = path55.join(dir, "SKILL.md");
|
|
26349
|
+
await fs52.access(rootSkill);
|
|
26350
|
+
const dirName = path55.basename(dir);
|
|
25588
26351
|
skills.push({ name: dirName, filePath: rootSkill });
|
|
25589
26352
|
} catch {
|
|
25590
26353
|
}
|
|
25591
26354
|
const subdirSkills = await glob("*/SKILL.md", { cwd: dir, absolute: true });
|
|
25592
26355
|
for (const filePath of subdirSkills) {
|
|
25593
|
-
const name =
|
|
26356
|
+
const name = path55.basename(path55.dirname(filePath));
|
|
25594
26357
|
if (!skills.some((s) => s.name === name)) {
|
|
25595
26358
|
skills.push({ name, filePath });
|
|
25596
26359
|
}
|
|
25597
26360
|
}
|
|
25598
26361
|
const nestedSkills = await glob("skills/*/SKILL.md", { cwd: dir, absolute: true });
|
|
25599
26362
|
for (const filePath of nestedSkills) {
|
|
25600
|
-
const name =
|
|
26363
|
+
const name = path55.basename(path55.dirname(filePath));
|
|
25601
26364
|
if (!skills.some((s) => s.name === name)) {
|
|
25602
26365
|
skills.push({ name, filePath });
|
|
25603
26366
|
}
|
|
@@ -25633,16 +26396,16 @@ ${prjctBlock.join("\n")}
|
|
|
25633
26396
|
${content}`;
|
|
25634
26397
|
}
|
|
25635
26398
|
function getInstallDir() {
|
|
25636
|
-
return
|
|
26399
|
+
return path55.join(os15.homedir(), ".claude", "skills");
|
|
25637
26400
|
}
|
|
25638
26401
|
async function installSkillFile(sourcePath, name, source, sha) {
|
|
25639
26402
|
const installDir = getInstallDir();
|
|
25640
|
-
const targetDir =
|
|
25641
|
-
const targetPath =
|
|
25642
|
-
const content = await
|
|
26403
|
+
const targetDir = path55.join(installDir, name);
|
|
26404
|
+
const targetPath = path55.join(targetDir, "SKILL.md");
|
|
26405
|
+
const content = await fs52.readFile(sourcePath, "utf-8");
|
|
25643
26406
|
const enrichedContent = injectSourceMetadata(content, source, sha);
|
|
25644
|
-
await
|
|
25645
|
-
await
|
|
26407
|
+
await fs52.mkdir(targetDir, { recursive: true });
|
|
26408
|
+
await fs52.writeFile(targetPath, enrichedContent, "utf-8");
|
|
25646
26409
|
return {
|
|
25647
26410
|
name,
|
|
25648
26411
|
filePath: targetPath,
|
|
@@ -25659,13 +26422,13 @@ async function installFromGitHub(source) {
|
|
|
25659
26422
|
);
|
|
25660
26423
|
return result;
|
|
25661
26424
|
}
|
|
25662
|
-
const tmpDir =
|
|
26425
|
+
const tmpDir = path55.join(os15.tmpdir(), `prjct-skill-${Date.now()}`);
|
|
25663
26426
|
try {
|
|
25664
26427
|
const cloneUrl = `https://github.com/${source.owner}/${source.repo}.git`;
|
|
25665
|
-
await
|
|
26428
|
+
await exec15(`git clone --depth 1 ${cloneUrl} ${tmpDir}`, { timeout: getTimeout("GIT_CLONE") });
|
|
25666
26429
|
let sha;
|
|
25667
26430
|
try {
|
|
25668
|
-
const { stdout } = await
|
|
26431
|
+
const { stdout } = await exec15("git rev-parse HEAD", {
|
|
25669
26432
|
cwd: tmpDir,
|
|
25670
26433
|
timeout: getTimeout("TOOL_CHECK")
|
|
25671
26434
|
});
|
|
@@ -25703,7 +26466,7 @@ async function installFromGitHub(source) {
|
|
|
25703
26466
|
}
|
|
25704
26467
|
} finally {
|
|
25705
26468
|
try {
|
|
25706
|
-
await
|
|
26469
|
+
await fs52.rm(tmpDir, { recursive: true, force: true });
|
|
25707
26470
|
} catch {
|
|
25708
26471
|
}
|
|
25709
26472
|
}
|
|
@@ -25713,14 +26476,14 @@ async function installFromLocal(source) {
|
|
|
25713
26476
|
const result = { installed: [], skipped: [], errors: [] };
|
|
25714
26477
|
const localPath = source.localPath;
|
|
25715
26478
|
try {
|
|
25716
|
-
await
|
|
26479
|
+
await fs52.access(localPath);
|
|
25717
26480
|
} catch {
|
|
25718
26481
|
result.errors.push(`Local path not found: ${localPath}`);
|
|
25719
26482
|
return result;
|
|
25720
26483
|
}
|
|
25721
|
-
const stat = await
|
|
26484
|
+
const stat = await fs52.stat(localPath);
|
|
25722
26485
|
if (stat.isFile()) {
|
|
25723
|
-
const name =
|
|
26486
|
+
const name = path55.basename(path55.dirname(localPath));
|
|
25724
26487
|
try {
|
|
25725
26488
|
const installed = await installSkillFile(localPath, name, source);
|
|
25726
26489
|
const lockEntry = {
|
|
@@ -25760,14 +26523,14 @@ async function installFromLocal(source) {
|
|
|
25760
26523
|
}
|
|
25761
26524
|
async function remove(name) {
|
|
25762
26525
|
const installDir = getInstallDir();
|
|
25763
|
-
const subdirPath =
|
|
26526
|
+
const subdirPath = path55.join(installDir, name);
|
|
25764
26527
|
try {
|
|
25765
|
-
await
|
|
26528
|
+
await fs52.rm(subdirPath, { recursive: true, force: true });
|
|
25766
26529
|
} catch {
|
|
25767
26530
|
}
|
|
25768
|
-
const flatPath =
|
|
26531
|
+
const flatPath = path55.join(installDir, `${name}.md`);
|
|
25769
26532
|
try {
|
|
25770
|
-
await
|
|
26533
|
+
await fs52.rm(flatPath, { force: true });
|
|
25771
26534
|
} catch {
|
|
25772
26535
|
}
|
|
25773
26536
|
return skillLock.removeEntry(name);
|
|
@@ -25787,7 +26550,7 @@ async function install(sourceStr) {
|
|
|
25787
26550
|
};
|
|
25788
26551
|
}
|
|
25789
26552
|
}
|
|
25790
|
-
var
|
|
26553
|
+
var exec15, skillInstaller;
|
|
25791
26554
|
var init_skill_installer = __esm({
|
|
25792
26555
|
"core/services/skill-installer.ts"() {
|
|
25793
26556
|
"use strict";
|
|
@@ -25795,7 +26558,7 @@ var init_skill_installer = __esm({
|
|
|
25795
26558
|
init_fs();
|
|
25796
26559
|
init_dependency_validator();
|
|
25797
26560
|
init_skill_lock();
|
|
25798
|
-
|
|
26561
|
+
exec15 = promisify16(execCallback8);
|
|
25799
26562
|
__name(parseSource, "parseSource");
|
|
25800
26563
|
__name(discoverSkills, "discoverSkills");
|
|
25801
26564
|
__name(injectSourceMetadata, "injectSourceMetadata");
|
|
@@ -25815,8 +26578,8 @@ var init_skill_installer = __esm({
|
|
|
25815
26578
|
});
|
|
25816
26579
|
|
|
25817
26580
|
// core/services/stack-detector.ts
|
|
25818
|
-
import
|
|
25819
|
-
import
|
|
26581
|
+
import fs53 from "node:fs/promises";
|
|
26582
|
+
import path56 from "node:path";
|
|
25820
26583
|
var StackDetector;
|
|
25821
26584
|
var init_stack_detector = __esm({
|
|
25822
26585
|
"core/services/stack-detector.ts"() {
|
|
@@ -25975,8 +26738,8 @@ var init_stack_detector = __esm({
|
|
|
25975
26738
|
*/
|
|
25976
26739
|
async readPackageJson() {
|
|
25977
26740
|
try {
|
|
25978
|
-
const pkgPath =
|
|
25979
|
-
const content = await
|
|
26741
|
+
const pkgPath = path56.join(this.projectPath, "package.json");
|
|
26742
|
+
const content = await fs53.readFile(pkgPath, "utf-8");
|
|
25980
26743
|
return JSON.parse(content);
|
|
25981
26744
|
} catch {
|
|
25982
26745
|
return null;
|
|
@@ -25987,7 +26750,7 @@ var init_stack_detector = __esm({
|
|
|
25987
26750
|
*/
|
|
25988
26751
|
async fileExists(filename) {
|
|
25989
26752
|
try {
|
|
25990
|
-
await
|
|
26753
|
+
await fs53.access(path56.join(this.projectPath, filename));
|
|
25991
26754
|
return true;
|
|
25992
26755
|
} catch {
|
|
25993
26756
|
return false;
|
|
@@ -25998,16 +26761,16 @@ var init_stack_detector = __esm({
|
|
|
25998
26761
|
});
|
|
25999
26762
|
|
|
26000
26763
|
// core/services/sync-verifier.ts
|
|
26001
|
-
import { exec as
|
|
26002
|
-
import
|
|
26003
|
-
import
|
|
26004
|
-
import { promisify as
|
|
26764
|
+
import { exec as exec16 } from "node:child_process";
|
|
26765
|
+
import fs54 from "node:fs/promises";
|
|
26766
|
+
import path57 from "node:path";
|
|
26767
|
+
import { promisify as promisify17 } from "node:util";
|
|
26005
26768
|
var execAsync10, BUILTIN_CHECKS, SyncVerifier, syncVerifier;
|
|
26006
26769
|
var init_sync_verifier = __esm({
|
|
26007
26770
|
"core/services/sync-verifier.ts"() {
|
|
26008
26771
|
"use strict";
|
|
26009
26772
|
init_fs();
|
|
26010
|
-
execAsync10 =
|
|
26773
|
+
execAsync10 = promisify17(exec16);
|
|
26011
26774
|
BUILTIN_CHECKS = {
|
|
26012
26775
|
/**
|
|
26013
26776
|
* Verify all expected context files exist after sync
|
|
@@ -26017,9 +26780,9 @@ var init_sync_verifier = __esm({
|
|
|
26017
26780
|
const expected = ["context/CLAUDE.md"];
|
|
26018
26781
|
const missing = [];
|
|
26019
26782
|
for (const file of expected) {
|
|
26020
|
-
const filePath =
|
|
26783
|
+
const filePath = path57.join(globalPath, file);
|
|
26021
26784
|
try {
|
|
26022
|
-
await
|
|
26785
|
+
await fs54.access(filePath);
|
|
26023
26786
|
} catch {
|
|
26024
26787
|
missing.push(file);
|
|
26025
26788
|
}
|
|
@@ -26040,9 +26803,9 @@ var init_sync_verifier = __esm({
|
|
|
26040
26803
|
const jsonFiles = ["storage/state.json"];
|
|
26041
26804
|
const invalid = [];
|
|
26042
26805
|
for (const file of jsonFiles) {
|
|
26043
|
-
const filePath =
|
|
26806
|
+
const filePath = path57.join(globalPath, file);
|
|
26044
26807
|
try {
|
|
26045
|
-
const content = await
|
|
26808
|
+
const content = await fs54.readFile(filePath, "utf-8");
|
|
26046
26809
|
JSON.parse(content);
|
|
26047
26810
|
} catch (error) {
|
|
26048
26811
|
if (!isNotFoundError(error)) {
|
|
@@ -26063,7 +26826,7 @@ var init_sync_verifier = __esm({
|
|
|
26063
26826
|
*/
|
|
26064
26827
|
async noSensitiveData(globalPath) {
|
|
26065
26828
|
const start = Date.now();
|
|
26066
|
-
const contextDir =
|
|
26829
|
+
const contextDir = path57.join(globalPath, "context");
|
|
26067
26830
|
const patterns = [
|
|
26068
26831
|
/(?:api[_-]?key|apikey)\s*[:=]\s*['"][^'"]{10,}/i,
|
|
26069
26832
|
/(?:password|passwd|pwd)\s*[:=]\s*['"][^'"]{4,}/i,
|
|
@@ -26071,10 +26834,10 @@ var init_sync_verifier = __esm({
|
|
|
26071
26834
|
];
|
|
26072
26835
|
const violations = [];
|
|
26073
26836
|
try {
|
|
26074
|
-
const files = await
|
|
26837
|
+
const files = await fs54.readdir(contextDir);
|
|
26075
26838
|
for (const file of files) {
|
|
26076
26839
|
if (!file.endsWith(".md")) continue;
|
|
26077
|
-
const content = await
|
|
26840
|
+
const content = await fs54.readFile(path57.join(contextDir, file), "utf-8");
|
|
26078
26841
|
for (const pattern of patterns) {
|
|
26079
26842
|
if (pattern.test(content)) {
|
|
26080
26843
|
violations.push(`${file}: potential sensitive data detected`);
|
|
@@ -26194,16 +26957,21 @@ var init_sync_verifier = __esm({
|
|
|
26194
26957
|
});
|
|
26195
26958
|
|
|
26196
26959
|
// core/services/sync-service.ts
|
|
26197
|
-
import { exec as
|
|
26198
|
-
import
|
|
26960
|
+
import { exec as exec17 } from "node:child_process";
|
|
26961
|
+
import fs55 from "node:fs/promises";
|
|
26199
26962
|
import os16 from "node:os";
|
|
26200
|
-
import
|
|
26201
|
-
import { promisify as
|
|
26963
|
+
import path58 from "node:path";
|
|
26964
|
+
import { promisify as promisify18 } from "node:util";
|
|
26202
26965
|
var execAsync11, SyncService, syncService;
|
|
26203
26966
|
var init_sync_service = __esm({
|
|
26204
26967
|
"core/services/sync-service.ts"() {
|
|
26205
26968
|
"use strict";
|
|
26206
26969
|
init_ai_tools();
|
|
26970
|
+
init_bm25();
|
|
26971
|
+
init_change_propagator();
|
|
26972
|
+
init_file_hasher();
|
|
26973
|
+
init_git_cochange();
|
|
26974
|
+
init_import_graph();
|
|
26207
26975
|
init_errors();
|
|
26208
26976
|
init_command_installer();
|
|
26209
26977
|
init_config_manager();
|
|
@@ -26219,7 +26987,7 @@ var init_sync_service = __esm({
|
|
|
26219
26987
|
init_skill_installer();
|
|
26220
26988
|
init_stack_detector();
|
|
26221
26989
|
init_sync_verifier();
|
|
26222
|
-
execAsync11 =
|
|
26990
|
+
execAsync11 = promisify18(exec17);
|
|
26223
26991
|
SyncService = class {
|
|
26224
26992
|
static {
|
|
26225
26993
|
__name(this, "SyncService");
|
|
@@ -26281,9 +27049,80 @@ var init_sync_service = __esm({
|
|
|
26281
27049
|
this.detectCommands(),
|
|
26282
27050
|
this.detectStack()
|
|
26283
27051
|
]);
|
|
26284
|
-
const
|
|
27052
|
+
const isFullSync = options.full === true;
|
|
27053
|
+
let incrementalInfo;
|
|
27054
|
+
let shouldRebuildIndexes = true;
|
|
27055
|
+
let shouldRegenerateAgents = true;
|
|
27056
|
+
let changedDomains = /* @__PURE__ */ new Set();
|
|
27057
|
+
if (!isFullSync && hasHashRegistry(this.projectId)) {
|
|
27058
|
+
try {
|
|
27059
|
+
const { diff, currentHashes } = await detectChanges(this.projectPath, this.projectId);
|
|
27060
|
+
const totalChanged = diff.added.length + diff.modified.length + diff.deleted.length;
|
|
27061
|
+
if (totalChanged === 0 && !options.changedFiles?.length) {
|
|
27062
|
+
shouldRebuildIndexes = false;
|
|
27063
|
+
shouldRegenerateAgents = false;
|
|
27064
|
+
incrementalInfo = {
|
|
27065
|
+
isIncremental: true,
|
|
27066
|
+
filesChanged: 0,
|
|
27067
|
+
filesUnchanged: diff.unchanged.length,
|
|
27068
|
+
indexesRebuilt: false,
|
|
27069
|
+
agentsRegenerated: false,
|
|
27070
|
+
affectedDomains: []
|
|
27071
|
+
};
|
|
27072
|
+
} else {
|
|
27073
|
+
const propagated = propagateChanges(diff, this.projectId);
|
|
27074
|
+
changedDomains = affectedDomains(propagated.allAffected);
|
|
27075
|
+
const sourceExtensions = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
27076
|
+
const hasSourceChanges = propagated.allAffected.some((f) => {
|
|
27077
|
+
const ext = f.substring(f.lastIndexOf("."));
|
|
27078
|
+
return sourceExtensions.has(ext);
|
|
27079
|
+
});
|
|
27080
|
+
shouldRebuildIndexes = hasSourceChanges;
|
|
27081
|
+
const configChanged = propagated.directlyChanged.some(
|
|
27082
|
+
(f) => f === "package.json" || f === "tsconfig.json" || f.includes("Dockerfile") || f.includes("docker-compose")
|
|
27083
|
+
);
|
|
27084
|
+
shouldRegenerateAgents = configChanged;
|
|
27085
|
+
incrementalInfo = {
|
|
27086
|
+
isIncremental: true,
|
|
27087
|
+
filesChanged: totalChanged,
|
|
27088
|
+
filesUnchanged: diff.unchanged.length,
|
|
27089
|
+
indexesRebuilt: shouldRebuildIndexes,
|
|
27090
|
+
agentsRegenerated: shouldRegenerateAgents,
|
|
27091
|
+
affectedDomains: Array.from(changedDomains)
|
|
27092
|
+
};
|
|
27093
|
+
}
|
|
27094
|
+
saveHashes(this.projectId, currentHashes);
|
|
27095
|
+
} catch (error) {
|
|
27096
|
+
logger_default.debug("Incremental detection failed, falling back to full sync", {
|
|
27097
|
+
error: getErrorMessage(error)
|
|
27098
|
+
});
|
|
27099
|
+
}
|
|
27100
|
+
} else {
|
|
27101
|
+
try {
|
|
27102
|
+
const { currentHashes } = await detectChanges(this.projectPath, this.projectId);
|
|
27103
|
+
saveHashes(this.projectId, currentHashes);
|
|
27104
|
+
} catch (error) {
|
|
27105
|
+
logger_default.debug("Hash computation failed (non-critical)", {
|
|
27106
|
+
error: getErrorMessage(error)
|
|
27107
|
+
});
|
|
27108
|
+
}
|
|
27109
|
+
}
|
|
27110
|
+
if (shouldRebuildIndexes) {
|
|
27111
|
+
try {
|
|
27112
|
+
await Promise.all([
|
|
27113
|
+
indexProject(this.projectPath, this.projectId),
|
|
27114
|
+
indexImports(this.projectPath, this.projectId),
|
|
27115
|
+
indexCoChanges(this.projectPath, this.projectId)
|
|
27116
|
+
]);
|
|
27117
|
+
} catch (error) {
|
|
27118
|
+
logger_default.debug("File ranking index build failed (non-critical)", {
|
|
27119
|
+
error: getErrorMessage(error)
|
|
27120
|
+
});
|
|
27121
|
+
}
|
|
27122
|
+
}
|
|
27123
|
+
const agents = shouldRegenerateAgents ? await this.generateAgents(stack, stats) : await this.loadExistingAgents();
|
|
26285
27124
|
const skills = this.configureSkills(agents);
|
|
26286
|
-
const skillsInstalled = await this.autoInstallSkills(agents);
|
|
27125
|
+
const skillsInstalled = shouldRegenerateAgents ? await this.autoInstallSkills(agents) : [];
|
|
26287
27126
|
const sources = this.buildSources(stats, commands);
|
|
26288
27127
|
const contextFiles = await this.generateContextFiles(git, stats, commands, agents, sources);
|
|
26289
27128
|
const projectContext = {
|
|
@@ -26351,7 +27190,8 @@ var init_sync_service = __esm({
|
|
|
26351
27190
|
success: r.success
|
|
26352
27191
|
})),
|
|
26353
27192
|
syncMetrics,
|
|
26354
|
-
verification
|
|
27193
|
+
verification,
|
|
27194
|
+
incremental: incrementalInfo
|
|
26355
27195
|
};
|
|
26356
27196
|
} catch (error) {
|
|
26357
27197
|
return {
|
|
@@ -26377,7 +27217,7 @@ var init_sync_service = __esm({
|
|
|
26377
27217
|
async ensureDirectories() {
|
|
26378
27218
|
const dirs = ["storage", "context", "agents", "memory", "analysis", "config", "sync"];
|
|
26379
27219
|
await Promise.all(
|
|
26380
|
-
dirs.map((dir) =>
|
|
27220
|
+
dirs.map((dir) => fs55.mkdir(path58.join(this.globalPath, dir), { recursive: true }))
|
|
26381
27221
|
);
|
|
26382
27222
|
}
|
|
26383
27223
|
// ==========================================================================
|
|
@@ -26448,7 +27288,7 @@ var init_sync_service = __esm({
|
|
|
26448
27288
|
const stats = {
|
|
26449
27289
|
fileCount: 0,
|
|
26450
27290
|
version: "0.0.0",
|
|
26451
|
-
name:
|
|
27291
|
+
name: path58.basename(this.projectPath),
|
|
26452
27292
|
ecosystem: "unknown",
|
|
26453
27293
|
projectType: "simple",
|
|
26454
27294
|
languages: [],
|
|
@@ -26465,8 +27305,8 @@ var init_sync_service = __esm({
|
|
|
26465
27305
|
stats.fileCount = 0;
|
|
26466
27306
|
}
|
|
26467
27307
|
try {
|
|
26468
|
-
const pkgPath =
|
|
26469
|
-
const pkg = JSON.parse(await
|
|
27308
|
+
const pkgPath = path58.join(this.projectPath, "package.json");
|
|
27309
|
+
const pkg = JSON.parse(await fs55.readFile(pkgPath, "utf-8"));
|
|
26470
27310
|
stats.version = pkg.version || "0.0.0";
|
|
26471
27311
|
stats.name = pkg.name || stats.name;
|
|
26472
27312
|
stats.ecosystem = "JavaScript";
|
|
@@ -26611,12 +27451,12 @@ var init_sync_service = __esm({
|
|
|
26611
27451
|
// ==========================================================================
|
|
26612
27452
|
async generateAgents(stack, stats) {
|
|
26613
27453
|
const agents = [];
|
|
26614
|
-
const agentsPath =
|
|
27454
|
+
const agentsPath = path58.join(this.globalPath, "agents");
|
|
26615
27455
|
try {
|
|
26616
|
-
const files = await
|
|
27456
|
+
const files = await fs55.readdir(agentsPath);
|
|
26617
27457
|
for (const file of files) {
|
|
26618
27458
|
if (file.endsWith(".md")) {
|
|
26619
|
-
await
|
|
27459
|
+
await fs55.unlink(path58.join(agentsPath, file));
|
|
26620
27460
|
}
|
|
26621
27461
|
}
|
|
26622
27462
|
} catch (error) {
|
|
@@ -26654,6 +27494,27 @@ var init_sync_service = __esm({
|
|
|
26654
27494
|
}
|
|
26655
27495
|
return agents;
|
|
26656
27496
|
}
|
|
27497
|
+
/**
|
|
27498
|
+
* Load existing agent info from disk (for incremental sync when agents don't need regeneration).
|
|
27499
|
+
* Reads the agents directory and returns metadata without regenerating files.
|
|
27500
|
+
*/
|
|
27501
|
+
async loadExistingAgents() {
|
|
27502
|
+
const agentsPath = path58.join(this.globalPath, "agents");
|
|
27503
|
+
const agents = [];
|
|
27504
|
+
try {
|
|
27505
|
+
const files = await fs55.readdir(agentsPath);
|
|
27506
|
+
const workflowNames = /* @__PURE__ */ new Set(["prjct-workflow", "prjct-planner", "prjct-shipper"]);
|
|
27507
|
+
for (const file of files) {
|
|
27508
|
+
if (!file.endsWith(".md")) continue;
|
|
27509
|
+
const name = file.replace(".md", "");
|
|
27510
|
+
const type = workflowNames.has(name) ? "workflow" : "domain";
|
|
27511
|
+
agents.push({ name, type });
|
|
27512
|
+
}
|
|
27513
|
+
} catch {
|
|
27514
|
+
return [];
|
|
27515
|
+
}
|
|
27516
|
+
return agents;
|
|
27517
|
+
}
|
|
26657
27518
|
/**
|
|
26658
27519
|
* Resolve {{> partial-name }} includes in template content.
|
|
26659
27520
|
* Loads partials from templates/subagents/.
|
|
@@ -26665,7 +27526,7 @@ var init_sync_service = __esm({
|
|
|
26665
27526
|
let resolved = content;
|
|
26666
27527
|
for (const match of matches) {
|
|
26667
27528
|
const partialName = match[1];
|
|
26668
|
-
const partialPath =
|
|
27529
|
+
const partialPath = path58.join(
|
|
26669
27530
|
__dirname,
|
|
26670
27531
|
"..",
|
|
26671
27532
|
"..",
|
|
@@ -26674,7 +27535,7 @@ var init_sync_service = __esm({
|
|
|
26674
27535
|
`${partialName}.md`
|
|
26675
27536
|
);
|
|
26676
27537
|
try {
|
|
26677
|
-
const partialContent = await
|
|
27538
|
+
const partialContent = await fs55.readFile(partialPath, "utf-8");
|
|
26678
27539
|
resolved = resolved.replace(match[0], partialContent.trim());
|
|
26679
27540
|
} catch {
|
|
26680
27541
|
resolved = resolved.replace(match[0], `<!-- partial "${partialName}" not found -->`);
|
|
@@ -26685,7 +27546,7 @@ var init_sync_service = __esm({
|
|
|
26685
27546
|
async generateWorkflowAgent(name, agentsPath) {
|
|
26686
27547
|
let content = "";
|
|
26687
27548
|
try {
|
|
26688
|
-
const templatePath =
|
|
27549
|
+
const templatePath = path58.join(
|
|
26689
27550
|
__dirname,
|
|
26690
27551
|
"..",
|
|
26691
27552
|
"..",
|
|
@@ -26694,7 +27555,7 @@ var init_sync_service = __esm({
|
|
|
26694
27555
|
"workflow",
|
|
26695
27556
|
`${name}.md`
|
|
26696
27557
|
);
|
|
26697
|
-
content = await
|
|
27558
|
+
content = await fs55.readFile(templatePath, "utf-8");
|
|
26698
27559
|
content = await this.resolveTemplateIncludes(content);
|
|
26699
27560
|
} catch (error) {
|
|
26700
27561
|
logger_default.debug("Workflow agent template not found, generating minimal", {
|
|
@@ -26703,12 +27564,12 @@ var init_sync_service = __esm({
|
|
|
26703
27564
|
});
|
|
26704
27565
|
content = this.generateMinimalWorkflowAgent(name);
|
|
26705
27566
|
}
|
|
26706
|
-
await
|
|
27567
|
+
await fs55.writeFile(path58.join(agentsPath, `${name}.md`), content, "utf-8");
|
|
26707
27568
|
}
|
|
26708
27569
|
async generateDomainAgent(name, agentsPath, stats, stack) {
|
|
26709
27570
|
let content = "";
|
|
26710
27571
|
try {
|
|
26711
|
-
const templatePath =
|
|
27572
|
+
const templatePath = path58.join(
|
|
26712
27573
|
__dirname,
|
|
26713
27574
|
"..",
|
|
26714
27575
|
"..",
|
|
@@ -26717,7 +27578,7 @@ var init_sync_service = __esm({
|
|
|
26717
27578
|
"domain",
|
|
26718
27579
|
`${name}.md`
|
|
26719
27580
|
);
|
|
26720
|
-
content = await
|
|
27581
|
+
content = await fs55.readFile(templatePath, "utf-8");
|
|
26721
27582
|
content = await this.resolveTemplateIncludes(content);
|
|
26722
27583
|
content = content.replace("{projectName}", stats.name);
|
|
26723
27584
|
content = content.replace("{frameworks}", stack.frameworks.join(", ") || "None detected");
|
|
@@ -26729,7 +27590,7 @@ var init_sync_service = __esm({
|
|
|
26729
27590
|
});
|
|
26730
27591
|
content = this.generateMinimalDomainAgent(name, stats, stack);
|
|
26731
27592
|
}
|
|
26732
|
-
await
|
|
27593
|
+
await fs55.writeFile(path58.join(agentsPath, `${name}.md`), content, "utf-8");
|
|
26733
27594
|
}
|
|
26734
27595
|
generateMinimalWorkflowAgent(name) {
|
|
26735
27596
|
const descriptions = {
|
|
@@ -26797,8 +27658,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
26797
27658
|
})),
|
|
26798
27659
|
agentSkillMap: Object.fromEntries(skills.map((s) => [s.agent, s.skill]))
|
|
26799
27660
|
};
|
|
26800
|
-
|
|
26801
|
-
|
|
27661
|
+
fs55.writeFile(
|
|
27662
|
+
path58.join(this.globalPath, "config", "skills.json"),
|
|
26802
27663
|
JSON.stringify(skillsConfig, null, 2),
|
|
26803
27664
|
"utf-8"
|
|
26804
27665
|
).catch((error) => {
|
|
@@ -26816,7 +27677,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
26816
27677
|
async autoInstallSkills(agents) {
|
|
26817
27678
|
const results = [];
|
|
26818
27679
|
try {
|
|
26819
|
-
const mappingsPath =
|
|
27680
|
+
const mappingsPath = path58.join(
|
|
26820
27681
|
__dirname,
|
|
26821
27682
|
"..",
|
|
26822
27683
|
"..",
|
|
@@ -26824,7 +27685,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
26824
27685
|
"config",
|
|
26825
27686
|
"skill-mappings.json"
|
|
26826
27687
|
);
|
|
26827
|
-
const mappingsContent = await
|
|
27688
|
+
const mappingsContent = await fs55.readFile(mappingsPath, "utf-8");
|
|
26828
27689
|
const mappings = JSON.parse(mappingsContent);
|
|
26829
27690
|
const agentToSkillMap = mappings.agentToSkillMap || {};
|
|
26830
27691
|
const packagesToInstall = [];
|
|
@@ -26837,18 +27698,18 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
26837
27698
|
}
|
|
26838
27699
|
}
|
|
26839
27700
|
if (packagesToInstall.length === 0) return results;
|
|
26840
|
-
const skillsDir =
|
|
27701
|
+
const skillsDir = path58.join(os16.homedir(), ".claude", "skills");
|
|
26841
27702
|
for (const { pkg, agent } of packagesToInstall) {
|
|
26842
27703
|
const skillName = pkg.split("/").pop() || pkg;
|
|
26843
|
-
const subdirPath =
|
|
26844
|
-
const flatPath =
|
|
27704
|
+
const subdirPath = path58.join(skillsDir, skillName, "SKILL.md");
|
|
27705
|
+
const flatPath = path58.join(skillsDir, `${skillName}.md`);
|
|
26845
27706
|
let alreadyInstalled = false;
|
|
26846
27707
|
try {
|
|
26847
|
-
await
|
|
27708
|
+
await fs55.access(subdirPath);
|
|
26848
27709
|
alreadyInstalled = true;
|
|
26849
27710
|
} catch {
|
|
26850
27711
|
try {
|
|
26851
|
-
await
|
|
27712
|
+
await fs55.access(flatPath);
|
|
26852
27713
|
alreadyInstalled = true;
|
|
26853
27714
|
} catch {
|
|
26854
27715
|
}
|
|
@@ -26900,10 +27761,10 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
26900
27761
|
// PROJECT.JSON UPDATE
|
|
26901
27762
|
// ==========================================================================
|
|
26902
27763
|
async updateProjectJson(git, stats) {
|
|
26903
|
-
const projectJsonPath =
|
|
27764
|
+
const projectJsonPath = path58.join(this.globalPath, "project.json");
|
|
26904
27765
|
let existing = {};
|
|
26905
27766
|
try {
|
|
26906
|
-
existing = JSON.parse(await
|
|
27767
|
+
existing = JSON.parse(await fs55.readFile(projectJsonPath, "utf-8"));
|
|
26907
27768
|
} catch (error) {
|
|
26908
27769
|
logger_default.debug("No existing project.json", {
|
|
26909
27770
|
path: projectJsonPath,
|
|
@@ -26929,16 +27790,16 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
26929
27790
|
lastSyncCommit: git.recentCommits[0]?.hash || null,
|
|
26930
27791
|
lastSyncBranch: git.branch
|
|
26931
27792
|
};
|
|
26932
|
-
await
|
|
27793
|
+
await fs55.writeFile(projectJsonPath, JSON.stringify(updated, null, 2), "utf-8");
|
|
26933
27794
|
}
|
|
26934
27795
|
// ==========================================================================
|
|
26935
27796
|
// STATE.JSON UPDATE
|
|
26936
27797
|
// ==========================================================================
|
|
26937
27798
|
async updateStateJson(stats, stack) {
|
|
26938
|
-
const statePath =
|
|
27799
|
+
const statePath = path58.join(this.globalPath, "storage", "state.json");
|
|
26939
27800
|
let state = {};
|
|
26940
27801
|
try {
|
|
26941
|
-
state = JSON.parse(await
|
|
27802
|
+
state = JSON.parse(await fs55.readFile(statePath, "utf-8"));
|
|
26942
27803
|
} catch (error) {
|
|
26943
27804
|
logger_default.debug("No existing state.json", { path: statePath, error: getErrorMessage(error) });
|
|
26944
27805
|
}
|
|
@@ -26966,7 +27827,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
26966
27827
|
lastAction: "Synced project",
|
|
26967
27828
|
nextAction: 'Run `p. task "description"` to start working'
|
|
26968
27829
|
};
|
|
26969
|
-
await
|
|
27830
|
+
await fs55.writeFile(statePath, JSON.stringify(state, null, 2), "utf-8");
|
|
26970
27831
|
try {
|
|
26971
27832
|
await localStateGenerator.generate(
|
|
26972
27833
|
this.projectPath,
|
|
@@ -26980,7 +27841,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
26980
27841
|
// MEMORY LOGGING
|
|
26981
27842
|
// ==========================================================================
|
|
26982
27843
|
async logToMemory(git, stats) {
|
|
26983
|
-
const memoryPath =
|
|
27844
|
+
const memoryPath = path58.join(this.globalPath, "memory", "events.jsonl");
|
|
26984
27845
|
const event = {
|
|
26985
27846
|
ts: getTimestamp(),
|
|
26986
27847
|
action: "sync",
|
|
@@ -26989,7 +27850,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
26989
27850
|
fileCount: stats.fileCount,
|
|
26990
27851
|
commitCount: git.commits
|
|
26991
27852
|
};
|
|
26992
|
-
await
|
|
27853
|
+
await fs55.appendFile(memoryPath, `${JSON.stringify(event)}
|
|
26993
27854
|
`, "utf-8");
|
|
26994
27855
|
}
|
|
26995
27856
|
// ==========================================================================
|
|
@@ -27009,8 +27870,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
27009
27870
|
let filteredChars = 0;
|
|
27010
27871
|
for (const file of contextFiles) {
|
|
27011
27872
|
try {
|
|
27012
|
-
const filePath =
|
|
27013
|
-
const content = await
|
|
27873
|
+
const filePath = path58.join(this.globalPath, file);
|
|
27874
|
+
const content = await fs55.readFile(filePath, "utf-8");
|
|
27014
27875
|
filteredChars += content.length;
|
|
27015
27876
|
} catch (error) {
|
|
27016
27877
|
logger_default.debug("Context file not found for metrics", { file, error: getErrorMessage(error) });
|
|
@@ -27018,8 +27879,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
27018
27879
|
}
|
|
27019
27880
|
for (const agent of agents) {
|
|
27020
27881
|
try {
|
|
27021
|
-
const agentPath =
|
|
27022
|
-
const content = await
|
|
27882
|
+
const agentPath = path58.join(this.globalPath, "agents", `${agent.name}.md`);
|
|
27883
|
+
const content = await fs55.readFile(agentPath, "utf-8");
|
|
27023
27884
|
filteredChars += content.length;
|
|
27024
27885
|
} catch (error) {
|
|
27025
27886
|
logger_default.debug("Agent file not found for metrics", {
|
|
@@ -27081,7 +27942,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
27081
27942
|
// ==========================================================================
|
|
27082
27943
|
async fileExists(filename) {
|
|
27083
27944
|
try {
|
|
27084
|
-
await
|
|
27945
|
+
await fs55.access(path58.join(this.projectPath, filename));
|
|
27085
27946
|
return true;
|
|
27086
27947
|
} catch (error) {
|
|
27087
27948
|
logger_default.debug("File not found", { filename, error: getErrorMessage(error) });
|
|
@@ -27090,8 +27951,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
27090
27951
|
}
|
|
27091
27952
|
async getCliVersion() {
|
|
27092
27953
|
try {
|
|
27093
|
-
const pkgPath =
|
|
27094
|
-
const pkg = JSON.parse(await
|
|
27954
|
+
const pkgPath = path58.join(__dirname, "..", "..", "package.json");
|
|
27955
|
+
const pkg = JSON.parse(await fs55.readFile(pkgPath, "utf-8"));
|
|
27095
27956
|
return pkg.version || "0.0.0";
|
|
27096
27957
|
} catch (error) {
|
|
27097
27958
|
logger_default.debug("Failed to read CLI version", { error: getErrorMessage(error) });
|
|
@@ -27252,22 +28113,22 @@ __export(uninstall_exports, {
|
|
|
27252
28113
|
uninstall: () => uninstall
|
|
27253
28114
|
});
|
|
27254
28115
|
import { execSync as execSync3 } from "node:child_process";
|
|
27255
|
-
import
|
|
28116
|
+
import fs56 from "node:fs/promises";
|
|
27256
28117
|
import os17 from "node:os";
|
|
27257
|
-
import
|
|
28118
|
+
import path59 from "node:path";
|
|
27258
28119
|
import readline2 from "node:readline";
|
|
27259
28120
|
import chalk12 from "chalk";
|
|
27260
28121
|
async function getDirectorySize(dirPath) {
|
|
27261
28122
|
let totalSize = 0;
|
|
27262
28123
|
try {
|
|
27263
|
-
const entries = await
|
|
28124
|
+
const entries = await fs56.readdir(dirPath, { withFileTypes: true });
|
|
27264
28125
|
for (const entry of entries) {
|
|
27265
|
-
const entryPath =
|
|
28126
|
+
const entryPath = path59.join(dirPath, entry.name);
|
|
27266
28127
|
if (entry.isDirectory()) {
|
|
27267
28128
|
totalSize += await getDirectorySize(entryPath);
|
|
27268
28129
|
} else {
|
|
27269
28130
|
try {
|
|
27270
|
-
const stats = await
|
|
28131
|
+
const stats = await fs56.stat(entryPath);
|
|
27271
28132
|
totalSize += stats.size;
|
|
27272
28133
|
} catch {
|
|
27273
28134
|
}
|
|
@@ -27286,7 +28147,7 @@ function formatSize(bytes) {
|
|
|
27286
28147
|
}
|
|
27287
28148
|
async function countDirectoryItems(dirPath) {
|
|
27288
28149
|
try {
|
|
27289
|
-
const entries = await
|
|
28150
|
+
const entries = await fs56.readdir(dirPath, { withFileTypes: true });
|
|
27290
28151
|
return entries.filter((e) => e.isDirectory()).length;
|
|
27291
28152
|
} catch {
|
|
27292
28153
|
return 0;
|
|
@@ -27319,7 +28180,7 @@ async function gatherUninstallItems() {
|
|
|
27319
28180
|
const providerPaths = getProviderPaths();
|
|
27320
28181
|
const prjctCliPath = path_manager_default.getGlobalBasePath();
|
|
27321
28182
|
const prjctCliExists = await fileExists(prjctCliPath);
|
|
27322
|
-
const projectCount = prjctCliExists ? await countDirectoryItems(
|
|
28183
|
+
const projectCount = prjctCliExists ? await countDirectoryItems(path59.join(prjctCliPath, "projects")) : 0;
|
|
27323
28184
|
const prjctCliSize = prjctCliExists ? await getDirectorySize(prjctCliPath) : 0;
|
|
27324
28185
|
items.push({
|
|
27325
28186
|
path: prjctCliPath,
|
|
@@ -27329,12 +28190,12 @@ async function gatherUninstallItems() {
|
|
|
27329
28190
|
count: projectCount,
|
|
27330
28191
|
exists: prjctCliExists
|
|
27331
28192
|
});
|
|
27332
|
-
const claudeMdPath =
|
|
28193
|
+
const claudeMdPath = path59.join(providerPaths.claude.config, "CLAUDE.md");
|
|
27333
28194
|
const claudeMdExists = await fileExists(claudeMdPath);
|
|
27334
28195
|
let hasPrjctSection = false;
|
|
27335
28196
|
if (claudeMdExists) {
|
|
27336
28197
|
try {
|
|
27337
|
-
const content = await
|
|
28198
|
+
const content = await fs56.readFile(claudeMdPath, "utf-8");
|
|
27338
28199
|
hasPrjctSection = content.includes(PRJCT_START_MARKER) && content.includes(PRJCT_END_MARKER);
|
|
27339
28200
|
} catch {
|
|
27340
28201
|
}
|
|
@@ -27363,7 +28224,7 @@ async function gatherUninstallItems() {
|
|
|
27363
28224
|
description: "Claude router",
|
|
27364
28225
|
exists: claudeRouterExists
|
|
27365
28226
|
});
|
|
27366
|
-
const statusLinePath =
|
|
28227
|
+
const statusLinePath = path59.join(providerPaths.claude.config, "prjct-statusline.sh");
|
|
27367
28228
|
const statusLineExists = await fileExists(statusLinePath);
|
|
27368
28229
|
items.push({
|
|
27369
28230
|
path: statusLinePath,
|
|
@@ -27379,12 +28240,12 @@ async function gatherUninstallItems() {
|
|
|
27379
28240
|
description: "Gemini router",
|
|
27380
28241
|
exists: geminiRouterExists
|
|
27381
28242
|
});
|
|
27382
|
-
const geminiMdPath =
|
|
28243
|
+
const geminiMdPath = path59.join(providerPaths.gemini.config, "GEMINI.md");
|
|
27383
28244
|
const geminiMdExists = await fileExists(geminiMdPath);
|
|
27384
28245
|
let hasGeminiPrjctSection = false;
|
|
27385
28246
|
if (geminiMdExists) {
|
|
27386
28247
|
try {
|
|
27387
|
-
const content = await
|
|
28248
|
+
const content = await fs56.readFile(geminiMdPath, "utf-8");
|
|
27388
28249
|
hasGeminiPrjctSection = content.includes(PRJCT_START_MARKER) && content.includes(PRJCT_END_MARKER);
|
|
27389
28250
|
} catch {
|
|
27390
28251
|
}
|
|
@@ -27401,7 +28262,7 @@ async function gatherUninstallItems() {
|
|
|
27401
28262
|
}
|
|
27402
28263
|
async function removePrjctSection(filePath) {
|
|
27403
28264
|
try {
|
|
27404
|
-
const content = await
|
|
28265
|
+
const content = await fs56.readFile(filePath, "utf-8");
|
|
27405
28266
|
if (!content.includes(PRJCT_START_MARKER) || !content.includes(PRJCT_END_MARKER)) {
|
|
27406
28267
|
return false;
|
|
27407
28268
|
}
|
|
@@ -27410,9 +28271,9 @@ async function removePrjctSection(filePath) {
|
|
|
27410
28271
|
let newContent = content.substring(0, startIndex) + content.substring(endIndex);
|
|
27411
28272
|
newContent = newContent.replace(/\n{3,}/g, "\n\n").trim();
|
|
27412
28273
|
if (!newContent || newContent.trim().length === 0) {
|
|
27413
|
-
await
|
|
28274
|
+
await fs56.unlink(filePath);
|
|
27414
28275
|
} else {
|
|
27415
|
-
await
|
|
28276
|
+
await fs56.writeFile(filePath, `${newContent}
|
|
27416
28277
|
`, "utf-8");
|
|
27417
28278
|
}
|
|
27418
28279
|
return true;
|
|
@@ -27423,12 +28284,12 @@ async function removePrjctSection(filePath) {
|
|
|
27423
28284
|
async function createBackup3() {
|
|
27424
28285
|
const homeDir = os17.homedir();
|
|
27425
28286
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").substring(0, 19);
|
|
27426
|
-
const backupDir =
|
|
28287
|
+
const backupDir = path59.join(homeDir, `.prjct-backup-${timestamp}`);
|
|
27427
28288
|
try {
|
|
27428
|
-
await
|
|
28289
|
+
await fs56.mkdir(backupDir, { recursive: true });
|
|
27429
28290
|
const prjctCliPath = path_manager_default.getGlobalBasePath();
|
|
27430
28291
|
if (await fileExists(prjctCliPath)) {
|
|
27431
|
-
await copyDirectory(prjctCliPath,
|
|
28292
|
+
await copyDirectory(prjctCliPath, path59.join(backupDir, ".prjct-cli"));
|
|
27432
28293
|
}
|
|
27433
28294
|
return backupDir;
|
|
27434
28295
|
} catch {
|
|
@@ -27436,15 +28297,15 @@ async function createBackup3() {
|
|
|
27436
28297
|
}
|
|
27437
28298
|
}
|
|
27438
28299
|
async function copyDirectory(src, dest) {
|
|
27439
|
-
await
|
|
27440
|
-
const entries = await
|
|
28300
|
+
await fs56.mkdir(dest, { recursive: true });
|
|
28301
|
+
const entries = await fs56.readdir(src, { withFileTypes: true });
|
|
27441
28302
|
for (const entry of entries) {
|
|
27442
|
-
const srcPath =
|
|
27443
|
-
const destPath =
|
|
28303
|
+
const srcPath = path59.join(src, entry.name);
|
|
28304
|
+
const destPath = path59.join(dest, entry.name);
|
|
27444
28305
|
if (entry.isDirectory()) {
|
|
27445
28306
|
await copyDirectory(srcPath, destPath);
|
|
27446
28307
|
} else {
|
|
27447
|
-
await
|
|
28308
|
+
await fs56.copyFile(srcPath, destPath);
|
|
27448
28309
|
}
|
|
27449
28310
|
}
|
|
27450
28311
|
}
|
|
@@ -27460,10 +28321,10 @@ async function performUninstall(items, installation, options) {
|
|
|
27460
28321
|
deleted.push(item.path);
|
|
27461
28322
|
}
|
|
27462
28323
|
} else if (item.type === "directory") {
|
|
27463
|
-
await
|
|
28324
|
+
await fs56.rm(item.path, { recursive: true, force: true });
|
|
27464
28325
|
deleted.push(item.path);
|
|
27465
28326
|
} else if (item.type === "file") {
|
|
27466
|
-
await
|
|
28327
|
+
await fs56.unlink(item.path);
|
|
27467
28328
|
deleted.push(item.path);
|
|
27468
28329
|
}
|
|
27469
28330
|
} catch (error) {
|
|
@@ -27640,7 +28501,7 @@ __export(watch_service_exports, {
|
|
|
27640
28501
|
WatchService: () => WatchService,
|
|
27641
28502
|
watchService: () => watchService
|
|
27642
28503
|
});
|
|
27643
|
-
import
|
|
28504
|
+
import path60 from "node:path";
|
|
27644
28505
|
import chalk13 from "chalk";
|
|
27645
28506
|
import chokidar from "chokidar";
|
|
27646
28507
|
var TRIGGER_PATTERNS, IGNORE_PATTERNS2, WatchService, watchService;
|
|
@@ -27829,7 +28690,7 @@ ${chalk13.dim(`[${timestamp}]`)} ${chalk13.cyan("\u27F3")} ${filesSummary} chang
|
|
|
27829
28690
|
);
|
|
27830
28691
|
}
|
|
27831
28692
|
try {
|
|
27832
|
-
const result = await syncService.sync(this.projectPath);
|
|
28693
|
+
const result = await syncService.sync(this.projectPath, { changedFiles });
|
|
27833
28694
|
this.lastSyncTime = Date.now();
|
|
27834
28695
|
this.syncCount++;
|
|
27835
28696
|
if (result.success) {
|
|
@@ -27861,7 +28722,7 @@ ${chalk13.dim(`[${timestamp}]`)} ${chalk13.cyan("\u27F3")} ${filesSummary} chang
|
|
|
27861
28722
|
printStartup() {
|
|
27862
28723
|
console.log("");
|
|
27863
28724
|
console.log(chalk13.cyan("\u{1F441}\uFE0F Watching for changes..."));
|
|
27864
|
-
console.log(chalk13.dim(` Project: ${
|
|
28725
|
+
console.log(chalk13.dim(` Project: ${path60.basename(this.projectPath)}`));
|
|
27865
28726
|
console.log(chalk13.dim(` Debounce: ${this.options.debounceMs}ms`));
|
|
27866
28727
|
console.log(chalk13.dim(` Min interval: ${this.options.minIntervalMs / 1e3}s`));
|
|
27867
28728
|
console.log("");
|
|
@@ -28034,11 +28895,13 @@ var init_command_data = __esm({
|
|
|
28034
28895
|
name: "sync",
|
|
28035
28896
|
group: "core",
|
|
28036
28897
|
description: "Sync project state and update workflow agents",
|
|
28037
|
-
usage: { claude: "/p:sync", terminal: "prjct sync [--package=<name>]" },
|
|
28898
|
+
usage: { claude: "/p:sync", terminal: "prjct sync [--package=<name>] [--full]" },
|
|
28038
28899
|
implemented: true,
|
|
28039
28900
|
hasTemplate: true,
|
|
28040
28901
|
requiresProject: true,
|
|
28041
28902
|
features: [
|
|
28903
|
+
"Incremental sync: only re-analyzes changed files (default)",
|
|
28904
|
+
"Force full sync: --full bypasses incremental cache",
|
|
28042
28905
|
"Monorepo support: --package=<name> for single package sync",
|
|
28043
28906
|
"Nested PRJCT.md inheritance",
|
|
28044
28907
|
"Per-package CLAUDE.md generation"
|
|
@@ -28592,9 +29455,9 @@ __export(setup_exports, {
|
|
|
28592
29455
|
run: () => run
|
|
28593
29456
|
});
|
|
28594
29457
|
import { execSync as execSync4 } from "node:child_process";
|
|
28595
|
-
import
|
|
29458
|
+
import fs57 from "node:fs/promises";
|
|
28596
29459
|
import os18 from "node:os";
|
|
28597
|
-
import
|
|
29460
|
+
import path61 from "node:path";
|
|
28598
29461
|
import chalk15 from "chalk";
|
|
28599
29462
|
async function installAICLI(provider) {
|
|
28600
29463
|
const packageName = provider.name === "claude" ? "@anthropic-ai/claude-code" : "@google/gemini-cli";
|
|
@@ -28733,12 +29596,12 @@ async function run() {
|
|
|
28733
29596
|
}
|
|
28734
29597
|
async function installGeminiRouter() {
|
|
28735
29598
|
try {
|
|
28736
|
-
const geminiCommandsDir =
|
|
28737
|
-
const routerSource =
|
|
28738
|
-
const routerDest =
|
|
28739
|
-
await
|
|
29599
|
+
const geminiCommandsDir = path61.join(os18.homedir(), ".gemini", "commands");
|
|
29600
|
+
const routerSource = path61.join(PACKAGE_ROOT, "templates", "commands", "p.toml");
|
|
29601
|
+
const routerDest = path61.join(geminiCommandsDir, "p.toml");
|
|
29602
|
+
await fs57.mkdir(geminiCommandsDir, { recursive: true });
|
|
28740
29603
|
if (await fileExists(routerSource)) {
|
|
28741
|
-
await
|
|
29604
|
+
await fs57.copyFile(routerSource, routerDest);
|
|
28742
29605
|
return true;
|
|
28743
29606
|
}
|
|
28744
29607
|
return false;
|
|
@@ -28749,15 +29612,15 @@ async function installGeminiRouter() {
|
|
|
28749
29612
|
}
|
|
28750
29613
|
async function installGeminiGlobalConfig() {
|
|
28751
29614
|
try {
|
|
28752
|
-
const geminiDir =
|
|
28753
|
-
const globalConfigPath =
|
|
28754
|
-
const templatePath =
|
|
28755
|
-
await
|
|
28756
|
-
const templateContent = await
|
|
29615
|
+
const geminiDir = path61.join(os18.homedir(), ".gemini");
|
|
29616
|
+
const globalConfigPath = path61.join(geminiDir, "GEMINI.md");
|
|
29617
|
+
const templatePath = path61.join(PACKAGE_ROOT, "templates", "global", "GEMINI.md");
|
|
29618
|
+
await fs57.mkdir(geminiDir, { recursive: true });
|
|
29619
|
+
const templateContent = await fs57.readFile(templatePath, "utf-8");
|
|
28757
29620
|
let existingContent = "";
|
|
28758
29621
|
let configExists = false;
|
|
28759
29622
|
try {
|
|
28760
|
-
existingContent = await
|
|
29623
|
+
existingContent = await fs57.readFile(globalConfigPath, "utf-8");
|
|
28761
29624
|
configExists = true;
|
|
28762
29625
|
} catch (error) {
|
|
28763
29626
|
if (isNotFoundError(error)) {
|
|
@@ -28767,7 +29630,7 @@ async function installGeminiGlobalConfig() {
|
|
|
28767
29630
|
}
|
|
28768
29631
|
}
|
|
28769
29632
|
if (!configExists) {
|
|
28770
|
-
await
|
|
29633
|
+
await fs57.writeFile(globalConfigPath, templateContent, "utf-8");
|
|
28771
29634
|
return { success: true, action: "created" };
|
|
28772
29635
|
}
|
|
28773
29636
|
const startMarker = "<!-- prjct:start - DO NOT REMOVE THIS MARKER -->";
|
|
@@ -28777,7 +29640,7 @@ async function installGeminiGlobalConfig() {
|
|
|
28777
29640
|
const updatedContent2 = `${existingContent}
|
|
28778
29641
|
|
|
28779
29642
|
${templateContent}`;
|
|
28780
|
-
await
|
|
29643
|
+
await fs57.writeFile(globalConfigPath, updatedContent2, "utf-8");
|
|
28781
29644
|
return { success: true, action: "appended" };
|
|
28782
29645
|
}
|
|
28783
29646
|
const beforeMarker = existingContent.substring(0, existingContent.indexOf(startMarker));
|
|
@@ -28789,7 +29652,7 @@ ${templateContent}`;
|
|
|
28789
29652
|
templateContent.indexOf(endMarker) + endMarker.length
|
|
28790
29653
|
);
|
|
28791
29654
|
const updatedContent = beforeMarker + prjctSection + afterMarker;
|
|
28792
|
-
await
|
|
29655
|
+
await fs57.writeFile(globalConfigPath, updatedContent, "utf-8");
|
|
28793
29656
|
return { success: true, action: "updated" };
|
|
28794
29657
|
} catch (error) {
|
|
28795
29658
|
logger_default.warn(`Gemini config warning: ${getErrorMessage2(error)}`);
|
|
@@ -28798,18 +29661,18 @@ ${templateContent}`;
|
|
|
28798
29661
|
}
|
|
28799
29662
|
async function installAntigravitySkill() {
|
|
28800
29663
|
try {
|
|
28801
|
-
const antigravitySkillsDir =
|
|
28802
|
-
const prjctSkillDir =
|
|
28803
|
-
const skillMdPath =
|
|
28804
|
-
const templatePath =
|
|
28805
|
-
await
|
|
29664
|
+
const antigravitySkillsDir = path61.join(os18.homedir(), ".gemini", "antigravity", "skills");
|
|
29665
|
+
const prjctSkillDir = path61.join(antigravitySkillsDir, "prjct");
|
|
29666
|
+
const skillMdPath = path61.join(prjctSkillDir, "SKILL.md");
|
|
29667
|
+
const templatePath = path61.join(PACKAGE_ROOT, "templates", "antigravity", "SKILL.md");
|
|
29668
|
+
await fs57.mkdir(prjctSkillDir, { recursive: true });
|
|
28806
29669
|
const skillExists = await fileExists(skillMdPath);
|
|
28807
29670
|
if (!await fileExists(templatePath)) {
|
|
28808
29671
|
logger_default.warn("Antigravity SKILL.md template not found");
|
|
28809
29672
|
return { success: false, action: null };
|
|
28810
29673
|
}
|
|
28811
|
-
const templateContent = await
|
|
28812
|
-
await
|
|
29674
|
+
const templateContent = await fs57.readFile(templatePath, "utf-8");
|
|
29675
|
+
await fs57.writeFile(skillMdPath, templateContent, "utf-8");
|
|
28813
29676
|
return { success: true, action: skillExists ? "updated" : "created" };
|
|
28814
29677
|
} catch (error) {
|
|
28815
29678
|
logger_default.warn(`Antigravity skill warning: ${getErrorMessage2(error)}`);
|
|
@@ -28828,24 +29691,24 @@ async function installCursorProject(projectRoot) {
|
|
|
28828
29691
|
gitignoreUpdated: false
|
|
28829
29692
|
};
|
|
28830
29693
|
try {
|
|
28831
|
-
const cursorDir =
|
|
28832
|
-
const rulesDir =
|
|
28833
|
-
const commandsDir =
|
|
28834
|
-
const routerMdcDest =
|
|
28835
|
-
const routerMdcSource =
|
|
28836
|
-
const cursorCommandsSource =
|
|
28837
|
-
await
|
|
28838
|
-
await
|
|
29694
|
+
const cursorDir = path61.join(projectRoot, ".cursor");
|
|
29695
|
+
const rulesDir = path61.join(cursorDir, "rules");
|
|
29696
|
+
const commandsDir = path61.join(cursorDir, "commands");
|
|
29697
|
+
const routerMdcDest = path61.join(rulesDir, "prjct.mdc");
|
|
29698
|
+
const routerMdcSource = path61.join(PACKAGE_ROOT, "templates", "cursor", "router.mdc");
|
|
29699
|
+
const cursorCommandsSource = path61.join(PACKAGE_ROOT, "templates", "cursor", "commands");
|
|
29700
|
+
await fs57.mkdir(rulesDir, { recursive: true });
|
|
29701
|
+
await fs57.mkdir(commandsDir, { recursive: true });
|
|
28839
29702
|
if (await fileExists(routerMdcSource)) {
|
|
28840
|
-
await
|
|
29703
|
+
await fs57.copyFile(routerMdcSource, routerMdcDest);
|
|
28841
29704
|
result.rulesCreated = true;
|
|
28842
29705
|
}
|
|
28843
29706
|
if (await fileExists(cursorCommandsSource)) {
|
|
28844
|
-
const commandFiles = (await
|
|
29707
|
+
const commandFiles = (await fs57.readdir(cursorCommandsSource)).filter((f) => f.endsWith(".md"));
|
|
28845
29708
|
for (const file of commandFiles) {
|
|
28846
|
-
const src =
|
|
28847
|
-
const dest =
|
|
28848
|
-
await
|
|
29709
|
+
const src = path61.join(cursorCommandsSource, file);
|
|
29710
|
+
const dest = path61.join(commandsDir, file);
|
|
29711
|
+
await fs57.copyFile(src, dest);
|
|
28849
29712
|
}
|
|
28850
29713
|
result.commandsCreated = commandFiles.length > 0;
|
|
28851
29714
|
}
|
|
@@ -28859,7 +29722,7 @@ async function installCursorProject(projectRoot) {
|
|
|
28859
29722
|
}
|
|
28860
29723
|
async function addCursorToGitignore(projectRoot) {
|
|
28861
29724
|
try {
|
|
28862
|
-
const gitignorePath =
|
|
29725
|
+
const gitignorePath = path61.join(projectRoot, ".gitignore");
|
|
28863
29726
|
const entriesToAdd = [
|
|
28864
29727
|
"# prjct Cursor routers (regenerated per-developer)",
|
|
28865
29728
|
".cursor/rules/prjct.mdc",
|
|
@@ -28874,7 +29737,7 @@ async function addCursorToGitignore(projectRoot) {
|
|
|
28874
29737
|
let content = "";
|
|
28875
29738
|
let configExists = false;
|
|
28876
29739
|
try {
|
|
28877
|
-
content = await
|
|
29740
|
+
content = await fs57.readFile(gitignorePath, "utf-8");
|
|
28878
29741
|
configExists = true;
|
|
28879
29742
|
} catch (error) {
|
|
28880
29743
|
if (!isNotFoundError(error)) {
|
|
@@ -28889,7 +29752,7 @@ async function addCursorToGitignore(projectRoot) {
|
|
|
28889
29752
|
${entriesToAdd.join("\n")}
|
|
28890
29753
|
` : `${entriesToAdd.join("\n")}
|
|
28891
29754
|
`;
|
|
28892
|
-
await
|
|
29755
|
+
await fs57.writeFile(gitignorePath, newContent, "utf-8");
|
|
28893
29756
|
return true;
|
|
28894
29757
|
} catch (error) {
|
|
28895
29758
|
logger_default.warn(`Gitignore update warning: ${getErrorMessage2(error)}`);
|
|
@@ -28897,11 +29760,11 @@ ${entriesToAdd.join("\n")}
|
|
|
28897
29760
|
}
|
|
28898
29761
|
}
|
|
28899
29762
|
async function hasCursorProject(projectRoot) {
|
|
28900
|
-
return await fileExists(
|
|
29763
|
+
return await fileExists(path61.join(projectRoot, ".cursor"));
|
|
28901
29764
|
}
|
|
28902
29765
|
async function needsCursorRegeneration(projectRoot) {
|
|
28903
|
-
const cursorDir =
|
|
28904
|
-
const routerPath =
|
|
29766
|
+
const cursorDir = path61.join(projectRoot, ".cursor");
|
|
29767
|
+
const routerPath = path61.join(cursorDir, "rules", "prjct.mdc");
|
|
28905
29768
|
return await fileExists(cursorDir) && !await fileExists(routerPath);
|
|
28906
29769
|
}
|
|
28907
29770
|
async function installWindsurfProject(projectRoot) {
|
|
@@ -28912,26 +29775,26 @@ async function installWindsurfProject(projectRoot) {
|
|
|
28912
29775
|
gitignoreUpdated: false
|
|
28913
29776
|
};
|
|
28914
29777
|
try {
|
|
28915
|
-
const windsurfDir =
|
|
28916
|
-
const rulesDir =
|
|
28917
|
-
const workflowsDir =
|
|
28918
|
-
const routerDest =
|
|
28919
|
-
const routerSource =
|
|
28920
|
-
const windsurfWorkflowsSource =
|
|
28921
|
-
await
|
|
28922
|
-
await
|
|
29778
|
+
const windsurfDir = path61.join(projectRoot, ".windsurf");
|
|
29779
|
+
const rulesDir = path61.join(windsurfDir, "rules");
|
|
29780
|
+
const workflowsDir = path61.join(windsurfDir, "workflows");
|
|
29781
|
+
const routerDest = path61.join(rulesDir, "prjct.md");
|
|
29782
|
+
const routerSource = path61.join(PACKAGE_ROOT, "templates", "windsurf", "router.md");
|
|
29783
|
+
const windsurfWorkflowsSource = path61.join(PACKAGE_ROOT, "templates", "windsurf", "workflows");
|
|
29784
|
+
await fs57.mkdir(rulesDir, { recursive: true });
|
|
29785
|
+
await fs57.mkdir(workflowsDir, { recursive: true });
|
|
28923
29786
|
if (await fileExists(routerSource)) {
|
|
28924
|
-
await
|
|
29787
|
+
await fs57.copyFile(routerSource, routerDest);
|
|
28925
29788
|
result.rulesCreated = true;
|
|
28926
29789
|
}
|
|
28927
29790
|
if (await fileExists(windsurfWorkflowsSource)) {
|
|
28928
|
-
const workflowFiles = (await
|
|
29791
|
+
const workflowFiles = (await fs57.readdir(windsurfWorkflowsSource)).filter(
|
|
28929
29792
|
(f) => f.endsWith(".md")
|
|
28930
29793
|
);
|
|
28931
29794
|
for (const file of workflowFiles) {
|
|
28932
|
-
const src =
|
|
28933
|
-
const dest =
|
|
28934
|
-
await
|
|
29795
|
+
const src = path61.join(windsurfWorkflowsSource, file);
|
|
29796
|
+
const dest = path61.join(workflowsDir, file);
|
|
29797
|
+
await fs57.copyFile(src, dest);
|
|
28935
29798
|
}
|
|
28936
29799
|
result.workflowsCreated = workflowFiles.length > 0;
|
|
28937
29800
|
}
|
|
@@ -28945,7 +29808,7 @@ async function installWindsurfProject(projectRoot) {
|
|
|
28945
29808
|
}
|
|
28946
29809
|
async function addWindsurfToGitignore(projectRoot) {
|
|
28947
29810
|
try {
|
|
28948
|
-
const gitignorePath =
|
|
29811
|
+
const gitignorePath = path61.join(projectRoot, ".gitignore");
|
|
28949
29812
|
const entriesToAdd = [
|
|
28950
29813
|
"# prjct Windsurf routers (regenerated per-developer)",
|
|
28951
29814
|
".windsurf/rules/prjct.md",
|
|
@@ -28960,7 +29823,7 @@ async function addWindsurfToGitignore(projectRoot) {
|
|
|
28960
29823
|
let content = "";
|
|
28961
29824
|
let configExists = false;
|
|
28962
29825
|
try {
|
|
28963
|
-
content = await
|
|
29826
|
+
content = await fs57.readFile(gitignorePath, "utf-8");
|
|
28964
29827
|
configExists = true;
|
|
28965
29828
|
} catch (error) {
|
|
28966
29829
|
if (!isNotFoundError(error)) {
|
|
@@ -28975,7 +29838,7 @@ async function addWindsurfToGitignore(projectRoot) {
|
|
|
28975
29838
|
${entriesToAdd.join("\n")}
|
|
28976
29839
|
` : `${entriesToAdd.join("\n")}
|
|
28977
29840
|
`;
|
|
28978
|
-
await
|
|
29841
|
+
await fs57.writeFile(gitignorePath, newContent, "utf-8");
|
|
28979
29842
|
return true;
|
|
28980
29843
|
} catch (error) {
|
|
28981
29844
|
logger_default.warn(`Gitignore update warning: ${getErrorMessage2(error)}`);
|
|
@@ -28983,32 +29846,32 @@ ${entriesToAdd.join("\n")}
|
|
|
28983
29846
|
}
|
|
28984
29847
|
}
|
|
28985
29848
|
async function hasWindsurfProject(projectRoot) {
|
|
28986
|
-
return await fileExists(
|
|
29849
|
+
return await fileExists(path61.join(projectRoot, ".windsurf"));
|
|
28987
29850
|
}
|
|
28988
29851
|
async function needsWindsurfRegeneration(projectRoot) {
|
|
28989
|
-
const windsurfDir =
|
|
28990
|
-
const routerPath =
|
|
29852
|
+
const windsurfDir = path61.join(projectRoot, ".windsurf");
|
|
29853
|
+
const routerPath = path61.join(windsurfDir, "rules", "prjct.md");
|
|
28991
29854
|
return await fileExists(windsurfDir) && !await fileExists(routerPath);
|
|
28992
29855
|
}
|
|
28993
29856
|
async function migrateProjectsCliVersion() {
|
|
28994
29857
|
try {
|
|
28995
|
-
const projectsDir =
|
|
29858
|
+
const projectsDir = path61.join(os18.homedir(), ".prjct-cli", "projects");
|
|
28996
29859
|
if (!await fileExists(projectsDir)) {
|
|
28997
29860
|
return;
|
|
28998
29861
|
}
|
|
28999
|
-
const projectDirs = (await
|
|
29862
|
+
const projectDirs = (await fs57.readdir(projectsDir, { withFileTypes: true })).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
29000
29863
|
let migrated = 0;
|
|
29001
29864
|
for (const projectId of projectDirs) {
|
|
29002
|
-
const projectJsonPath =
|
|
29865
|
+
const projectJsonPath = path61.join(projectsDir, projectId, "project.json");
|
|
29003
29866
|
if (!await fileExists(projectJsonPath)) {
|
|
29004
29867
|
continue;
|
|
29005
29868
|
}
|
|
29006
29869
|
try {
|
|
29007
|
-
const content = await
|
|
29870
|
+
const content = await fs57.readFile(projectJsonPath, "utf8");
|
|
29008
29871
|
const project = JSON.parse(content);
|
|
29009
29872
|
if (project.cliVersion !== VERSION) {
|
|
29010
29873
|
project.cliVersion = VERSION;
|
|
29011
|
-
await
|
|
29874
|
+
await fs57.writeFile(projectJsonPath, JSON.stringify(project, null, 2));
|
|
29012
29875
|
migrated++;
|
|
29013
29876
|
}
|
|
29014
29877
|
} catch (error) {
|
|
@@ -29030,7 +29893,7 @@ async function ensureStatusLineSettings(settingsPath, statusLinePath) {
|
|
|
29030
29893
|
let settings = {};
|
|
29031
29894
|
if (await fileExists(settingsPath)) {
|
|
29032
29895
|
try {
|
|
29033
|
-
settings = JSON.parse(await
|
|
29896
|
+
settings = JSON.parse(await fs57.readFile(settingsPath, "utf8"));
|
|
29034
29897
|
} catch (error) {
|
|
29035
29898
|
if (!(error instanceof SyntaxError)) {
|
|
29036
29899
|
throw error;
|
|
@@ -29038,42 +29901,42 @@ async function ensureStatusLineSettings(settingsPath, statusLinePath) {
|
|
|
29038
29901
|
}
|
|
29039
29902
|
}
|
|
29040
29903
|
settings.statusLine = { type: "command", command: statusLinePath };
|
|
29041
|
-
await
|
|
29904
|
+
await fs57.writeFile(settingsPath, JSON.stringify(settings, null, 2));
|
|
29042
29905
|
}
|
|
29043
29906
|
async function installStatusLine() {
|
|
29044
29907
|
try {
|
|
29045
|
-
const claudeDir =
|
|
29046
|
-
const settingsPath =
|
|
29047
|
-
const claudeStatusLinePath =
|
|
29048
|
-
const prjctStatusLineDir =
|
|
29049
|
-
const prjctStatusLinePath =
|
|
29050
|
-
const prjctThemesDir =
|
|
29051
|
-
const prjctLibDir =
|
|
29052
|
-
const prjctComponentsDir =
|
|
29053
|
-
const prjctConfigPath =
|
|
29054
|
-
const assetsDir =
|
|
29055
|
-
const sourceScript =
|
|
29056
|
-
const sourceThemeDir =
|
|
29057
|
-
const sourceLibDir =
|
|
29058
|
-
const sourceComponentsDir =
|
|
29059
|
-
const sourceConfigPath =
|
|
29908
|
+
const claudeDir = path61.join(os18.homedir(), ".claude");
|
|
29909
|
+
const settingsPath = path61.join(claudeDir, "settings.json");
|
|
29910
|
+
const claudeStatusLinePath = path61.join(claudeDir, "prjct-statusline.sh");
|
|
29911
|
+
const prjctStatusLineDir = path61.join(os18.homedir(), ".prjct-cli", "statusline");
|
|
29912
|
+
const prjctStatusLinePath = path61.join(prjctStatusLineDir, "statusline.sh");
|
|
29913
|
+
const prjctThemesDir = path61.join(prjctStatusLineDir, "themes");
|
|
29914
|
+
const prjctLibDir = path61.join(prjctStatusLineDir, "lib");
|
|
29915
|
+
const prjctComponentsDir = path61.join(prjctStatusLineDir, "components");
|
|
29916
|
+
const prjctConfigPath = path61.join(prjctStatusLineDir, "config.json");
|
|
29917
|
+
const assetsDir = path61.join(PACKAGE_ROOT, "assets", "statusline");
|
|
29918
|
+
const sourceScript = path61.join(assetsDir, "statusline.sh");
|
|
29919
|
+
const sourceThemeDir = path61.join(assetsDir, "themes");
|
|
29920
|
+
const sourceLibDir = path61.join(assetsDir, "lib");
|
|
29921
|
+
const sourceComponentsDir = path61.join(assetsDir, "components");
|
|
29922
|
+
const sourceConfigPath = path61.join(assetsDir, "default-config.json");
|
|
29060
29923
|
if (!await fileExists(claudeDir)) {
|
|
29061
|
-
await
|
|
29924
|
+
await fs57.mkdir(claudeDir, { recursive: true });
|
|
29062
29925
|
}
|
|
29063
29926
|
if (!await fileExists(prjctStatusLineDir)) {
|
|
29064
|
-
await
|
|
29927
|
+
await fs57.mkdir(prjctStatusLineDir, { recursive: true });
|
|
29065
29928
|
}
|
|
29066
29929
|
if (!await fileExists(prjctThemesDir)) {
|
|
29067
|
-
await
|
|
29930
|
+
await fs57.mkdir(prjctThemesDir, { recursive: true });
|
|
29068
29931
|
}
|
|
29069
29932
|
if (!await fileExists(prjctLibDir)) {
|
|
29070
|
-
await
|
|
29933
|
+
await fs57.mkdir(prjctLibDir, { recursive: true });
|
|
29071
29934
|
}
|
|
29072
29935
|
if (!await fileExists(prjctComponentsDir)) {
|
|
29073
|
-
await
|
|
29936
|
+
await fs57.mkdir(prjctComponentsDir, { recursive: true });
|
|
29074
29937
|
}
|
|
29075
29938
|
if (await fileExists(prjctStatusLinePath)) {
|
|
29076
|
-
const existingContent = await
|
|
29939
|
+
const existingContent = await fs57.readFile(prjctStatusLinePath, "utf8");
|
|
29077
29940
|
if (existingContent.includes("CLI_VERSION=")) {
|
|
29078
29941
|
const versionMatch = existingContent.match(/CLI_VERSION="([^"]*)"/);
|
|
29079
29942
|
if (versionMatch && versionMatch[1] !== VERSION) {
|
|
@@ -29081,7 +29944,7 @@ async function installStatusLine() {
|
|
|
29081
29944
|
/CLI_VERSION="[^"]*"/,
|
|
29082
29945
|
`CLI_VERSION="${VERSION}"`
|
|
29083
29946
|
);
|
|
29084
|
-
await
|
|
29947
|
+
await fs57.writeFile(prjctStatusLinePath, updatedContent, { mode: 493 });
|
|
29085
29948
|
}
|
|
29086
29949
|
await installStatusLineModules(sourceLibDir, prjctLibDir);
|
|
29087
29950
|
await installStatusLineModules(sourceComponentsDir, prjctComponentsDir);
|
|
@@ -29091,21 +29954,21 @@ async function installStatusLine() {
|
|
|
29091
29954
|
}
|
|
29092
29955
|
}
|
|
29093
29956
|
if (await fileExists(sourceScript)) {
|
|
29094
|
-
let scriptContent = await
|
|
29957
|
+
let scriptContent = await fs57.readFile(sourceScript, "utf8");
|
|
29095
29958
|
scriptContent = scriptContent.replace(/CLI_VERSION="[^"]*"/, `CLI_VERSION="${VERSION}"`);
|
|
29096
|
-
await
|
|
29959
|
+
await fs57.writeFile(prjctStatusLinePath, scriptContent, { mode: 493 });
|
|
29097
29960
|
await installStatusLineModules(sourceLibDir, prjctLibDir);
|
|
29098
29961
|
await installStatusLineModules(sourceComponentsDir, prjctComponentsDir);
|
|
29099
29962
|
if (await fileExists(sourceThemeDir)) {
|
|
29100
|
-
const themes = await
|
|
29963
|
+
const themes = await fs57.readdir(sourceThemeDir);
|
|
29101
29964
|
for (const theme of themes) {
|
|
29102
|
-
const src =
|
|
29103
|
-
const dest =
|
|
29104
|
-
await
|
|
29965
|
+
const src = path61.join(sourceThemeDir, theme);
|
|
29966
|
+
const dest = path61.join(prjctThemesDir, theme);
|
|
29967
|
+
await fs57.copyFile(src, dest);
|
|
29105
29968
|
}
|
|
29106
29969
|
}
|
|
29107
29970
|
if (!await fileExists(prjctConfigPath) && await fileExists(sourceConfigPath)) {
|
|
29108
|
-
await
|
|
29971
|
+
await fs57.copyFile(sourceConfigPath, prjctConfigPath);
|
|
29109
29972
|
}
|
|
29110
29973
|
} else {
|
|
29111
29974
|
const scriptContent = `#!/bin/bash
|
|
@@ -29140,7 +30003,7 @@ if [ -f "$CONFIG" ]; then
|
|
|
29140
30003
|
fi
|
|
29141
30004
|
echo "prjct"
|
|
29142
30005
|
`;
|
|
29143
|
-
await
|
|
30006
|
+
await fs57.writeFile(prjctStatusLinePath, scriptContent, { mode: 493 });
|
|
29144
30007
|
}
|
|
29145
30008
|
await ensureStatusLineSymlink(claudeStatusLinePath, prjctStatusLinePath);
|
|
29146
30009
|
await ensureStatusLineSettings(settingsPath, claudeStatusLinePath);
|
|
@@ -29152,10 +30015,10 @@ echo "prjct"
|
|
|
29152
30015
|
}
|
|
29153
30016
|
async function installContext7MCP() {
|
|
29154
30017
|
try {
|
|
29155
|
-
const claudeDir =
|
|
29156
|
-
const mcpConfigPath =
|
|
30018
|
+
const claudeDir = path61.join(os18.homedir(), ".claude");
|
|
30019
|
+
const mcpConfigPath = path61.join(claudeDir, "mcp.json");
|
|
29157
30020
|
if (!await fileExists(claudeDir)) {
|
|
29158
|
-
await
|
|
30021
|
+
await fs57.mkdir(claudeDir, { recursive: true });
|
|
29159
30022
|
}
|
|
29160
30023
|
const context7Config = {
|
|
29161
30024
|
mcpServers: {
|
|
@@ -29166,16 +30029,16 @@ async function installContext7MCP() {
|
|
|
29166
30029
|
}
|
|
29167
30030
|
};
|
|
29168
30031
|
if (await fileExists(mcpConfigPath)) {
|
|
29169
|
-
const existingContent = await
|
|
30032
|
+
const existingContent = await fs57.readFile(mcpConfigPath, "utf-8");
|
|
29170
30033
|
const existingConfig = JSON.parse(existingContent);
|
|
29171
30034
|
if (existingConfig.mcpServers?.context7) {
|
|
29172
30035
|
return;
|
|
29173
30036
|
}
|
|
29174
30037
|
existingConfig.mcpServers = existingConfig.mcpServers || {};
|
|
29175
30038
|
existingConfig.mcpServers.context7 = context7Config.mcpServers.context7;
|
|
29176
|
-
await
|
|
30039
|
+
await fs57.writeFile(mcpConfigPath, JSON.stringify(existingConfig, null, 2), "utf-8");
|
|
29177
30040
|
} else {
|
|
29178
|
-
await
|
|
30041
|
+
await fs57.writeFile(mcpConfigPath, JSON.stringify(context7Config, null, 2), "utf-8");
|
|
29179
30042
|
}
|
|
29180
30043
|
} catch (error) {
|
|
29181
30044
|
logger_default.warn(`Context7 MCP setup warning: ${getErrorMessage2(error)}`);
|
|
@@ -29185,34 +30048,34 @@ async function installStatusLineModules(sourceDir, destDir) {
|
|
|
29185
30048
|
if (!await fileExists(sourceDir)) {
|
|
29186
30049
|
return;
|
|
29187
30050
|
}
|
|
29188
|
-
const files = await
|
|
30051
|
+
const files = await fs57.readdir(sourceDir);
|
|
29189
30052
|
for (const file of files) {
|
|
29190
30053
|
if (file.endsWith(".sh")) {
|
|
29191
|
-
const src =
|
|
29192
|
-
const dest =
|
|
29193
|
-
await
|
|
29194
|
-
await
|
|
30054
|
+
const src = path61.join(sourceDir, file);
|
|
30055
|
+
const dest = path61.join(destDir, file);
|
|
30056
|
+
await fs57.copyFile(src, dest);
|
|
30057
|
+
await fs57.chmod(dest, 493);
|
|
29195
30058
|
}
|
|
29196
30059
|
}
|
|
29197
30060
|
}
|
|
29198
30061
|
async function ensureStatusLineSymlink(linkPath, targetPath) {
|
|
29199
30062
|
try {
|
|
29200
30063
|
if (await fileExists(linkPath)) {
|
|
29201
|
-
const stats = await
|
|
30064
|
+
const stats = await fs57.lstat(linkPath);
|
|
29202
30065
|
if (stats.isSymbolicLink()) {
|
|
29203
|
-
const existingTarget = await
|
|
30066
|
+
const existingTarget = await fs57.readlink(linkPath);
|
|
29204
30067
|
if (existingTarget === targetPath) {
|
|
29205
30068
|
return;
|
|
29206
30069
|
}
|
|
29207
30070
|
}
|
|
29208
|
-
await
|
|
30071
|
+
await fs57.unlink(linkPath);
|
|
29209
30072
|
}
|
|
29210
|
-
await
|
|
30073
|
+
await fs57.symlink(targetPath, linkPath);
|
|
29211
30074
|
} catch (_error) {
|
|
29212
30075
|
try {
|
|
29213
30076
|
if (await fileExists(targetPath)) {
|
|
29214
|
-
await
|
|
29215
|
-
await
|
|
30077
|
+
await fs57.copyFile(targetPath, linkPath);
|
|
30078
|
+
await fs57.chmod(linkPath, 493);
|
|
29216
30079
|
}
|
|
29217
30080
|
} catch (copyError) {
|
|
29218
30081
|
if (!isNotFoundError(copyError)) {
|
|
@@ -29627,7 +30490,7 @@ var init_registry2 = __esm({
|
|
|
29627
30490
|
});
|
|
29628
30491
|
|
|
29629
30492
|
// core/commands/analytics.ts
|
|
29630
|
-
import
|
|
30493
|
+
import path62 from "node:path";
|
|
29631
30494
|
var AnalyticsCommands;
|
|
29632
30495
|
var init_analytics = __esm({
|
|
29633
30496
|
"core/commands/analytics.ts"() {
|
|
@@ -29654,7 +30517,7 @@ var init_analytics = __esm({
|
|
|
29654
30517
|
output_default.failWithHint("NO_PROJECT_ID");
|
|
29655
30518
|
return { success: false, error: "No project ID found" };
|
|
29656
30519
|
}
|
|
29657
|
-
const projectName =
|
|
30520
|
+
const projectName = path62.basename(projectPath);
|
|
29658
30521
|
const currentTask = await stateStorage.getCurrentTask(projectId);
|
|
29659
30522
|
const queueTasks = await queueStorage.getActiveTasks(projectId);
|
|
29660
30523
|
const shipped = await shippedStorage.getRecent(projectId, 5);
|
|
@@ -29906,8 +30769,8 @@ ${"\u2550".repeat(50)}
|
|
|
29906
30769
|
});
|
|
29907
30770
|
|
|
29908
30771
|
// core/commands/context.ts
|
|
29909
|
-
import
|
|
29910
|
-
import
|
|
30772
|
+
import fs58 from "node:fs/promises";
|
|
30773
|
+
import path63 from "node:path";
|
|
29911
30774
|
var ContextCommands, contextCommands;
|
|
29912
30775
|
var init_context = __esm({
|
|
29913
30776
|
"core/commands/context.ts"() {
|
|
@@ -30033,8 +30896,8 @@ var init_context = __esm({
|
|
|
30033
30896
|
*/
|
|
30034
30897
|
async loadRepoAnalysis(globalPath) {
|
|
30035
30898
|
try {
|
|
30036
|
-
const analysisPath =
|
|
30037
|
-
const content = await
|
|
30899
|
+
const analysisPath = path63.join(globalPath, "analysis", "repo-analysis.json");
|
|
30900
|
+
const content = await fs58.readFile(analysisPath, "utf-8");
|
|
30038
30901
|
const data = JSON.parse(content);
|
|
30039
30902
|
return {
|
|
30040
30903
|
ecosystem: data.ecosystem || "unknown",
|
|
@@ -30053,7 +30916,7 @@ var init_context = __esm({
|
|
|
30053
30916
|
});
|
|
30054
30917
|
|
|
30055
30918
|
// core/commands/cleanup.ts
|
|
30056
|
-
import
|
|
30919
|
+
import path64 from "node:path";
|
|
30057
30920
|
async function cleanupMemory(projectPath) {
|
|
30058
30921
|
const projectId = await config_manager_default.getProjectId(projectPath);
|
|
30059
30922
|
const results = { rotated: [], totalSize: 0, freedSpace: 0 };
|
|
@@ -30069,7 +30932,7 @@ async function cleanupMemory(projectPath) {
|
|
|
30069
30932
|
results.totalSize += sizeMB;
|
|
30070
30933
|
const rotated = await jsonl_helper_exports.rotateJsonLinesIfNeeded(filePath, 10);
|
|
30071
30934
|
if (rotated) {
|
|
30072
|
-
results.rotated.push(
|
|
30935
|
+
results.rotated.push(path64.basename(filePath));
|
|
30073
30936
|
results.freedSpace += sizeMB;
|
|
30074
30937
|
}
|
|
30075
30938
|
}
|
|
@@ -30176,7 +31039,7 @@ var init_cleanup = __esm({
|
|
|
30176
31039
|
});
|
|
30177
31040
|
|
|
30178
31041
|
// core/commands/design.ts
|
|
30179
|
-
import
|
|
31042
|
+
import path65 from "node:path";
|
|
30180
31043
|
async function design(target = null, options = {}, projectPath = process.cwd()) {
|
|
30181
31044
|
try {
|
|
30182
31045
|
const designType = options.type || "architecture";
|
|
@@ -30188,7 +31051,7 @@ async function design(target = null, options = {}, projectPath = process.cwd())
|
|
|
30188
31051
|
const designTarget = target || "system";
|
|
30189
31052
|
output_default.spin(`designing ${designType}...`);
|
|
30190
31053
|
const projectId = await config_manager_default.getProjectId(projectPath);
|
|
30191
|
-
const designsPath =
|
|
31054
|
+
const designsPath = path65.join(
|
|
30192
31055
|
path_manager_default.getGlobalProjectPath(projectId),
|
|
30193
31056
|
"planning",
|
|
30194
31057
|
"designs"
|
|
@@ -30228,7 +31091,7 @@ async function design(target = null, options = {}, projectPath = process.cwd())
|
|
|
30228
31091
|
break;
|
|
30229
31092
|
}
|
|
30230
31093
|
const designFileName = `${designType}-${designTarget.toLowerCase().replace(/\s+/g, "-")}.md`;
|
|
30231
|
-
const designFilePath =
|
|
31094
|
+
const designFilePath = path65.join(designsPath, designFileName);
|
|
30232
31095
|
await file_helper_exports.writeFile(designFilePath, designContent);
|
|
30233
31096
|
await memoryService.log(projectPath, "design_created", {
|
|
30234
31097
|
type: designType,
|
|
@@ -30253,7 +31116,7 @@ var init_design = __esm({
|
|
|
30253
31116
|
});
|
|
30254
31117
|
|
|
30255
31118
|
// core/commands/snapshots.ts
|
|
30256
|
-
import
|
|
31119
|
+
import path66 from "node:path";
|
|
30257
31120
|
async function recover(projectPath = process.cwd()) {
|
|
30258
31121
|
try {
|
|
30259
31122
|
const projectId = await config_manager_default.getProjectId(projectPath);
|
|
@@ -30305,7 +31168,7 @@ async function undo(projectPath = process.cwd()) {
|
|
|
30305
31168
|
output_default.failWithHint("NO_PROJECT_ID");
|
|
30306
31169
|
return { success: false, error: "No project ID found" };
|
|
30307
31170
|
}
|
|
30308
|
-
const snapshotsPath =
|
|
31171
|
+
const snapshotsPath = path66.join(path_manager_default.getGlobalProjectPath(projectId), "snapshots");
|
|
30309
31172
|
await file_helper_exports.ensureDir(snapshotsPath);
|
|
30310
31173
|
const { execSync: execSync5 } = await import("node:child_process");
|
|
30311
31174
|
try {
|
|
@@ -30323,7 +31186,7 @@ async function undo(projectPath = process.cwd()) {
|
|
|
30323
31186
|
cwd: projectPath,
|
|
30324
31187
|
encoding: "utf-8"
|
|
30325
31188
|
});
|
|
30326
|
-
const snapshotFile =
|
|
31189
|
+
const snapshotFile = path66.join(snapshotsPath, "history.json");
|
|
30327
31190
|
let history2 = { snapshots: [], current: -1 };
|
|
30328
31191
|
try {
|
|
30329
31192
|
const content = await file_helper_exports.readFile(snapshotFile);
|
|
@@ -30363,8 +31226,8 @@ async function redo(projectPath = process.cwd()) {
|
|
|
30363
31226
|
output_default.failWithHint("NO_PROJECT_ID");
|
|
30364
31227
|
return { success: false, error: "No project ID found" };
|
|
30365
31228
|
}
|
|
30366
|
-
const snapshotsPath =
|
|
30367
|
-
const snapshotFile =
|
|
31229
|
+
const snapshotsPath = path66.join(path_manager_default.getGlobalProjectPath(projectId), "snapshots");
|
|
31230
|
+
const snapshotFile = path66.join(snapshotsPath, "history.json");
|
|
30368
31231
|
let history2;
|
|
30369
31232
|
try {
|
|
30370
31233
|
const content = await file_helper_exports.readFile(snapshotFile);
|
|
@@ -30423,8 +31286,8 @@ async function history(projectPath = process.cwd()) {
|
|
|
30423
31286
|
output_default.failWithHint("NO_PROJECT_ID");
|
|
30424
31287
|
return { success: false, error: "No project ID found" };
|
|
30425
31288
|
}
|
|
30426
|
-
const snapshotsPath =
|
|
30427
|
-
const snapshotFile =
|
|
31289
|
+
const snapshotsPath = path66.join(path_manager_default.getGlobalProjectPath(projectId), "snapshots");
|
|
31290
|
+
const snapshotFile = path66.join(snapshotsPath, "history.json");
|
|
30428
31291
|
let snapshotHistory;
|
|
30429
31292
|
try {
|
|
30430
31293
|
const content = await file_helper_exports.readFile(snapshotFile);
|
|
@@ -30627,8 +31490,8 @@ ${chalk16.cyan("Performance Report")} ${chalk16.dim(`(last ${days} days)`)}`);
|
|
|
30627
31490
|
});
|
|
30628
31491
|
|
|
30629
31492
|
// core/commands/setup.ts
|
|
30630
|
-
import
|
|
30631
|
-
import
|
|
31493
|
+
import fs59 from "node:fs/promises";
|
|
31494
|
+
import path67 from "node:path";
|
|
30632
31495
|
import chalk17 from "chalk";
|
|
30633
31496
|
var SetupCommands;
|
|
30634
31497
|
var init_setup2 = __esm({
|
|
@@ -30757,7 +31620,7 @@ Please install it first:
|
|
|
30757
31620
|
try {
|
|
30758
31621
|
const claudeDir = path_manager_default.getClaudeDir();
|
|
30759
31622
|
const settingsPath = path_manager_default.getClaudeSettingsPath();
|
|
30760
|
-
const statusLinePath =
|
|
31623
|
+
const statusLinePath = path67.join(claudeDir, "prjct-statusline.sh");
|
|
30761
31624
|
const scriptContent = `#!/bin/bash
|
|
30762
31625
|
# prjct Status Line for Claude Code
|
|
30763
31626
|
# Shows version update notifications and current task
|
|
@@ -30815,11 +31678,11 @@ fi
|
|
|
30815
31678
|
# Default: show prjct branding
|
|
30816
31679
|
echo "\u26A1 prjct"
|
|
30817
31680
|
`;
|
|
30818
|
-
await
|
|
31681
|
+
await fs59.writeFile(statusLinePath, scriptContent, { mode: 493 });
|
|
30819
31682
|
let settings = {};
|
|
30820
31683
|
if (await fileExists(settingsPath)) {
|
|
30821
31684
|
try {
|
|
30822
|
-
settings = JSON.parse(await
|
|
31685
|
+
settings = JSON.parse(await fs59.readFile(settingsPath, "utf8"));
|
|
30823
31686
|
} catch (_error) {
|
|
30824
31687
|
}
|
|
30825
31688
|
}
|
|
@@ -30827,7 +31690,7 @@ echo "\u26A1 prjct"
|
|
|
30827
31690
|
type: "command",
|
|
30828
31691
|
command: statusLinePath
|
|
30829
31692
|
};
|
|
30830
|
-
await
|
|
31693
|
+
await fs59.writeFile(settingsPath, JSON.stringify(settings, null, 2));
|
|
30831
31694
|
return { success: true };
|
|
30832
31695
|
} catch (error) {
|
|
30833
31696
|
return { success: false, error: getErrorMessage2(error) };
|
|
@@ -30883,18 +31746,18 @@ echo "\u26A1 prjct"
|
|
|
30883
31746
|
});
|
|
30884
31747
|
|
|
30885
31748
|
// core/utils/project-commands.ts
|
|
30886
|
-
import
|
|
31749
|
+
import path68 from "node:path";
|
|
30887
31750
|
async function detectPackageManager(projectPath, pkg) {
|
|
30888
31751
|
const declared = pkg?.packageManager?.trim().toLowerCase();
|
|
30889
31752
|
if (declared?.startsWith("pnpm@")) return "pnpm";
|
|
30890
31753
|
if (declared?.startsWith("yarn@")) return "yarn";
|
|
30891
31754
|
if (declared?.startsWith("bun@")) return "bun";
|
|
30892
31755
|
if (declared?.startsWith("npm@")) return "npm";
|
|
30893
|
-
if (await fileExists2(
|
|
30894
|
-
if (await fileExists2(
|
|
30895
|
-
if (await fileExists2(
|
|
30896
|
-
if (await fileExists2(
|
|
30897
|
-
if (await fileExists2(
|
|
31756
|
+
if (await fileExists2(path68.join(projectPath, "pnpm-lock.yaml"))) return "pnpm";
|
|
31757
|
+
if (await fileExists2(path68.join(projectPath, "yarn.lock"))) return "yarn";
|
|
31758
|
+
if (await fileExists2(path68.join(projectPath, "bun.lockb"))) return "bun";
|
|
31759
|
+
if (await fileExists2(path68.join(projectPath, "bun.lock"))) return "bun";
|
|
31760
|
+
if (await fileExists2(path68.join(projectPath, "package-lock.json"))) return "npm";
|
|
30898
31761
|
return "npm";
|
|
30899
31762
|
}
|
|
30900
31763
|
function pmRun(pm, scriptName) {
|
|
@@ -30910,7 +31773,7 @@ function pmTest(pm) {
|
|
|
30910
31773
|
return "npm test";
|
|
30911
31774
|
}
|
|
30912
31775
|
async function detectProjectCommands(projectPath) {
|
|
30913
|
-
const pkgPath =
|
|
31776
|
+
const pkgPath = path68.join(projectPath, "package.json");
|
|
30914
31777
|
const pkg = await readJson(pkgPath, null);
|
|
30915
31778
|
if (pkg) {
|
|
30916
31779
|
const pm = await detectPackageManager(projectPath, pkg);
|
|
@@ -30927,27 +31790,27 @@ async function detectProjectCommands(projectPath) {
|
|
|
30927
31790
|
}
|
|
30928
31791
|
return result;
|
|
30929
31792
|
}
|
|
30930
|
-
if (await fileExists2(
|
|
31793
|
+
if (await fileExists2(path68.join(projectPath, "pytest.ini"))) {
|
|
30931
31794
|
return { stack: "python", test: { tool: "pytest", command: "pytest" } };
|
|
30932
31795
|
}
|
|
30933
|
-
const pyproject = await readFile(
|
|
31796
|
+
const pyproject = await readFile(path68.join(projectPath, "pyproject.toml"), "");
|
|
30934
31797
|
if (pyproject.includes("[tool.pytest") || pyproject.includes("pytest")) {
|
|
30935
31798
|
return { stack: "python", test: { tool: "pytest", command: "pytest" } };
|
|
30936
31799
|
}
|
|
30937
|
-
if (await fileExists2(
|
|
31800
|
+
if (await fileExists2(path68.join(projectPath, "Cargo.toml"))) {
|
|
30938
31801
|
return { stack: "rust", test: { tool: "cargo", command: "cargo test" } };
|
|
30939
31802
|
}
|
|
30940
|
-
if (await fileExists2(
|
|
31803
|
+
if (await fileExists2(path68.join(projectPath, "go.mod"))) {
|
|
30941
31804
|
return { stack: "go", test: { tool: "go", command: "go test ./..." } };
|
|
30942
31805
|
}
|
|
30943
31806
|
const files = await listFiles(projectPath);
|
|
30944
31807
|
if (files.some((f) => f.endsWith(".sln") || f.endsWith(".csproj") || f.endsWith(".fsproj"))) {
|
|
30945
31808
|
return { stack: "dotnet", test: { tool: "dotnet", command: "dotnet test" } };
|
|
30946
31809
|
}
|
|
30947
|
-
if (await fileExists2(
|
|
31810
|
+
if (await fileExists2(path68.join(projectPath, "pom.xml"))) {
|
|
30948
31811
|
return { stack: "java", test: { tool: "maven", command: "mvn test" } };
|
|
30949
31812
|
}
|
|
30950
|
-
if (await fileExists2(
|
|
31813
|
+
if (await fileExists2(path68.join(projectPath, "gradlew")) && (await fileExists2(path68.join(projectPath, "build.gradle")) || await fileExists2(path68.join(projectPath, "build.gradle.kts")))) {
|
|
30951
31814
|
return { stack: "java", test: { tool: "gradle", command: "./gradlew test" } };
|
|
30952
31815
|
}
|
|
30953
31816
|
return { stack: "unknown" };
|
|
@@ -30964,8 +31827,8 @@ var init_project_commands = __esm({
|
|
|
30964
31827
|
});
|
|
30965
31828
|
|
|
30966
31829
|
// core/workflow/workflow-preferences.ts
|
|
30967
|
-
import { exec as
|
|
30968
|
-
import { promisify as
|
|
31830
|
+
import { exec as exec18 } from "node:child_process";
|
|
31831
|
+
import { promisify as promisify19 } from "node:util";
|
|
30969
31832
|
import chalk18 from "chalk";
|
|
30970
31833
|
function prefKey(hook, command) {
|
|
30971
31834
|
return `workflow:${hook}_${command}`;
|
|
@@ -31108,7 +31971,7 @@ var init_workflow_preferences = __esm({
|
|
|
31108
31971
|
init_memory_system();
|
|
31109
31972
|
init_constants();
|
|
31110
31973
|
init_fs();
|
|
31111
|
-
execAsync12 =
|
|
31974
|
+
execAsync12 = promisify19(exec18);
|
|
31112
31975
|
sessionPreferences = /* @__PURE__ */ new Map();
|
|
31113
31976
|
oncePreferences = /* @__PURE__ */ new Map();
|
|
31114
31977
|
__name(prefKey, "prefKey");
|
|
@@ -31122,7 +31985,7 @@ var init_workflow_preferences = __esm({
|
|
|
31122
31985
|
});
|
|
31123
31986
|
|
|
31124
31987
|
// core/commands/shipping.ts
|
|
31125
|
-
import
|
|
31988
|
+
import path69 from "node:path";
|
|
31126
31989
|
var ShippingCommands;
|
|
31127
31990
|
var init_shipping = __esm({
|
|
31128
31991
|
"core/commands/shipping.ts"() {
|
|
@@ -31268,7 +32131,7 @@ ${result.stderr}`.trim();
|
|
|
31268
32131
|
*/
|
|
31269
32132
|
async _bumpVersion(projectPath) {
|
|
31270
32133
|
try {
|
|
31271
|
-
const pkgPath =
|
|
32134
|
+
const pkgPath = path69.join(projectPath, "package.json");
|
|
31272
32135
|
const pkg = await file_helper_exports.readJson(pkgPath, { version: "0.0.0" });
|
|
31273
32136
|
const oldVersion = pkg?.version || "0.0.0";
|
|
31274
32137
|
const [major, minor, patch] = oldVersion.split(".").map(Number);
|
|
@@ -31290,7 +32153,7 @@ ${result.stderr}`.trim();
|
|
|
31290
32153
|
*/
|
|
31291
32154
|
async _updateChangelog(feature, version, projectPath) {
|
|
31292
32155
|
try {
|
|
31293
|
-
const changelogPath =
|
|
32156
|
+
const changelogPath = path69.join(projectPath, "CHANGELOG.md");
|
|
31294
32157
|
const changelog = await file_helper_exports.readFile(changelogPath, "# Changelog\n\n");
|
|
31295
32158
|
const entry = `## [${version}] - ${date_helper_exports.formatDate(/* @__PURE__ */ new Date())}
|
|
31296
32159
|
|
|
@@ -31538,8 +32401,8 @@ var init_cache2 = __esm({
|
|
|
31538
32401
|
});
|
|
31539
32402
|
|
|
31540
32403
|
// core/utils/keychain.ts
|
|
31541
|
-
import { exec as
|
|
31542
|
-
import { promisify as
|
|
32404
|
+
import { exec as exec19 } from "node:child_process";
|
|
32405
|
+
import { promisify as promisify20 } from "node:util";
|
|
31543
32406
|
async function getCredential(key) {
|
|
31544
32407
|
if (process.platform !== "darwin") {
|
|
31545
32408
|
return getEnvFallback(key);
|
|
@@ -31566,7 +32429,7 @@ var init_keychain = __esm({
|
|
|
31566
32429
|
"core/utils/keychain.ts"() {
|
|
31567
32430
|
"use strict";
|
|
31568
32431
|
init_fs();
|
|
31569
|
-
execAsync13 =
|
|
32432
|
+
execAsync13 = promisify20(exec19);
|
|
31570
32433
|
SERVICE_NAME = "prjct-cli";
|
|
31571
32434
|
__name(getCredential, "getCredential");
|
|
31572
32435
|
__name(getEnvFallback, "getEnvFallback");
|
|
@@ -32334,11 +33197,11 @@ var init_linear = __esm({
|
|
|
32334
33197
|
});
|
|
32335
33198
|
|
|
32336
33199
|
// core/utils/project-credentials.ts
|
|
32337
|
-
import
|
|
33200
|
+
import fs60 from "node:fs/promises";
|
|
32338
33201
|
import os19 from "node:os";
|
|
32339
|
-
import
|
|
33202
|
+
import path70 from "node:path";
|
|
32340
33203
|
function getCredentialsPath(projectId) {
|
|
32341
|
-
return
|
|
33204
|
+
return path70.join(os19.homedir(), ".prjct-cli", "projects", projectId, "config", "credentials.json");
|
|
32342
33205
|
}
|
|
32343
33206
|
async function getProjectCredentials(projectId) {
|
|
32344
33207
|
const credPath = getCredentialsPath(projectId);
|
|
@@ -32346,7 +33209,7 @@ async function getProjectCredentials(projectId) {
|
|
|
32346
33209
|
return {};
|
|
32347
33210
|
}
|
|
32348
33211
|
try {
|
|
32349
|
-
return JSON.parse(await
|
|
33212
|
+
return JSON.parse(await fs60.readFile(credPath, "utf-8"));
|
|
32350
33213
|
} catch (error) {
|
|
32351
33214
|
console.error("[project-credentials] Failed to read credentials:", getErrorMessage2(error));
|
|
32352
33215
|
return {};
|
|
@@ -33018,7 +33881,7 @@ var require_package = __commonJS({
|
|
|
33018
33881
|
"package.json"(exports, module) {
|
|
33019
33882
|
module.exports = {
|
|
33020
33883
|
name: "prjct-cli",
|
|
33021
|
-
version: "1.
|
|
33884
|
+
version: "1.18.0",
|
|
33022
33885
|
description: "Context layer for AI agents. Project context for Claude Code, Gemini CLI, and more.",
|
|
33023
33886
|
main: "core/index.ts",
|
|
33024
33887
|
bin: {
|
|
@@ -33125,7 +33988,7 @@ var require_package = __commonJS({
|
|
|
33125
33988
|
// core/index.ts
|
|
33126
33989
|
var core_exports = {};
|
|
33127
33990
|
import os20 from "node:os";
|
|
33128
|
-
import
|
|
33991
|
+
import path71 from "node:path";
|
|
33129
33992
|
import chalk20 from "chalk";
|
|
33130
33993
|
async function main() {
|
|
33131
33994
|
const [commandName, ...rawArgs] = process.argv.slice(2);
|
|
@@ -33230,7 +34093,8 @@ async function main() {
|
|
|
33230
34093
|
preview: options.preview === true || options["dry-run"] === true,
|
|
33231
34094
|
yes: options.yes === true,
|
|
33232
34095
|
json: options.json === true,
|
|
33233
|
-
package: options.package ? String(options.package) : void 0
|
|
34096
|
+
package: options.package ? String(options.package) : void 0,
|
|
34097
|
+
full: options.full === true
|
|
33234
34098
|
}), "sync"),
|
|
33235
34099
|
seal: /* @__PURE__ */ __name(() => commands.seal(process.cwd(), { json: options.json === true }), "seal"),
|
|
33236
34100
|
verify: /* @__PURE__ */ __name(() => commands.verify(process.cwd(), { json: options.json === true }), "verify"),
|
|
@@ -33338,13 +34202,13 @@ function parseCommandArgs(_cmd, rawArgs) {
|
|
|
33338
34202
|
}
|
|
33339
34203
|
async function displayVersion(version) {
|
|
33340
34204
|
const detection = await detectAllProviders();
|
|
33341
|
-
const claudeCommandPath =
|
|
33342
|
-
const geminiCommandPath =
|
|
34205
|
+
const claudeCommandPath = path71.join(os20.homedir(), ".claude", "commands", "p.md");
|
|
34206
|
+
const geminiCommandPath = path71.join(os20.homedir(), ".gemini", "commands", "p.toml");
|
|
33343
34207
|
const [claudeConfigured, geminiConfigured, cursorConfigured, cursorExists] = await Promise.all([
|
|
33344
34208
|
fileExists(claudeCommandPath),
|
|
33345
34209
|
fileExists(geminiCommandPath),
|
|
33346
|
-
fileExists(
|
|
33347
|
-
fileExists(
|
|
34210
|
+
fileExists(path71.join(process.cwd(), ".cursor", "commands", "sync.md")),
|
|
34211
|
+
fileExists(path71.join(process.cwd(), ".cursor"))
|
|
33348
34212
|
]);
|
|
33349
34213
|
const antigravityDetection = await detectAntigravity();
|
|
33350
34214
|
console.log(`
|
|
@@ -33483,7 +34347,7 @@ init_ai_provider();
|
|
|
33483
34347
|
init_config_manager();
|
|
33484
34348
|
init_editors_config();
|
|
33485
34349
|
import os21 from "node:os";
|
|
33486
|
-
import
|
|
34350
|
+
import path72 from "node:path";
|
|
33487
34351
|
import chalk21 from "chalk";
|
|
33488
34352
|
|
|
33489
34353
|
// core/server/server.ts
|
|
@@ -34304,13 +35168,13 @@ async function checkRoutersInstalled() {
|
|
|
34304
35168
|
const home = os21.homedir();
|
|
34305
35169
|
const detection = await detectAllProviders();
|
|
34306
35170
|
if (detection.claude.installed) {
|
|
34307
|
-
const claudeRouter =
|
|
35171
|
+
const claudeRouter = path72.join(home, ".claude", "commands", "p.md");
|
|
34308
35172
|
if (!await fileExists(claudeRouter)) {
|
|
34309
35173
|
return false;
|
|
34310
35174
|
}
|
|
34311
35175
|
}
|
|
34312
35176
|
if (detection.gemini.installed) {
|
|
34313
|
-
const geminiRouter =
|
|
35177
|
+
const geminiRouter = path72.join(home, ".gemini", "commands", "p.toml");
|
|
34314
35178
|
if (!await fileExists(geminiRouter)) {
|
|
34315
35179
|
return false;
|
|
34316
35180
|
}
|
|
@@ -34451,7 +35315,7 @@ if (args[0] === "start" || args[0] === "setup") {
|
|
|
34451
35315
|
console.error('No prjct project found. Run "prjct init" first.');
|
|
34452
35316
|
process.exitCode = 1;
|
|
34453
35317
|
} else {
|
|
34454
|
-
const linearCliPath =
|
|
35318
|
+
const linearCliPath = path72.join(__dirname, "..", "core", "cli", "linear.ts");
|
|
34455
35319
|
const linearArgs = ["--project", projectId, ...args.slice(1)];
|
|
34456
35320
|
const child = spawn("bun", [linearCliPath, ...linearArgs], {
|
|
34457
35321
|
stdio: "inherit",
|
|
@@ -34478,12 +35342,12 @@ if (args[0] === "start" || args[0] === "setup") {
|
|
|
34478
35342
|
windsurfDetected,
|
|
34479
35343
|
windsurfConfigured
|
|
34480
35344
|
] = await Promise.all([
|
|
34481
|
-
fileExists(
|
|
34482
|
-
fileExists(
|
|
34483
|
-
fileExists(
|
|
34484
|
-
fileExists(
|
|
34485
|
-
fileExists(
|
|
34486
|
-
fileExists(
|
|
35345
|
+
fileExists(path72.join(home, ".claude", "commands", "p.md")),
|
|
35346
|
+
fileExists(path72.join(home, ".gemini", "commands", "p.toml")),
|
|
35347
|
+
fileExists(path72.join(cwd, ".cursor")),
|
|
35348
|
+
fileExists(path72.join(cwd, ".cursor", "rules", "prjct.mdc")),
|
|
35349
|
+
fileExists(path72.join(cwd, ".windsurf")),
|
|
35350
|
+
fileExists(path72.join(cwd, ".windsurf", "rules", "prjct.md"))
|
|
34487
35351
|
]);
|
|
34488
35352
|
console.log(`
|
|
34489
35353
|
${chalk21.cyan("p/")} prjct v${VERSION}
|
|
@@ -34522,7 +35386,7 @@ ${chalk21.dim("Run 'prjct init' to configure (Cursor/Windsurf IDE)")}
|
|
|
34522
35386
|
${chalk21.cyan("https://prjct.app")}
|
|
34523
35387
|
`);
|
|
34524
35388
|
} else {
|
|
34525
|
-
const configPath =
|
|
35389
|
+
const configPath = path72.join(os21.homedir(), ".prjct-cli", "config", "installed-editors.json");
|
|
34526
35390
|
const routersInstalled = await checkRoutersInstalled();
|
|
34527
35391
|
if (!await fileExists(configPath) || !routersInstalled) {
|
|
34528
35392
|
console.log(`
|