prjct-cli 1.17.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 +51 -0
- package/core/__tests__/domain/change-propagator.test.ts +100 -0
- package/core/__tests__/domain/file-hasher.test.ts +146 -0
- 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/change-propagator.ts +162 -0
- package/core/domain/file-hasher.ts +296 -0
- package/core/index.ts +1 -0
- package/core/services/sync-service.ts +127 -13
- 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 +811 -471
- 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;
|
|
@@ -6576,11 +6576,11 @@ async function runSignaturesTool(args2, projectPath) {
|
|
|
6576
6576
|
}
|
|
6577
6577
|
};
|
|
6578
6578
|
}
|
|
6579
|
-
const
|
|
6580
|
-
const
|
|
6581
|
-
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);
|
|
6582
6582
|
try {
|
|
6583
|
-
const stat = await
|
|
6583
|
+
const stat = await fs61.stat(fullPath);
|
|
6584
6584
|
if (stat.isDirectory()) {
|
|
6585
6585
|
const results = await extractDirectorySignatures(filePath, projectPath, {
|
|
6586
6586
|
recursive: args2.includes("--recursive") || args2.includes("-r")
|
|
@@ -6647,11 +6647,11 @@ async function runSummaryTool(args2, projectPath) {
|
|
|
6647
6647
|
}
|
|
6648
6648
|
};
|
|
6649
6649
|
}
|
|
6650
|
-
const
|
|
6651
|
-
const
|
|
6652
|
-
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);
|
|
6653
6653
|
try {
|
|
6654
|
-
const stat = await
|
|
6654
|
+
const stat = await fs61.stat(fullPath);
|
|
6655
6655
|
if (stat.isDirectory()) {
|
|
6656
6656
|
const results = await summarizeDirectory(targetPath, projectPath, {
|
|
6657
6657
|
recursive: args2.includes("--recursive") || args2.includes("-r")
|
|
@@ -21768,16 +21768,16 @@ var init_onboarding = __esm({
|
|
|
21768
21768
|
* Detect project type from file system
|
|
21769
21769
|
*/
|
|
21770
21770
|
async detectProjectType() {
|
|
21771
|
-
const
|
|
21772
|
-
const
|
|
21771
|
+
const fs61 = await import("node:fs/promises");
|
|
21772
|
+
const path73 = await import("node:path");
|
|
21773
21773
|
try {
|
|
21774
|
-
const files = await
|
|
21774
|
+
const files = await fs61.readdir(this.projectPath);
|
|
21775
21775
|
if (files.includes("turbo.json") || files.includes("lerna.json") || files.includes("nx.json")) {
|
|
21776
21776
|
return "monorepo";
|
|
21777
21777
|
}
|
|
21778
21778
|
if (files.includes("package.json")) {
|
|
21779
|
-
const pkgPath =
|
|
21780
|
-
const pkgContent = await
|
|
21779
|
+
const pkgPath = path73.join(this.projectPath, "package.json");
|
|
21780
|
+
const pkgContent = await fs61.readFile(pkgPath, "utf-8");
|
|
21781
21781
|
const pkg = JSON.parse(pkgContent);
|
|
21782
21782
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
21783
21783
|
if (pkg.bin) return "cli-tool";
|
|
@@ -21813,32 +21813,32 @@ var init_onboarding = __esm({
|
|
|
21813
21813
|
* Detect installed AI agents from config files
|
|
21814
21814
|
*/
|
|
21815
21815
|
async detectInstalledAgents() {
|
|
21816
|
-
const
|
|
21817
|
-
const
|
|
21816
|
+
const fs61 = await import("node:fs/promises");
|
|
21817
|
+
const path73 = await import("node:path");
|
|
21818
21818
|
const os22 = await import("node:os");
|
|
21819
21819
|
const agents = [];
|
|
21820
21820
|
try {
|
|
21821
|
-
await
|
|
21821
|
+
await fs61.access(path73.join(os22.homedir(), ".claude"));
|
|
21822
21822
|
agents.push("claude");
|
|
21823
21823
|
} catch {
|
|
21824
21824
|
}
|
|
21825
21825
|
try {
|
|
21826
|
-
await
|
|
21826
|
+
await fs61.access(path73.join(this.projectPath, ".cursorrules"));
|
|
21827
21827
|
agents.push("cursor");
|
|
21828
21828
|
} catch {
|
|
21829
21829
|
}
|
|
21830
21830
|
try {
|
|
21831
|
-
await
|
|
21831
|
+
await fs61.access(path73.join(this.projectPath, ".windsurfrules"));
|
|
21832
21832
|
agents.push("windsurf");
|
|
21833
21833
|
} catch {
|
|
21834
21834
|
}
|
|
21835
21835
|
try {
|
|
21836
|
-
await
|
|
21836
|
+
await fs61.access(path73.join(this.projectPath, ".github", "copilot-instructions.md"));
|
|
21837
21837
|
agents.push("copilot");
|
|
21838
21838
|
} catch {
|
|
21839
21839
|
}
|
|
21840
21840
|
try {
|
|
21841
|
-
await
|
|
21841
|
+
await fs61.access(path73.join(os22.homedir(), ".gemini"));
|
|
21842
21842
|
agents.push("gemini");
|
|
21843
21843
|
} catch {
|
|
21844
21844
|
}
|
|
@@ -21848,17 +21848,17 @@ var init_onboarding = __esm({
|
|
|
21848
21848
|
* Detect tech stack from project files
|
|
21849
21849
|
*/
|
|
21850
21850
|
async detectStack() {
|
|
21851
|
-
const
|
|
21852
|
-
const
|
|
21851
|
+
const fs61 = await import("node:fs/promises");
|
|
21852
|
+
const path73 = await import("node:path");
|
|
21853
21853
|
const stack = {
|
|
21854
21854
|
language: "Unknown",
|
|
21855
21855
|
technologies: []
|
|
21856
21856
|
};
|
|
21857
21857
|
try {
|
|
21858
|
-
const files = await
|
|
21858
|
+
const files = await fs61.readdir(this.projectPath);
|
|
21859
21859
|
if (files.includes("package.json")) {
|
|
21860
|
-
const pkgPath =
|
|
21861
|
-
const pkgContent = await
|
|
21860
|
+
const pkgPath = path73.join(this.projectPath, "package.json");
|
|
21861
|
+
const pkgContent = await fs61.readFile(pkgPath, "utf-8");
|
|
21862
21862
|
const pkg = JSON.parse(pkgContent);
|
|
21863
21863
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
21864
21864
|
stack.language = deps.typescript ? "TypeScript" : "JavaScript";
|
|
@@ -22984,7 +22984,10 @@ var init_analysis2 = __esm({
|
|
|
22984
22984
|
if (!isNonInteractive) {
|
|
22985
22985
|
output_default.spin("Analyzing changes...");
|
|
22986
22986
|
}
|
|
22987
|
-
const result2 = await syncService.sync(projectPath, {
|
|
22987
|
+
const result2 = await syncService.sync(projectPath, {
|
|
22988
|
+
aiTools: options.aiTools,
|
|
22989
|
+
full: options.full
|
|
22990
|
+
});
|
|
22988
22991
|
if (!result2.success) {
|
|
22989
22992
|
if (isNonInteractive) {
|
|
22990
22993
|
console.log(JSON.stringify({ success: false, error: result2.error || "Sync failed" }));
|
|
@@ -23098,7 +23101,10 @@ ${formatFullDiff(diff)}`);
|
|
|
23098
23101
|
return this.showSyncResult(result2, startTime);
|
|
23099
23102
|
}
|
|
23100
23103
|
output_default.spin("Syncing project...");
|
|
23101
|
-
const result = await syncService.sync(projectPath, {
|
|
23104
|
+
const result = await syncService.sync(projectPath, {
|
|
23105
|
+
aiTools: options.aiTools,
|
|
23106
|
+
full: options.full
|
|
23107
|
+
});
|
|
23102
23108
|
if (!result.success) {
|
|
23103
23109
|
output_default.fail(result.error || "Sync failed");
|
|
23104
23110
|
return { success: false, error: result.error };
|
|
@@ -24083,8 +24089,8 @@ Generated: ${(/* @__PURE__ */ new Date()).toLocaleString()}
|
|
|
24083
24089
|
const globalPath2 = path_manager_default.getGlobalProjectPath(projectId);
|
|
24084
24090
|
const specsPath2 = path45.join(globalPath2, "planning", "specs");
|
|
24085
24091
|
try {
|
|
24086
|
-
const
|
|
24087
|
-
const files = await
|
|
24092
|
+
const fs61 = await import("node:fs/promises");
|
|
24093
|
+
const files = await fs61.readdir(specsPath2);
|
|
24088
24094
|
const specs = files.filter((f) => f.endsWith(".md") && f !== ".gitkeep");
|
|
24089
24095
|
if (specs.length === 0) {
|
|
24090
24096
|
output_default.warn("no specs yet");
|
|
@@ -25283,109 +25289,6 @@ var init_bm25 = __esm({
|
|
|
25283
25289
|
}
|
|
25284
25290
|
});
|
|
25285
25291
|
|
|
25286
|
-
// core/domain/git-cochange.ts
|
|
25287
|
-
import { exec as execCallback7 } from "node:child_process";
|
|
25288
|
-
import { promisify as promisify15 } from "node:util";
|
|
25289
|
-
async function parseGitLog(projectPath, maxCommits = 100) {
|
|
25290
|
-
try {
|
|
25291
|
-
const { stdout } = await exec14(
|
|
25292
|
-
`git log --name-only --pretty=format:'---COMMIT---' -${maxCommits}`,
|
|
25293
|
-
{ cwd: projectPath, maxBuffer: 10 * 1024 * 1024 }
|
|
25294
|
-
);
|
|
25295
|
-
const commits = [];
|
|
25296
|
-
let currentFiles = null;
|
|
25297
|
-
for (const line of stdout.split("\n")) {
|
|
25298
|
-
const trimmed = line.trim();
|
|
25299
|
-
if (trimmed === "---COMMIT---") {
|
|
25300
|
-
if (currentFiles && currentFiles.size > 0 && currentFiles.size <= MAX_FILES_PER_COMMIT) {
|
|
25301
|
-
commits.push(currentFiles);
|
|
25302
|
-
}
|
|
25303
|
-
currentFiles = /* @__PURE__ */ new Set();
|
|
25304
|
-
} else if (trimmed && currentFiles) {
|
|
25305
|
-
if (isSourceFile(trimmed)) {
|
|
25306
|
-
currentFiles.add(trimmed);
|
|
25307
|
-
}
|
|
25308
|
-
}
|
|
25309
|
-
}
|
|
25310
|
-
if (currentFiles && currentFiles.size > 0 && currentFiles.size <= MAX_FILES_PER_COMMIT) {
|
|
25311
|
-
commits.push(currentFiles);
|
|
25312
|
-
}
|
|
25313
|
-
return commits;
|
|
25314
|
-
} catch {
|
|
25315
|
-
return [];
|
|
25316
|
-
}
|
|
25317
|
-
}
|
|
25318
|
-
function isSourceFile(filePath) {
|
|
25319
|
-
const sourceExtensions = /\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|cs|rb|php|vue|svelte)$/i;
|
|
25320
|
-
return sourceExtensions.test(filePath) && !filePath.includes("node_modules/");
|
|
25321
|
-
}
|
|
25322
|
-
async function buildMatrix(projectPath, maxCommits = 100) {
|
|
25323
|
-
const commitSets = await parseGitLog(projectPath, maxCommits);
|
|
25324
|
-
const fileCommitCount = /* @__PURE__ */ new Map();
|
|
25325
|
-
const pairCount = /* @__PURE__ */ new Map();
|
|
25326
|
-
for (const files of commitSets) {
|
|
25327
|
-
const fileArray = Array.from(files);
|
|
25328
|
-
for (const file of fileArray) {
|
|
25329
|
-
fileCommitCount.set(file, (fileCommitCount.get(file) || 0) + 1);
|
|
25330
|
-
}
|
|
25331
|
-
for (let i = 0; i < fileArray.length; i++) {
|
|
25332
|
-
for (let j = i + 1; j < fileArray.length; j++) {
|
|
25333
|
-
const key = pairKey(fileArray[i], fileArray[j]);
|
|
25334
|
-
pairCount.set(key, (pairCount.get(key) || 0) + 1);
|
|
25335
|
-
}
|
|
25336
|
-
}
|
|
25337
|
-
}
|
|
25338
|
-
const matrix = {};
|
|
25339
|
-
for (const [key, count] of pairCount) {
|
|
25340
|
-
const [fileA, fileB] = key.split("\0");
|
|
25341
|
-
const countA = fileCommitCount.get(fileA) || 0;
|
|
25342
|
-
const countB = fileCommitCount.get(fileB) || 0;
|
|
25343
|
-
if (countA < MIN_FILE_OCCURRENCES || countB < MIN_FILE_OCCURRENCES) continue;
|
|
25344
|
-
const unionCount = countA + countB - count;
|
|
25345
|
-
const similarity = unionCount > 0 ? count / unionCount : 0;
|
|
25346
|
-
if (similarity < MIN_SIMILARITY) continue;
|
|
25347
|
-
if (!matrix[fileA]) matrix[fileA] = {};
|
|
25348
|
-
if (!matrix[fileB]) matrix[fileB] = {};
|
|
25349
|
-
matrix[fileA][fileB] = similarity;
|
|
25350
|
-
matrix[fileB][fileA] = similarity;
|
|
25351
|
-
}
|
|
25352
|
-
return {
|
|
25353
|
-
matrix,
|
|
25354
|
-
commitsAnalyzed: commitSets.length,
|
|
25355
|
-
filesAnalyzed: fileCommitCount.size,
|
|
25356
|
-
builtAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
25357
|
-
};
|
|
25358
|
-
}
|
|
25359
|
-
function pairKey(a, b) {
|
|
25360
|
-
return a < b ? `${a}\0${b}` : `${b}\0${a}`;
|
|
25361
|
-
}
|
|
25362
|
-
function saveMatrix(projectId, index) {
|
|
25363
|
-
database_default.setDoc(projectId, INDEX_KEY2, index);
|
|
25364
|
-
}
|
|
25365
|
-
async function indexCoChanges(projectPath, projectId, maxCommits = 100) {
|
|
25366
|
-
const index = await buildMatrix(projectPath, maxCommits);
|
|
25367
|
-
saveMatrix(projectId, index);
|
|
25368
|
-
return index;
|
|
25369
|
-
}
|
|
25370
|
-
var exec14, MIN_SIMILARITY, MIN_FILE_OCCURRENCES, MAX_FILES_PER_COMMIT, INDEX_KEY2;
|
|
25371
|
-
var init_git_cochange = __esm({
|
|
25372
|
-
"core/domain/git-cochange.ts"() {
|
|
25373
|
-
"use strict";
|
|
25374
|
-
init_database();
|
|
25375
|
-
exec14 = promisify15(execCallback7);
|
|
25376
|
-
MIN_SIMILARITY = 0.1;
|
|
25377
|
-
MIN_FILE_OCCURRENCES = 2;
|
|
25378
|
-
MAX_FILES_PER_COMMIT = 30;
|
|
25379
|
-
__name(parseGitLog, "parseGitLog");
|
|
25380
|
-
__name(isSourceFile, "isSourceFile");
|
|
25381
|
-
__name(buildMatrix, "buildMatrix");
|
|
25382
|
-
__name(pairKey, "pairKey");
|
|
25383
|
-
INDEX_KEY2 = "cochange-index";
|
|
25384
|
-
__name(saveMatrix, "saveMatrix");
|
|
25385
|
-
__name(indexCoChanges, "indexCoChanges");
|
|
25386
|
-
}
|
|
25387
|
-
});
|
|
25388
|
-
|
|
25389
25292
|
// core/domain/import-graph.ts
|
|
25390
25293
|
import fs47 from "node:fs/promises";
|
|
25391
25294
|
import path50 from "node:path";
|
|
@@ -25483,14 +25386,17 @@ async function buildGraph(projectPath) {
|
|
|
25483
25386
|
};
|
|
25484
25387
|
}
|
|
25485
25388
|
function saveGraph(projectId, graph) {
|
|
25486
|
-
database_default.setDoc(projectId,
|
|
25389
|
+
database_default.setDoc(projectId, INDEX_KEY2, graph);
|
|
25390
|
+
}
|
|
25391
|
+
function loadGraph(projectId) {
|
|
25392
|
+
return database_default.getDoc(projectId, INDEX_KEY2);
|
|
25487
25393
|
}
|
|
25488
25394
|
async function indexImports(projectPath, projectId) {
|
|
25489
25395
|
const graph = await buildGraph(projectPath);
|
|
25490
25396
|
saveGraph(projectId, graph);
|
|
25491
25397
|
return graph;
|
|
25492
25398
|
}
|
|
25493
|
-
var INDEXABLE_EXTENSIONS2, SKIP_DIRS2, RESOLVE_EXTENSIONS, IMPORT_REGEX,
|
|
25399
|
+
var INDEXABLE_EXTENSIONS2, SKIP_DIRS2, RESOLVE_EXTENSIONS, IMPORT_REGEX, INDEX_KEY2;
|
|
25494
25400
|
var init_import_graph = __esm({
|
|
25495
25401
|
"core/domain/import-graph.ts"() {
|
|
25496
25402
|
"use strict";
|
|
@@ -25514,15 +25420,362 @@ var init_import_graph = __esm({
|
|
|
25514
25420
|
__name(resolveImport2, "resolveImport");
|
|
25515
25421
|
__name(listFiles3, "listFiles");
|
|
25516
25422
|
__name(buildGraph, "buildGraph");
|
|
25517
|
-
|
|
25423
|
+
INDEX_KEY2 = "import-graph";
|
|
25518
25424
|
__name(saveGraph, "saveGraph");
|
|
25425
|
+
__name(loadGraph, "loadGraph");
|
|
25519
25426
|
__name(indexImports, "indexImports");
|
|
25520
25427
|
}
|
|
25521
25428
|
});
|
|
25522
25429
|
|
|
25523
|
-
// core/
|
|
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
|
|
25524
25490
|
import fs48 from "node:fs/promises";
|
|
25525
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";
|
|
25526
25779
|
var ContextFileGenerator;
|
|
25527
25780
|
var init_context_generator = __esm({
|
|
25528
25781
|
"core/services/context-generator.ts"() {
|
|
@@ -25547,10 +25800,10 @@ var init_context_generator = __esm({
|
|
|
25547
25800
|
async writeWithPreservation(filePath, content) {
|
|
25548
25801
|
let finalContent = content;
|
|
25549
25802
|
try {
|
|
25550
|
-
const existingContent = await
|
|
25803
|
+
const existingContent = await fs49.readFile(filePath, "utf-8");
|
|
25551
25804
|
const validation = validatePreserveBlocks(existingContent);
|
|
25552
25805
|
if (!validation.valid) {
|
|
25553
|
-
const filename =
|
|
25806
|
+
const filename = path52.basename(filePath);
|
|
25554
25807
|
console.warn(`\u26A0\uFE0F ${filename} has invalid preserve blocks:`);
|
|
25555
25808
|
for (const error of validation.errors) {
|
|
25556
25809
|
console.warn(` ${error}`);
|
|
@@ -25559,13 +25812,13 @@ var init_context_generator = __esm({
|
|
|
25559
25812
|
finalContent = mergePreservedSections(content, existingContent);
|
|
25560
25813
|
} catch {
|
|
25561
25814
|
}
|
|
25562
|
-
await
|
|
25815
|
+
await fs49.writeFile(filePath, finalContent, "utf-8");
|
|
25563
25816
|
}
|
|
25564
25817
|
/**
|
|
25565
25818
|
* Generate all context files in parallel
|
|
25566
25819
|
*/
|
|
25567
25820
|
async generate(git, stats, commands, agents, sources) {
|
|
25568
|
-
const contextPath =
|
|
25821
|
+
const contextPath = path52.join(this.config.globalPath, "context");
|
|
25569
25822
|
await Promise.all([
|
|
25570
25823
|
this.generateClaudeMd(contextPath, git, stats, commands, agents, sources),
|
|
25571
25824
|
this.generateNowMd(contextPath),
|
|
@@ -25665,7 +25918,7 @@ Load from \`~/.prjct-cli/projects/${this.config.projectId}/agents/\`:
|
|
|
25665
25918
|
**Workflow**: ${workflowAgents.join(", ")}
|
|
25666
25919
|
**Domain**: ${domainAgents.join(", ") || "none"}
|
|
25667
25920
|
`;
|
|
25668
|
-
const claudePath =
|
|
25921
|
+
const claudePath = path52.join(contextPath, "CLAUDE.md");
|
|
25669
25922
|
await this.writeWithPreservation(claudePath, content);
|
|
25670
25923
|
}
|
|
25671
25924
|
/**
|
|
@@ -25674,8 +25927,8 @@ Load from \`~/.prjct-cli/projects/${this.config.projectId}/agents/\`:
|
|
|
25674
25927
|
async generateNowMd(contextPath) {
|
|
25675
25928
|
let currentTask = null;
|
|
25676
25929
|
try {
|
|
25677
|
-
const statePath =
|
|
25678
|
-
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"));
|
|
25679
25932
|
currentTask = state.currentTask;
|
|
25680
25933
|
} catch {
|
|
25681
25934
|
}
|
|
@@ -25691,7 +25944,7 @@ _No active task_
|
|
|
25691
25944
|
|
|
25692
25945
|
Use \`p. task "description"\` to start working.
|
|
25693
25946
|
`;
|
|
25694
|
-
await this.writeWithPreservation(
|
|
25947
|
+
await this.writeWithPreservation(path52.join(contextPath, "now.md"), content);
|
|
25695
25948
|
}
|
|
25696
25949
|
/**
|
|
25697
25950
|
* Generate next.md - task queue
|
|
@@ -25699,15 +25952,15 @@ Use \`p. task "description"\` to start working.
|
|
|
25699
25952
|
async generateNextMd(contextPath) {
|
|
25700
25953
|
let queue = { tasks: [] };
|
|
25701
25954
|
try {
|
|
25702
|
-
const queuePath =
|
|
25703
|
-
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"));
|
|
25704
25957
|
} catch {
|
|
25705
25958
|
}
|
|
25706
25959
|
const content = `# NEXT
|
|
25707
25960
|
|
|
25708
25961
|
${queue.tasks.length > 0 ? queue.tasks.map((t, i) => `${i + 1}. ${t.description}${t.priority ? ` [${t.priority}]` : ""}`).join("\n") : "_Empty queue_"}
|
|
25709
25962
|
`;
|
|
25710
|
-
await this.writeWithPreservation(
|
|
25963
|
+
await this.writeWithPreservation(path52.join(contextPath, "next.md"), content);
|
|
25711
25964
|
}
|
|
25712
25965
|
/**
|
|
25713
25966
|
* Generate ideas.md - captured ideas
|
|
@@ -25715,15 +25968,15 @@ ${queue.tasks.length > 0 ? queue.tasks.map((t, i) => `${i + 1}. ${t.description}
|
|
|
25715
25968
|
async generateIdeasMd(contextPath) {
|
|
25716
25969
|
let ideas = { ideas: [] };
|
|
25717
25970
|
try {
|
|
25718
|
-
const ideasPath =
|
|
25719
|
-
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"));
|
|
25720
25973
|
} catch {
|
|
25721
25974
|
}
|
|
25722
25975
|
const content = `# IDEAS
|
|
25723
25976
|
|
|
25724
25977
|
${ideas.ideas.length > 0 ? ideas.ideas.map((i) => `- ${i.text}${i.priority ? ` [${i.priority}]` : ""}`).join("\n") : "_No ideas captured yet_"}
|
|
25725
25978
|
`;
|
|
25726
|
-
await this.writeWithPreservation(
|
|
25979
|
+
await this.writeWithPreservation(path52.join(contextPath, "ideas.md"), content);
|
|
25727
25980
|
}
|
|
25728
25981
|
/**
|
|
25729
25982
|
* Generate shipped.md - completed features
|
|
@@ -25733,8 +25986,8 @@ ${ideas.ideas.length > 0 ? ideas.ideas.map((i) => `- ${i.text}${i.priority ? ` [
|
|
|
25733
25986
|
shipped: []
|
|
25734
25987
|
};
|
|
25735
25988
|
try {
|
|
25736
|
-
const shippedPath =
|
|
25737
|
-
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"));
|
|
25738
25991
|
} catch {
|
|
25739
25992
|
}
|
|
25740
25993
|
const content = `# SHIPPED \u{1F680}
|
|
@@ -25743,7 +25996,7 @@ ${shipped.shipped.length > 0 ? shipped.shipped.slice(-10).map((s) => `- **${s.na
|
|
|
25743
25996
|
|
|
25744
25997
|
**Total shipped:** ${shipped.shipped.length}
|
|
25745
25998
|
`;
|
|
25746
|
-
await this.writeWithPreservation(
|
|
25999
|
+
await this.writeWithPreservation(path52.join(contextPath, "shipped.md"), content);
|
|
25747
26000
|
}
|
|
25748
26001
|
// ==========================================================================
|
|
25749
26002
|
// MONOREPO SUPPORT
|
|
@@ -25772,9 +26025,9 @@ ${shipped.shipped.length > 0 ? shipped.shipped.slice(-10).map((s) => `- **${s.na
|
|
|
25772
26025
|
commands,
|
|
25773
26026
|
agents
|
|
25774
26027
|
);
|
|
25775
|
-
const claudePath =
|
|
26028
|
+
const claudePath = path52.join(pkg.path, "CLAUDE.md");
|
|
25776
26029
|
await this.writeWithPreservation(claudePath, content);
|
|
25777
|
-
generatedFiles.push(
|
|
26030
|
+
generatedFiles.push(path52.relative(this.config.projectPath, claudePath));
|
|
25778
26031
|
}
|
|
25779
26032
|
return generatedFiles;
|
|
25780
26033
|
}
|
|
@@ -25787,8 +26040,8 @@ ${shipped.shipped.length > 0 ? shipped.shipped.slice(-10).map((s) => `- **${s.na
|
|
|
25787
26040
|
let pkgVersion = stats.version;
|
|
25788
26041
|
let pkgName = pkg.name;
|
|
25789
26042
|
try {
|
|
25790
|
-
const pkgJsonPath =
|
|
25791
|
-
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"));
|
|
25792
26045
|
pkgVersion = pkgJson.version || stats.version;
|
|
25793
26046
|
pkgName = pkgJson.name || pkg.name;
|
|
25794
26047
|
} catch {
|
|
@@ -25853,8 +26106,8 @@ Load from \`~/.prjct-cli/projects/${this.config.projectId}/agents/\`:
|
|
|
25853
26106
|
});
|
|
25854
26107
|
|
|
25855
26108
|
// core/services/local-state-generator.ts
|
|
25856
|
-
import
|
|
25857
|
-
import
|
|
26109
|
+
import fs50 from "node:fs/promises";
|
|
26110
|
+
import path53 from "node:path";
|
|
25858
26111
|
var LOCAL_STATE_FILENAME, LocalStateGenerator, localStateGenerator;
|
|
25859
26112
|
var init_local_state_generator = __esm({
|
|
25860
26113
|
"core/services/local-state-generator.ts"() {
|
|
@@ -25869,17 +26122,17 @@ var init_local_state_generator = __esm({
|
|
|
25869
26122
|
* Generate .prjct-state.md in the project root
|
|
25870
26123
|
*/
|
|
25871
26124
|
async generate(projectPath, state) {
|
|
25872
|
-
const filePath =
|
|
26125
|
+
const filePath = path53.join(projectPath, LOCAL_STATE_FILENAME);
|
|
25873
26126
|
const content = this.toMarkdown(state);
|
|
25874
|
-
await
|
|
26127
|
+
await fs50.writeFile(filePath, content, "utf-8");
|
|
25875
26128
|
}
|
|
25876
26129
|
/**
|
|
25877
26130
|
* Remove local state file
|
|
25878
26131
|
*/
|
|
25879
26132
|
async remove(projectPath) {
|
|
25880
|
-
const filePath =
|
|
26133
|
+
const filePath = path53.join(projectPath, LOCAL_STATE_FILENAME);
|
|
25881
26134
|
try {
|
|
25882
|
-
await
|
|
26135
|
+
await fs50.unlink(filePath);
|
|
25883
26136
|
} catch (error) {
|
|
25884
26137
|
if (!isNotFoundError(error)) throw error;
|
|
25885
26138
|
}
|
|
@@ -25888,9 +26141,9 @@ var init_local_state_generator = __esm({
|
|
|
25888
26141
|
* Check if local state file exists
|
|
25889
26142
|
*/
|
|
25890
26143
|
async exists(projectPath) {
|
|
25891
|
-
const filePath =
|
|
26144
|
+
const filePath = path53.join(projectPath, LOCAL_STATE_FILENAME);
|
|
25892
26145
|
try {
|
|
25893
|
-
await
|
|
26146
|
+
await fs50.access(filePath);
|
|
25894
26147
|
return true;
|
|
25895
26148
|
} catch {
|
|
25896
26149
|
return false;
|
|
@@ -25969,11 +26222,11 @@ var init_local_state_generator = __esm({
|
|
|
25969
26222
|
});
|
|
25970
26223
|
|
|
25971
26224
|
// core/services/skill-lock.ts
|
|
25972
|
-
import
|
|
26225
|
+
import fs51 from "node:fs/promises";
|
|
25973
26226
|
import os14 from "node:os";
|
|
25974
|
-
import
|
|
26227
|
+
import path54 from "node:path";
|
|
25975
26228
|
function getLockFilePath() {
|
|
25976
|
-
return
|
|
26229
|
+
return path54.join(os14.homedir(), ".prjct-cli", "skills", LOCK_FILE_NAME);
|
|
25977
26230
|
}
|
|
25978
26231
|
function createEmptyLockFile() {
|
|
25979
26232
|
return {
|
|
@@ -25984,7 +26237,7 @@ function createEmptyLockFile() {
|
|
|
25984
26237
|
}
|
|
25985
26238
|
async function read() {
|
|
25986
26239
|
try {
|
|
25987
|
-
const content = await
|
|
26240
|
+
const content = await fs51.readFile(getLockFilePath(), "utf-8");
|
|
25988
26241
|
return JSON.parse(content);
|
|
25989
26242
|
} catch {
|
|
25990
26243
|
return createEmptyLockFile();
|
|
@@ -25992,9 +26245,9 @@ async function read() {
|
|
|
25992
26245
|
}
|
|
25993
26246
|
async function write(lockFile) {
|
|
25994
26247
|
const lockPath = getLockFilePath();
|
|
25995
|
-
await
|
|
26248
|
+
await fs51.mkdir(path54.dirname(lockPath), { recursive: true });
|
|
25996
26249
|
lockFile.generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
25997
|
-
await
|
|
26250
|
+
await fs51.writeFile(lockPath, JSON.stringify(lockFile, null, 2), "utf-8");
|
|
25998
26251
|
}
|
|
25999
26252
|
async function addEntry(entry) {
|
|
26000
26253
|
const lockFile = await read();
|
|
@@ -26047,14 +26300,14 @@ var init_skill_lock = __esm({
|
|
|
26047
26300
|
|
|
26048
26301
|
// core/services/skill-installer.ts
|
|
26049
26302
|
import { exec as execCallback8 } from "node:child_process";
|
|
26050
|
-
import
|
|
26303
|
+
import fs52 from "node:fs/promises";
|
|
26051
26304
|
import os15 from "node:os";
|
|
26052
|
-
import
|
|
26305
|
+
import path55 from "node:path";
|
|
26053
26306
|
import { promisify as promisify16 } from "node:util";
|
|
26054
26307
|
import { glob } from "glob";
|
|
26055
26308
|
function parseSource(source) {
|
|
26056
26309
|
if (source.startsWith("./") || source.startsWith("/") || source.startsWith("~")) {
|
|
26057
|
-
const resolvedPath = source.startsWith("~") ?
|
|
26310
|
+
const resolvedPath = source.startsWith("~") ? path55.join(os15.homedir(), source.slice(1)) : path55.resolve(source);
|
|
26058
26311
|
return {
|
|
26059
26312
|
type: "local",
|
|
26060
26313
|
localPath: resolvedPath,
|
|
@@ -26092,22 +26345,22 @@ function parseSource(source) {
|
|
|
26092
26345
|
async function discoverSkills(dir) {
|
|
26093
26346
|
const skills = [];
|
|
26094
26347
|
try {
|
|
26095
|
-
const rootSkill =
|
|
26096
|
-
await
|
|
26097
|
-
const dirName =
|
|
26348
|
+
const rootSkill = path55.join(dir, "SKILL.md");
|
|
26349
|
+
await fs52.access(rootSkill);
|
|
26350
|
+
const dirName = path55.basename(dir);
|
|
26098
26351
|
skills.push({ name: dirName, filePath: rootSkill });
|
|
26099
26352
|
} catch {
|
|
26100
26353
|
}
|
|
26101
26354
|
const subdirSkills = await glob("*/SKILL.md", { cwd: dir, absolute: true });
|
|
26102
26355
|
for (const filePath of subdirSkills) {
|
|
26103
|
-
const name =
|
|
26356
|
+
const name = path55.basename(path55.dirname(filePath));
|
|
26104
26357
|
if (!skills.some((s) => s.name === name)) {
|
|
26105
26358
|
skills.push({ name, filePath });
|
|
26106
26359
|
}
|
|
26107
26360
|
}
|
|
26108
26361
|
const nestedSkills = await glob("skills/*/SKILL.md", { cwd: dir, absolute: true });
|
|
26109
26362
|
for (const filePath of nestedSkills) {
|
|
26110
|
-
const name =
|
|
26363
|
+
const name = path55.basename(path55.dirname(filePath));
|
|
26111
26364
|
if (!skills.some((s) => s.name === name)) {
|
|
26112
26365
|
skills.push({ name, filePath });
|
|
26113
26366
|
}
|
|
@@ -26143,16 +26396,16 @@ ${prjctBlock.join("\n")}
|
|
|
26143
26396
|
${content}`;
|
|
26144
26397
|
}
|
|
26145
26398
|
function getInstallDir() {
|
|
26146
|
-
return
|
|
26399
|
+
return path55.join(os15.homedir(), ".claude", "skills");
|
|
26147
26400
|
}
|
|
26148
26401
|
async function installSkillFile(sourcePath, name, source, sha) {
|
|
26149
26402
|
const installDir = getInstallDir();
|
|
26150
|
-
const targetDir =
|
|
26151
|
-
const targetPath =
|
|
26152
|
-
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");
|
|
26153
26406
|
const enrichedContent = injectSourceMetadata(content, source, sha);
|
|
26154
|
-
await
|
|
26155
|
-
await
|
|
26407
|
+
await fs52.mkdir(targetDir, { recursive: true });
|
|
26408
|
+
await fs52.writeFile(targetPath, enrichedContent, "utf-8");
|
|
26156
26409
|
return {
|
|
26157
26410
|
name,
|
|
26158
26411
|
filePath: targetPath,
|
|
@@ -26169,7 +26422,7 @@ async function installFromGitHub(source) {
|
|
|
26169
26422
|
);
|
|
26170
26423
|
return result;
|
|
26171
26424
|
}
|
|
26172
|
-
const tmpDir =
|
|
26425
|
+
const tmpDir = path55.join(os15.tmpdir(), `prjct-skill-${Date.now()}`);
|
|
26173
26426
|
try {
|
|
26174
26427
|
const cloneUrl = `https://github.com/${source.owner}/${source.repo}.git`;
|
|
26175
26428
|
await exec15(`git clone --depth 1 ${cloneUrl} ${tmpDir}`, { timeout: getTimeout("GIT_CLONE") });
|
|
@@ -26213,7 +26466,7 @@ async function installFromGitHub(source) {
|
|
|
26213
26466
|
}
|
|
26214
26467
|
} finally {
|
|
26215
26468
|
try {
|
|
26216
|
-
await
|
|
26469
|
+
await fs52.rm(tmpDir, { recursive: true, force: true });
|
|
26217
26470
|
} catch {
|
|
26218
26471
|
}
|
|
26219
26472
|
}
|
|
@@ -26223,14 +26476,14 @@ async function installFromLocal(source) {
|
|
|
26223
26476
|
const result = { installed: [], skipped: [], errors: [] };
|
|
26224
26477
|
const localPath = source.localPath;
|
|
26225
26478
|
try {
|
|
26226
|
-
await
|
|
26479
|
+
await fs52.access(localPath);
|
|
26227
26480
|
} catch {
|
|
26228
26481
|
result.errors.push(`Local path not found: ${localPath}`);
|
|
26229
26482
|
return result;
|
|
26230
26483
|
}
|
|
26231
|
-
const stat = await
|
|
26484
|
+
const stat = await fs52.stat(localPath);
|
|
26232
26485
|
if (stat.isFile()) {
|
|
26233
|
-
const name =
|
|
26486
|
+
const name = path55.basename(path55.dirname(localPath));
|
|
26234
26487
|
try {
|
|
26235
26488
|
const installed = await installSkillFile(localPath, name, source);
|
|
26236
26489
|
const lockEntry = {
|
|
@@ -26270,14 +26523,14 @@ async function installFromLocal(source) {
|
|
|
26270
26523
|
}
|
|
26271
26524
|
async function remove(name) {
|
|
26272
26525
|
const installDir = getInstallDir();
|
|
26273
|
-
const subdirPath =
|
|
26526
|
+
const subdirPath = path55.join(installDir, name);
|
|
26274
26527
|
try {
|
|
26275
|
-
await
|
|
26528
|
+
await fs52.rm(subdirPath, { recursive: true, force: true });
|
|
26276
26529
|
} catch {
|
|
26277
26530
|
}
|
|
26278
|
-
const flatPath =
|
|
26531
|
+
const flatPath = path55.join(installDir, `${name}.md`);
|
|
26279
26532
|
try {
|
|
26280
|
-
await
|
|
26533
|
+
await fs52.rm(flatPath, { force: true });
|
|
26281
26534
|
} catch {
|
|
26282
26535
|
}
|
|
26283
26536
|
return skillLock.removeEntry(name);
|
|
@@ -26325,8 +26578,8 @@ var init_skill_installer = __esm({
|
|
|
26325
26578
|
});
|
|
26326
26579
|
|
|
26327
26580
|
// core/services/stack-detector.ts
|
|
26328
|
-
import
|
|
26329
|
-
import
|
|
26581
|
+
import fs53 from "node:fs/promises";
|
|
26582
|
+
import path56 from "node:path";
|
|
26330
26583
|
var StackDetector;
|
|
26331
26584
|
var init_stack_detector = __esm({
|
|
26332
26585
|
"core/services/stack-detector.ts"() {
|
|
@@ -26485,8 +26738,8 @@ var init_stack_detector = __esm({
|
|
|
26485
26738
|
*/
|
|
26486
26739
|
async readPackageJson() {
|
|
26487
26740
|
try {
|
|
26488
|
-
const pkgPath =
|
|
26489
|
-
const content = await
|
|
26741
|
+
const pkgPath = path56.join(this.projectPath, "package.json");
|
|
26742
|
+
const content = await fs53.readFile(pkgPath, "utf-8");
|
|
26490
26743
|
return JSON.parse(content);
|
|
26491
26744
|
} catch {
|
|
26492
26745
|
return null;
|
|
@@ -26497,7 +26750,7 @@ var init_stack_detector = __esm({
|
|
|
26497
26750
|
*/
|
|
26498
26751
|
async fileExists(filename) {
|
|
26499
26752
|
try {
|
|
26500
|
-
await
|
|
26753
|
+
await fs53.access(path56.join(this.projectPath, filename));
|
|
26501
26754
|
return true;
|
|
26502
26755
|
} catch {
|
|
26503
26756
|
return false;
|
|
@@ -26509,8 +26762,8 @@ var init_stack_detector = __esm({
|
|
|
26509
26762
|
|
|
26510
26763
|
// core/services/sync-verifier.ts
|
|
26511
26764
|
import { exec as exec16 } from "node:child_process";
|
|
26512
|
-
import
|
|
26513
|
-
import
|
|
26765
|
+
import fs54 from "node:fs/promises";
|
|
26766
|
+
import path57 from "node:path";
|
|
26514
26767
|
import { promisify as promisify17 } from "node:util";
|
|
26515
26768
|
var execAsync10, BUILTIN_CHECKS, SyncVerifier, syncVerifier;
|
|
26516
26769
|
var init_sync_verifier = __esm({
|
|
@@ -26527,9 +26780,9 @@ var init_sync_verifier = __esm({
|
|
|
26527
26780
|
const expected = ["context/CLAUDE.md"];
|
|
26528
26781
|
const missing = [];
|
|
26529
26782
|
for (const file of expected) {
|
|
26530
|
-
const filePath =
|
|
26783
|
+
const filePath = path57.join(globalPath, file);
|
|
26531
26784
|
try {
|
|
26532
|
-
await
|
|
26785
|
+
await fs54.access(filePath);
|
|
26533
26786
|
} catch {
|
|
26534
26787
|
missing.push(file);
|
|
26535
26788
|
}
|
|
@@ -26550,9 +26803,9 @@ var init_sync_verifier = __esm({
|
|
|
26550
26803
|
const jsonFiles = ["storage/state.json"];
|
|
26551
26804
|
const invalid = [];
|
|
26552
26805
|
for (const file of jsonFiles) {
|
|
26553
|
-
const filePath =
|
|
26806
|
+
const filePath = path57.join(globalPath, file);
|
|
26554
26807
|
try {
|
|
26555
|
-
const content = await
|
|
26808
|
+
const content = await fs54.readFile(filePath, "utf-8");
|
|
26556
26809
|
JSON.parse(content);
|
|
26557
26810
|
} catch (error) {
|
|
26558
26811
|
if (!isNotFoundError(error)) {
|
|
@@ -26573,7 +26826,7 @@ var init_sync_verifier = __esm({
|
|
|
26573
26826
|
*/
|
|
26574
26827
|
async noSensitiveData(globalPath) {
|
|
26575
26828
|
const start = Date.now();
|
|
26576
|
-
const contextDir =
|
|
26829
|
+
const contextDir = path57.join(globalPath, "context");
|
|
26577
26830
|
const patterns = [
|
|
26578
26831
|
/(?:api[_-]?key|apikey)\s*[:=]\s*['"][^'"]{10,}/i,
|
|
26579
26832
|
/(?:password|passwd|pwd)\s*[:=]\s*['"][^'"]{4,}/i,
|
|
@@ -26581,10 +26834,10 @@ var init_sync_verifier = __esm({
|
|
|
26581
26834
|
];
|
|
26582
26835
|
const violations = [];
|
|
26583
26836
|
try {
|
|
26584
|
-
const files = await
|
|
26837
|
+
const files = await fs54.readdir(contextDir);
|
|
26585
26838
|
for (const file of files) {
|
|
26586
26839
|
if (!file.endsWith(".md")) continue;
|
|
26587
|
-
const content = await
|
|
26840
|
+
const content = await fs54.readFile(path57.join(contextDir, file), "utf-8");
|
|
26588
26841
|
for (const pattern of patterns) {
|
|
26589
26842
|
if (pattern.test(content)) {
|
|
26590
26843
|
violations.push(`${file}: potential sensitive data detected`);
|
|
@@ -26705,9 +26958,9 @@ var init_sync_verifier = __esm({
|
|
|
26705
26958
|
|
|
26706
26959
|
// core/services/sync-service.ts
|
|
26707
26960
|
import { exec as exec17 } from "node:child_process";
|
|
26708
|
-
import
|
|
26961
|
+
import fs55 from "node:fs/promises";
|
|
26709
26962
|
import os16 from "node:os";
|
|
26710
|
-
import
|
|
26963
|
+
import path58 from "node:path";
|
|
26711
26964
|
import { promisify as promisify18 } from "node:util";
|
|
26712
26965
|
var execAsync11, SyncService, syncService;
|
|
26713
26966
|
var init_sync_service = __esm({
|
|
@@ -26715,6 +26968,8 @@ var init_sync_service = __esm({
|
|
|
26715
26968
|
"use strict";
|
|
26716
26969
|
init_ai_tools();
|
|
26717
26970
|
init_bm25();
|
|
26971
|
+
init_change_propagator();
|
|
26972
|
+
init_file_hasher();
|
|
26718
26973
|
init_git_cochange();
|
|
26719
26974
|
init_import_graph();
|
|
26720
26975
|
init_errors();
|
|
@@ -26794,20 +27049,80 @@ var init_sync_service = __esm({
|
|
|
26794
27049
|
this.detectCommands(),
|
|
26795
27050
|
this.detectStack()
|
|
26796
27051
|
]);
|
|
26797
|
-
|
|
26798
|
-
|
|
26799
|
-
|
|
26800
|
-
|
|
26801
|
-
|
|
26802
|
-
|
|
26803
|
-
|
|
26804
|
-
|
|
26805
|
-
|
|
26806
|
-
|
|
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
|
+
}
|
|
26807
27109
|
}
|
|
26808
|
-
|
|
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();
|
|
26809
27124
|
const skills = this.configureSkills(agents);
|
|
26810
|
-
const skillsInstalled = await this.autoInstallSkills(agents);
|
|
27125
|
+
const skillsInstalled = shouldRegenerateAgents ? await this.autoInstallSkills(agents) : [];
|
|
26811
27126
|
const sources = this.buildSources(stats, commands);
|
|
26812
27127
|
const contextFiles = await this.generateContextFiles(git, stats, commands, agents, sources);
|
|
26813
27128
|
const projectContext = {
|
|
@@ -26875,7 +27190,8 @@ var init_sync_service = __esm({
|
|
|
26875
27190
|
success: r.success
|
|
26876
27191
|
})),
|
|
26877
27192
|
syncMetrics,
|
|
26878
|
-
verification
|
|
27193
|
+
verification,
|
|
27194
|
+
incremental: incrementalInfo
|
|
26879
27195
|
};
|
|
26880
27196
|
} catch (error) {
|
|
26881
27197
|
return {
|
|
@@ -26901,7 +27217,7 @@ var init_sync_service = __esm({
|
|
|
26901
27217
|
async ensureDirectories() {
|
|
26902
27218
|
const dirs = ["storage", "context", "agents", "memory", "analysis", "config", "sync"];
|
|
26903
27219
|
await Promise.all(
|
|
26904
|
-
dirs.map((dir) =>
|
|
27220
|
+
dirs.map((dir) => fs55.mkdir(path58.join(this.globalPath, dir), { recursive: true }))
|
|
26905
27221
|
);
|
|
26906
27222
|
}
|
|
26907
27223
|
// ==========================================================================
|
|
@@ -26972,7 +27288,7 @@ var init_sync_service = __esm({
|
|
|
26972
27288
|
const stats = {
|
|
26973
27289
|
fileCount: 0,
|
|
26974
27290
|
version: "0.0.0",
|
|
26975
|
-
name:
|
|
27291
|
+
name: path58.basename(this.projectPath),
|
|
26976
27292
|
ecosystem: "unknown",
|
|
26977
27293
|
projectType: "simple",
|
|
26978
27294
|
languages: [],
|
|
@@ -26989,8 +27305,8 @@ var init_sync_service = __esm({
|
|
|
26989
27305
|
stats.fileCount = 0;
|
|
26990
27306
|
}
|
|
26991
27307
|
try {
|
|
26992
|
-
const pkgPath =
|
|
26993
|
-
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"));
|
|
26994
27310
|
stats.version = pkg.version || "0.0.0";
|
|
26995
27311
|
stats.name = pkg.name || stats.name;
|
|
26996
27312
|
stats.ecosystem = "JavaScript";
|
|
@@ -27135,12 +27451,12 @@ var init_sync_service = __esm({
|
|
|
27135
27451
|
// ==========================================================================
|
|
27136
27452
|
async generateAgents(stack, stats) {
|
|
27137
27453
|
const agents = [];
|
|
27138
|
-
const agentsPath =
|
|
27454
|
+
const agentsPath = path58.join(this.globalPath, "agents");
|
|
27139
27455
|
try {
|
|
27140
|
-
const files = await
|
|
27456
|
+
const files = await fs55.readdir(agentsPath);
|
|
27141
27457
|
for (const file of files) {
|
|
27142
27458
|
if (file.endsWith(".md")) {
|
|
27143
|
-
await
|
|
27459
|
+
await fs55.unlink(path58.join(agentsPath, file));
|
|
27144
27460
|
}
|
|
27145
27461
|
}
|
|
27146
27462
|
} catch (error) {
|
|
@@ -27178,6 +27494,27 @@ var init_sync_service = __esm({
|
|
|
27178
27494
|
}
|
|
27179
27495
|
return agents;
|
|
27180
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
|
+
}
|
|
27181
27518
|
/**
|
|
27182
27519
|
* Resolve {{> partial-name }} includes in template content.
|
|
27183
27520
|
* Loads partials from templates/subagents/.
|
|
@@ -27189,7 +27526,7 @@ var init_sync_service = __esm({
|
|
|
27189
27526
|
let resolved = content;
|
|
27190
27527
|
for (const match of matches) {
|
|
27191
27528
|
const partialName = match[1];
|
|
27192
|
-
const partialPath =
|
|
27529
|
+
const partialPath = path58.join(
|
|
27193
27530
|
__dirname,
|
|
27194
27531
|
"..",
|
|
27195
27532
|
"..",
|
|
@@ -27198,7 +27535,7 @@ var init_sync_service = __esm({
|
|
|
27198
27535
|
`${partialName}.md`
|
|
27199
27536
|
);
|
|
27200
27537
|
try {
|
|
27201
|
-
const partialContent = await
|
|
27538
|
+
const partialContent = await fs55.readFile(partialPath, "utf-8");
|
|
27202
27539
|
resolved = resolved.replace(match[0], partialContent.trim());
|
|
27203
27540
|
} catch {
|
|
27204
27541
|
resolved = resolved.replace(match[0], `<!-- partial "${partialName}" not found -->`);
|
|
@@ -27209,7 +27546,7 @@ var init_sync_service = __esm({
|
|
|
27209
27546
|
async generateWorkflowAgent(name, agentsPath) {
|
|
27210
27547
|
let content = "";
|
|
27211
27548
|
try {
|
|
27212
|
-
const templatePath =
|
|
27549
|
+
const templatePath = path58.join(
|
|
27213
27550
|
__dirname,
|
|
27214
27551
|
"..",
|
|
27215
27552
|
"..",
|
|
@@ -27218,7 +27555,7 @@ var init_sync_service = __esm({
|
|
|
27218
27555
|
"workflow",
|
|
27219
27556
|
`${name}.md`
|
|
27220
27557
|
);
|
|
27221
|
-
content = await
|
|
27558
|
+
content = await fs55.readFile(templatePath, "utf-8");
|
|
27222
27559
|
content = await this.resolveTemplateIncludes(content);
|
|
27223
27560
|
} catch (error) {
|
|
27224
27561
|
logger_default.debug("Workflow agent template not found, generating minimal", {
|
|
@@ -27227,12 +27564,12 @@ var init_sync_service = __esm({
|
|
|
27227
27564
|
});
|
|
27228
27565
|
content = this.generateMinimalWorkflowAgent(name);
|
|
27229
27566
|
}
|
|
27230
|
-
await
|
|
27567
|
+
await fs55.writeFile(path58.join(agentsPath, `${name}.md`), content, "utf-8");
|
|
27231
27568
|
}
|
|
27232
27569
|
async generateDomainAgent(name, agentsPath, stats, stack) {
|
|
27233
27570
|
let content = "";
|
|
27234
27571
|
try {
|
|
27235
|
-
const templatePath =
|
|
27572
|
+
const templatePath = path58.join(
|
|
27236
27573
|
__dirname,
|
|
27237
27574
|
"..",
|
|
27238
27575
|
"..",
|
|
@@ -27241,7 +27578,7 @@ var init_sync_service = __esm({
|
|
|
27241
27578
|
"domain",
|
|
27242
27579
|
`${name}.md`
|
|
27243
27580
|
);
|
|
27244
|
-
content = await
|
|
27581
|
+
content = await fs55.readFile(templatePath, "utf-8");
|
|
27245
27582
|
content = await this.resolveTemplateIncludes(content);
|
|
27246
27583
|
content = content.replace("{projectName}", stats.name);
|
|
27247
27584
|
content = content.replace("{frameworks}", stack.frameworks.join(", ") || "None detected");
|
|
@@ -27253,7 +27590,7 @@ var init_sync_service = __esm({
|
|
|
27253
27590
|
});
|
|
27254
27591
|
content = this.generateMinimalDomainAgent(name, stats, stack);
|
|
27255
27592
|
}
|
|
27256
|
-
await
|
|
27593
|
+
await fs55.writeFile(path58.join(agentsPath, `${name}.md`), content, "utf-8");
|
|
27257
27594
|
}
|
|
27258
27595
|
generateMinimalWorkflowAgent(name) {
|
|
27259
27596
|
const descriptions = {
|
|
@@ -27321,8 +27658,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
27321
27658
|
})),
|
|
27322
27659
|
agentSkillMap: Object.fromEntries(skills.map((s) => [s.agent, s.skill]))
|
|
27323
27660
|
};
|
|
27324
|
-
|
|
27325
|
-
|
|
27661
|
+
fs55.writeFile(
|
|
27662
|
+
path58.join(this.globalPath, "config", "skills.json"),
|
|
27326
27663
|
JSON.stringify(skillsConfig, null, 2),
|
|
27327
27664
|
"utf-8"
|
|
27328
27665
|
).catch((error) => {
|
|
@@ -27340,7 +27677,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
27340
27677
|
async autoInstallSkills(agents) {
|
|
27341
27678
|
const results = [];
|
|
27342
27679
|
try {
|
|
27343
|
-
const mappingsPath =
|
|
27680
|
+
const mappingsPath = path58.join(
|
|
27344
27681
|
__dirname,
|
|
27345
27682
|
"..",
|
|
27346
27683
|
"..",
|
|
@@ -27348,7 +27685,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
27348
27685
|
"config",
|
|
27349
27686
|
"skill-mappings.json"
|
|
27350
27687
|
);
|
|
27351
|
-
const mappingsContent = await
|
|
27688
|
+
const mappingsContent = await fs55.readFile(mappingsPath, "utf-8");
|
|
27352
27689
|
const mappings = JSON.parse(mappingsContent);
|
|
27353
27690
|
const agentToSkillMap = mappings.agentToSkillMap || {};
|
|
27354
27691
|
const packagesToInstall = [];
|
|
@@ -27361,18 +27698,18 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
27361
27698
|
}
|
|
27362
27699
|
}
|
|
27363
27700
|
if (packagesToInstall.length === 0) return results;
|
|
27364
|
-
const skillsDir =
|
|
27701
|
+
const skillsDir = path58.join(os16.homedir(), ".claude", "skills");
|
|
27365
27702
|
for (const { pkg, agent } of packagesToInstall) {
|
|
27366
27703
|
const skillName = pkg.split("/").pop() || pkg;
|
|
27367
|
-
const subdirPath =
|
|
27368
|
-
const flatPath =
|
|
27704
|
+
const subdirPath = path58.join(skillsDir, skillName, "SKILL.md");
|
|
27705
|
+
const flatPath = path58.join(skillsDir, `${skillName}.md`);
|
|
27369
27706
|
let alreadyInstalled = false;
|
|
27370
27707
|
try {
|
|
27371
|
-
await
|
|
27708
|
+
await fs55.access(subdirPath);
|
|
27372
27709
|
alreadyInstalled = true;
|
|
27373
27710
|
} catch {
|
|
27374
27711
|
try {
|
|
27375
|
-
await
|
|
27712
|
+
await fs55.access(flatPath);
|
|
27376
27713
|
alreadyInstalled = true;
|
|
27377
27714
|
} catch {
|
|
27378
27715
|
}
|
|
@@ -27424,10 +27761,10 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
27424
27761
|
// PROJECT.JSON UPDATE
|
|
27425
27762
|
// ==========================================================================
|
|
27426
27763
|
async updateProjectJson(git, stats) {
|
|
27427
|
-
const projectJsonPath =
|
|
27764
|
+
const projectJsonPath = path58.join(this.globalPath, "project.json");
|
|
27428
27765
|
let existing = {};
|
|
27429
27766
|
try {
|
|
27430
|
-
existing = JSON.parse(await
|
|
27767
|
+
existing = JSON.parse(await fs55.readFile(projectJsonPath, "utf-8"));
|
|
27431
27768
|
} catch (error) {
|
|
27432
27769
|
logger_default.debug("No existing project.json", {
|
|
27433
27770
|
path: projectJsonPath,
|
|
@@ -27453,16 +27790,16 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
27453
27790
|
lastSyncCommit: git.recentCommits[0]?.hash || null,
|
|
27454
27791
|
lastSyncBranch: git.branch
|
|
27455
27792
|
};
|
|
27456
|
-
await
|
|
27793
|
+
await fs55.writeFile(projectJsonPath, JSON.stringify(updated, null, 2), "utf-8");
|
|
27457
27794
|
}
|
|
27458
27795
|
// ==========================================================================
|
|
27459
27796
|
// STATE.JSON UPDATE
|
|
27460
27797
|
// ==========================================================================
|
|
27461
27798
|
async updateStateJson(stats, stack) {
|
|
27462
|
-
const statePath =
|
|
27799
|
+
const statePath = path58.join(this.globalPath, "storage", "state.json");
|
|
27463
27800
|
let state = {};
|
|
27464
27801
|
try {
|
|
27465
|
-
state = JSON.parse(await
|
|
27802
|
+
state = JSON.parse(await fs55.readFile(statePath, "utf-8"));
|
|
27466
27803
|
} catch (error) {
|
|
27467
27804
|
logger_default.debug("No existing state.json", { path: statePath, error: getErrorMessage(error) });
|
|
27468
27805
|
}
|
|
@@ -27490,7 +27827,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
27490
27827
|
lastAction: "Synced project",
|
|
27491
27828
|
nextAction: 'Run `p. task "description"` to start working'
|
|
27492
27829
|
};
|
|
27493
|
-
await
|
|
27830
|
+
await fs55.writeFile(statePath, JSON.stringify(state, null, 2), "utf-8");
|
|
27494
27831
|
try {
|
|
27495
27832
|
await localStateGenerator.generate(
|
|
27496
27833
|
this.projectPath,
|
|
@@ -27504,7 +27841,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
27504
27841
|
// MEMORY LOGGING
|
|
27505
27842
|
// ==========================================================================
|
|
27506
27843
|
async logToMemory(git, stats) {
|
|
27507
|
-
const memoryPath =
|
|
27844
|
+
const memoryPath = path58.join(this.globalPath, "memory", "events.jsonl");
|
|
27508
27845
|
const event = {
|
|
27509
27846
|
ts: getTimestamp(),
|
|
27510
27847
|
action: "sync",
|
|
@@ -27513,7 +27850,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
27513
27850
|
fileCount: stats.fileCount,
|
|
27514
27851
|
commitCount: git.commits
|
|
27515
27852
|
};
|
|
27516
|
-
await
|
|
27853
|
+
await fs55.appendFile(memoryPath, `${JSON.stringify(event)}
|
|
27517
27854
|
`, "utf-8");
|
|
27518
27855
|
}
|
|
27519
27856
|
// ==========================================================================
|
|
@@ -27533,8 +27870,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
27533
27870
|
let filteredChars = 0;
|
|
27534
27871
|
for (const file of contextFiles) {
|
|
27535
27872
|
try {
|
|
27536
|
-
const filePath =
|
|
27537
|
-
const content = await
|
|
27873
|
+
const filePath = path58.join(this.globalPath, file);
|
|
27874
|
+
const content = await fs55.readFile(filePath, "utf-8");
|
|
27538
27875
|
filteredChars += content.length;
|
|
27539
27876
|
} catch (error) {
|
|
27540
27877
|
logger_default.debug("Context file not found for metrics", { file, error: getErrorMessage(error) });
|
|
@@ -27542,8 +27879,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
27542
27879
|
}
|
|
27543
27880
|
for (const agent of agents) {
|
|
27544
27881
|
try {
|
|
27545
|
-
const agentPath =
|
|
27546
|
-
const content = await
|
|
27882
|
+
const agentPath = path58.join(this.globalPath, "agents", `${agent.name}.md`);
|
|
27883
|
+
const content = await fs55.readFile(agentPath, "utf-8");
|
|
27547
27884
|
filteredChars += content.length;
|
|
27548
27885
|
} catch (error) {
|
|
27549
27886
|
logger_default.debug("Agent file not found for metrics", {
|
|
@@ -27605,7 +27942,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
27605
27942
|
// ==========================================================================
|
|
27606
27943
|
async fileExists(filename) {
|
|
27607
27944
|
try {
|
|
27608
|
-
await
|
|
27945
|
+
await fs55.access(path58.join(this.projectPath, filename));
|
|
27609
27946
|
return true;
|
|
27610
27947
|
} catch (error) {
|
|
27611
27948
|
logger_default.debug("File not found", { filename, error: getErrorMessage(error) });
|
|
@@ -27614,8 +27951,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
27614
27951
|
}
|
|
27615
27952
|
async getCliVersion() {
|
|
27616
27953
|
try {
|
|
27617
|
-
const pkgPath =
|
|
27618
|
-
const pkg = JSON.parse(await
|
|
27954
|
+
const pkgPath = path58.join(__dirname, "..", "..", "package.json");
|
|
27955
|
+
const pkg = JSON.parse(await fs55.readFile(pkgPath, "utf-8"));
|
|
27619
27956
|
return pkg.version || "0.0.0";
|
|
27620
27957
|
} catch (error) {
|
|
27621
27958
|
logger_default.debug("Failed to read CLI version", { error: getErrorMessage(error) });
|
|
@@ -27776,22 +28113,22 @@ __export(uninstall_exports, {
|
|
|
27776
28113
|
uninstall: () => uninstall
|
|
27777
28114
|
});
|
|
27778
28115
|
import { execSync as execSync3 } from "node:child_process";
|
|
27779
|
-
import
|
|
28116
|
+
import fs56 from "node:fs/promises";
|
|
27780
28117
|
import os17 from "node:os";
|
|
27781
|
-
import
|
|
28118
|
+
import path59 from "node:path";
|
|
27782
28119
|
import readline2 from "node:readline";
|
|
27783
28120
|
import chalk12 from "chalk";
|
|
27784
28121
|
async function getDirectorySize(dirPath) {
|
|
27785
28122
|
let totalSize = 0;
|
|
27786
28123
|
try {
|
|
27787
|
-
const entries = await
|
|
28124
|
+
const entries = await fs56.readdir(dirPath, { withFileTypes: true });
|
|
27788
28125
|
for (const entry of entries) {
|
|
27789
|
-
const entryPath =
|
|
28126
|
+
const entryPath = path59.join(dirPath, entry.name);
|
|
27790
28127
|
if (entry.isDirectory()) {
|
|
27791
28128
|
totalSize += await getDirectorySize(entryPath);
|
|
27792
28129
|
} else {
|
|
27793
28130
|
try {
|
|
27794
|
-
const stats = await
|
|
28131
|
+
const stats = await fs56.stat(entryPath);
|
|
27795
28132
|
totalSize += stats.size;
|
|
27796
28133
|
} catch {
|
|
27797
28134
|
}
|
|
@@ -27810,7 +28147,7 @@ function formatSize(bytes) {
|
|
|
27810
28147
|
}
|
|
27811
28148
|
async function countDirectoryItems(dirPath) {
|
|
27812
28149
|
try {
|
|
27813
|
-
const entries = await
|
|
28150
|
+
const entries = await fs56.readdir(dirPath, { withFileTypes: true });
|
|
27814
28151
|
return entries.filter((e) => e.isDirectory()).length;
|
|
27815
28152
|
} catch {
|
|
27816
28153
|
return 0;
|
|
@@ -27843,7 +28180,7 @@ async function gatherUninstallItems() {
|
|
|
27843
28180
|
const providerPaths = getProviderPaths();
|
|
27844
28181
|
const prjctCliPath = path_manager_default.getGlobalBasePath();
|
|
27845
28182
|
const prjctCliExists = await fileExists(prjctCliPath);
|
|
27846
|
-
const projectCount = prjctCliExists ? await countDirectoryItems(
|
|
28183
|
+
const projectCount = prjctCliExists ? await countDirectoryItems(path59.join(prjctCliPath, "projects")) : 0;
|
|
27847
28184
|
const prjctCliSize = prjctCliExists ? await getDirectorySize(prjctCliPath) : 0;
|
|
27848
28185
|
items.push({
|
|
27849
28186
|
path: prjctCliPath,
|
|
@@ -27853,12 +28190,12 @@ async function gatherUninstallItems() {
|
|
|
27853
28190
|
count: projectCount,
|
|
27854
28191
|
exists: prjctCliExists
|
|
27855
28192
|
});
|
|
27856
|
-
const claudeMdPath =
|
|
28193
|
+
const claudeMdPath = path59.join(providerPaths.claude.config, "CLAUDE.md");
|
|
27857
28194
|
const claudeMdExists = await fileExists(claudeMdPath);
|
|
27858
28195
|
let hasPrjctSection = false;
|
|
27859
28196
|
if (claudeMdExists) {
|
|
27860
28197
|
try {
|
|
27861
|
-
const content = await
|
|
28198
|
+
const content = await fs56.readFile(claudeMdPath, "utf-8");
|
|
27862
28199
|
hasPrjctSection = content.includes(PRJCT_START_MARKER) && content.includes(PRJCT_END_MARKER);
|
|
27863
28200
|
} catch {
|
|
27864
28201
|
}
|
|
@@ -27887,7 +28224,7 @@ async function gatherUninstallItems() {
|
|
|
27887
28224
|
description: "Claude router",
|
|
27888
28225
|
exists: claudeRouterExists
|
|
27889
28226
|
});
|
|
27890
|
-
const statusLinePath =
|
|
28227
|
+
const statusLinePath = path59.join(providerPaths.claude.config, "prjct-statusline.sh");
|
|
27891
28228
|
const statusLineExists = await fileExists(statusLinePath);
|
|
27892
28229
|
items.push({
|
|
27893
28230
|
path: statusLinePath,
|
|
@@ -27903,12 +28240,12 @@ async function gatherUninstallItems() {
|
|
|
27903
28240
|
description: "Gemini router",
|
|
27904
28241
|
exists: geminiRouterExists
|
|
27905
28242
|
});
|
|
27906
|
-
const geminiMdPath =
|
|
28243
|
+
const geminiMdPath = path59.join(providerPaths.gemini.config, "GEMINI.md");
|
|
27907
28244
|
const geminiMdExists = await fileExists(geminiMdPath);
|
|
27908
28245
|
let hasGeminiPrjctSection = false;
|
|
27909
28246
|
if (geminiMdExists) {
|
|
27910
28247
|
try {
|
|
27911
|
-
const content = await
|
|
28248
|
+
const content = await fs56.readFile(geminiMdPath, "utf-8");
|
|
27912
28249
|
hasGeminiPrjctSection = content.includes(PRJCT_START_MARKER) && content.includes(PRJCT_END_MARKER);
|
|
27913
28250
|
} catch {
|
|
27914
28251
|
}
|
|
@@ -27925,7 +28262,7 @@ async function gatherUninstallItems() {
|
|
|
27925
28262
|
}
|
|
27926
28263
|
async function removePrjctSection(filePath) {
|
|
27927
28264
|
try {
|
|
27928
|
-
const content = await
|
|
28265
|
+
const content = await fs56.readFile(filePath, "utf-8");
|
|
27929
28266
|
if (!content.includes(PRJCT_START_MARKER) || !content.includes(PRJCT_END_MARKER)) {
|
|
27930
28267
|
return false;
|
|
27931
28268
|
}
|
|
@@ -27934,9 +28271,9 @@ async function removePrjctSection(filePath) {
|
|
|
27934
28271
|
let newContent = content.substring(0, startIndex) + content.substring(endIndex);
|
|
27935
28272
|
newContent = newContent.replace(/\n{3,}/g, "\n\n").trim();
|
|
27936
28273
|
if (!newContent || newContent.trim().length === 0) {
|
|
27937
|
-
await
|
|
28274
|
+
await fs56.unlink(filePath);
|
|
27938
28275
|
} else {
|
|
27939
|
-
await
|
|
28276
|
+
await fs56.writeFile(filePath, `${newContent}
|
|
27940
28277
|
`, "utf-8");
|
|
27941
28278
|
}
|
|
27942
28279
|
return true;
|
|
@@ -27947,12 +28284,12 @@ async function removePrjctSection(filePath) {
|
|
|
27947
28284
|
async function createBackup3() {
|
|
27948
28285
|
const homeDir = os17.homedir();
|
|
27949
28286
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").substring(0, 19);
|
|
27950
|
-
const backupDir =
|
|
28287
|
+
const backupDir = path59.join(homeDir, `.prjct-backup-${timestamp}`);
|
|
27951
28288
|
try {
|
|
27952
|
-
await
|
|
28289
|
+
await fs56.mkdir(backupDir, { recursive: true });
|
|
27953
28290
|
const prjctCliPath = path_manager_default.getGlobalBasePath();
|
|
27954
28291
|
if (await fileExists(prjctCliPath)) {
|
|
27955
|
-
await copyDirectory(prjctCliPath,
|
|
28292
|
+
await copyDirectory(prjctCliPath, path59.join(backupDir, ".prjct-cli"));
|
|
27956
28293
|
}
|
|
27957
28294
|
return backupDir;
|
|
27958
28295
|
} catch {
|
|
@@ -27960,15 +28297,15 @@ async function createBackup3() {
|
|
|
27960
28297
|
}
|
|
27961
28298
|
}
|
|
27962
28299
|
async function copyDirectory(src, dest) {
|
|
27963
|
-
await
|
|
27964
|
-
const entries = await
|
|
28300
|
+
await fs56.mkdir(dest, { recursive: true });
|
|
28301
|
+
const entries = await fs56.readdir(src, { withFileTypes: true });
|
|
27965
28302
|
for (const entry of entries) {
|
|
27966
|
-
const srcPath =
|
|
27967
|
-
const destPath =
|
|
28303
|
+
const srcPath = path59.join(src, entry.name);
|
|
28304
|
+
const destPath = path59.join(dest, entry.name);
|
|
27968
28305
|
if (entry.isDirectory()) {
|
|
27969
28306
|
await copyDirectory(srcPath, destPath);
|
|
27970
28307
|
} else {
|
|
27971
|
-
await
|
|
28308
|
+
await fs56.copyFile(srcPath, destPath);
|
|
27972
28309
|
}
|
|
27973
28310
|
}
|
|
27974
28311
|
}
|
|
@@ -27984,10 +28321,10 @@ async function performUninstall(items, installation, options) {
|
|
|
27984
28321
|
deleted.push(item.path);
|
|
27985
28322
|
}
|
|
27986
28323
|
} else if (item.type === "directory") {
|
|
27987
|
-
await
|
|
28324
|
+
await fs56.rm(item.path, { recursive: true, force: true });
|
|
27988
28325
|
deleted.push(item.path);
|
|
27989
28326
|
} else if (item.type === "file") {
|
|
27990
|
-
await
|
|
28327
|
+
await fs56.unlink(item.path);
|
|
27991
28328
|
deleted.push(item.path);
|
|
27992
28329
|
}
|
|
27993
28330
|
} catch (error) {
|
|
@@ -28164,7 +28501,7 @@ __export(watch_service_exports, {
|
|
|
28164
28501
|
WatchService: () => WatchService,
|
|
28165
28502
|
watchService: () => watchService
|
|
28166
28503
|
});
|
|
28167
|
-
import
|
|
28504
|
+
import path60 from "node:path";
|
|
28168
28505
|
import chalk13 from "chalk";
|
|
28169
28506
|
import chokidar from "chokidar";
|
|
28170
28507
|
var TRIGGER_PATTERNS, IGNORE_PATTERNS2, WatchService, watchService;
|
|
@@ -28353,7 +28690,7 @@ ${chalk13.dim(`[${timestamp}]`)} ${chalk13.cyan("\u27F3")} ${filesSummary} chang
|
|
|
28353
28690
|
);
|
|
28354
28691
|
}
|
|
28355
28692
|
try {
|
|
28356
|
-
const result = await syncService.sync(this.projectPath);
|
|
28693
|
+
const result = await syncService.sync(this.projectPath, { changedFiles });
|
|
28357
28694
|
this.lastSyncTime = Date.now();
|
|
28358
28695
|
this.syncCount++;
|
|
28359
28696
|
if (result.success) {
|
|
@@ -28385,7 +28722,7 @@ ${chalk13.dim(`[${timestamp}]`)} ${chalk13.cyan("\u27F3")} ${filesSummary} chang
|
|
|
28385
28722
|
printStartup() {
|
|
28386
28723
|
console.log("");
|
|
28387
28724
|
console.log(chalk13.cyan("\u{1F441}\uFE0F Watching for changes..."));
|
|
28388
|
-
console.log(chalk13.dim(` Project: ${
|
|
28725
|
+
console.log(chalk13.dim(` Project: ${path60.basename(this.projectPath)}`));
|
|
28389
28726
|
console.log(chalk13.dim(` Debounce: ${this.options.debounceMs}ms`));
|
|
28390
28727
|
console.log(chalk13.dim(` Min interval: ${this.options.minIntervalMs / 1e3}s`));
|
|
28391
28728
|
console.log("");
|
|
@@ -28558,11 +28895,13 @@ var init_command_data = __esm({
|
|
|
28558
28895
|
name: "sync",
|
|
28559
28896
|
group: "core",
|
|
28560
28897
|
description: "Sync project state and update workflow agents",
|
|
28561
|
-
usage: { claude: "/p:sync", terminal: "prjct sync [--package=<name>]" },
|
|
28898
|
+
usage: { claude: "/p:sync", terminal: "prjct sync [--package=<name>] [--full]" },
|
|
28562
28899
|
implemented: true,
|
|
28563
28900
|
hasTemplate: true,
|
|
28564
28901
|
requiresProject: true,
|
|
28565
28902
|
features: [
|
|
28903
|
+
"Incremental sync: only re-analyzes changed files (default)",
|
|
28904
|
+
"Force full sync: --full bypasses incremental cache",
|
|
28566
28905
|
"Monorepo support: --package=<name> for single package sync",
|
|
28567
28906
|
"Nested PRJCT.md inheritance",
|
|
28568
28907
|
"Per-package CLAUDE.md generation"
|
|
@@ -29116,9 +29455,9 @@ __export(setup_exports, {
|
|
|
29116
29455
|
run: () => run
|
|
29117
29456
|
});
|
|
29118
29457
|
import { execSync as execSync4 } from "node:child_process";
|
|
29119
|
-
import
|
|
29458
|
+
import fs57 from "node:fs/promises";
|
|
29120
29459
|
import os18 from "node:os";
|
|
29121
|
-
import
|
|
29460
|
+
import path61 from "node:path";
|
|
29122
29461
|
import chalk15 from "chalk";
|
|
29123
29462
|
async function installAICLI(provider) {
|
|
29124
29463
|
const packageName = provider.name === "claude" ? "@anthropic-ai/claude-code" : "@google/gemini-cli";
|
|
@@ -29257,12 +29596,12 @@ async function run() {
|
|
|
29257
29596
|
}
|
|
29258
29597
|
async function installGeminiRouter() {
|
|
29259
29598
|
try {
|
|
29260
|
-
const geminiCommandsDir =
|
|
29261
|
-
const routerSource =
|
|
29262
|
-
const routerDest =
|
|
29263
|
-
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 });
|
|
29264
29603
|
if (await fileExists(routerSource)) {
|
|
29265
|
-
await
|
|
29604
|
+
await fs57.copyFile(routerSource, routerDest);
|
|
29266
29605
|
return true;
|
|
29267
29606
|
}
|
|
29268
29607
|
return false;
|
|
@@ -29273,15 +29612,15 @@ async function installGeminiRouter() {
|
|
|
29273
29612
|
}
|
|
29274
29613
|
async function installGeminiGlobalConfig() {
|
|
29275
29614
|
try {
|
|
29276
|
-
const geminiDir =
|
|
29277
|
-
const globalConfigPath =
|
|
29278
|
-
const templatePath =
|
|
29279
|
-
await
|
|
29280
|
-
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");
|
|
29281
29620
|
let existingContent = "";
|
|
29282
29621
|
let configExists = false;
|
|
29283
29622
|
try {
|
|
29284
|
-
existingContent = await
|
|
29623
|
+
existingContent = await fs57.readFile(globalConfigPath, "utf-8");
|
|
29285
29624
|
configExists = true;
|
|
29286
29625
|
} catch (error) {
|
|
29287
29626
|
if (isNotFoundError(error)) {
|
|
@@ -29291,7 +29630,7 @@ async function installGeminiGlobalConfig() {
|
|
|
29291
29630
|
}
|
|
29292
29631
|
}
|
|
29293
29632
|
if (!configExists) {
|
|
29294
|
-
await
|
|
29633
|
+
await fs57.writeFile(globalConfigPath, templateContent, "utf-8");
|
|
29295
29634
|
return { success: true, action: "created" };
|
|
29296
29635
|
}
|
|
29297
29636
|
const startMarker = "<!-- prjct:start - DO NOT REMOVE THIS MARKER -->";
|
|
@@ -29301,7 +29640,7 @@ async function installGeminiGlobalConfig() {
|
|
|
29301
29640
|
const updatedContent2 = `${existingContent}
|
|
29302
29641
|
|
|
29303
29642
|
${templateContent}`;
|
|
29304
|
-
await
|
|
29643
|
+
await fs57.writeFile(globalConfigPath, updatedContent2, "utf-8");
|
|
29305
29644
|
return { success: true, action: "appended" };
|
|
29306
29645
|
}
|
|
29307
29646
|
const beforeMarker = existingContent.substring(0, existingContent.indexOf(startMarker));
|
|
@@ -29313,7 +29652,7 @@ ${templateContent}`;
|
|
|
29313
29652
|
templateContent.indexOf(endMarker) + endMarker.length
|
|
29314
29653
|
);
|
|
29315
29654
|
const updatedContent = beforeMarker + prjctSection + afterMarker;
|
|
29316
|
-
await
|
|
29655
|
+
await fs57.writeFile(globalConfigPath, updatedContent, "utf-8");
|
|
29317
29656
|
return { success: true, action: "updated" };
|
|
29318
29657
|
} catch (error) {
|
|
29319
29658
|
logger_default.warn(`Gemini config warning: ${getErrorMessage2(error)}`);
|
|
@@ -29322,18 +29661,18 @@ ${templateContent}`;
|
|
|
29322
29661
|
}
|
|
29323
29662
|
async function installAntigravitySkill() {
|
|
29324
29663
|
try {
|
|
29325
|
-
const antigravitySkillsDir =
|
|
29326
|
-
const prjctSkillDir =
|
|
29327
|
-
const skillMdPath =
|
|
29328
|
-
const templatePath =
|
|
29329
|
-
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 });
|
|
29330
29669
|
const skillExists = await fileExists(skillMdPath);
|
|
29331
29670
|
if (!await fileExists(templatePath)) {
|
|
29332
29671
|
logger_default.warn("Antigravity SKILL.md template not found");
|
|
29333
29672
|
return { success: false, action: null };
|
|
29334
29673
|
}
|
|
29335
|
-
const templateContent = await
|
|
29336
|
-
await
|
|
29674
|
+
const templateContent = await fs57.readFile(templatePath, "utf-8");
|
|
29675
|
+
await fs57.writeFile(skillMdPath, templateContent, "utf-8");
|
|
29337
29676
|
return { success: true, action: skillExists ? "updated" : "created" };
|
|
29338
29677
|
} catch (error) {
|
|
29339
29678
|
logger_default.warn(`Antigravity skill warning: ${getErrorMessage2(error)}`);
|
|
@@ -29352,24 +29691,24 @@ async function installCursorProject(projectRoot) {
|
|
|
29352
29691
|
gitignoreUpdated: false
|
|
29353
29692
|
};
|
|
29354
29693
|
try {
|
|
29355
|
-
const cursorDir =
|
|
29356
|
-
const rulesDir =
|
|
29357
|
-
const commandsDir =
|
|
29358
|
-
const routerMdcDest =
|
|
29359
|
-
const routerMdcSource =
|
|
29360
|
-
const cursorCommandsSource =
|
|
29361
|
-
await
|
|
29362
|
-
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 });
|
|
29363
29702
|
if (await fileExists(routerMdcSource)) {
|
|
29364
|
-
await
|
|
29703
|
+
await fs57.copyFile(routerMdcSource, routerMdcDest);
|
|
29365
29704
|
result.rulesCreated = true;
|
|
29366
29705
|
}
|
|
29367
29706
|
if (await fileExists(cursorCommandsSource)) {
|
|
29368
|
-
const commandFiles = (await
|
|
29707
|
+
const commandFiles = (await fs57.readdir(cursorCommandsSource)).filter((f) => f.endsWith(".md"));
|
|
29369
29708
|
for (const file of commandFiles) {
|
|
29370
|
-
const src =
|
|
29371
|
-
const dest =
|
|
29372
|
-
await
|
|
29709
|
+
const src = path61.join(cursorCommandsSource, file);
|
|
29710
|
+
const dest = path61.join(commandsDir, file);
|
|
29711
|
+
await fs57.copyFile(src, dest);
|
|
29373
29712
|
}
|
|
29374
29713
|
result.commandsCreated = commandFiles.length > 0;
|
|
29375
29714
|
}
|
|
@@ -29383,7 +29722,7 @@ async function installCursorProject(projectRoot) {
|
|
|
29383
29722
|
}
|
|
29384
29723
|
async function addCursorToGitignore(projectRoot) {
|
|
29385
29724
|
try {
|
|
29386
|
-
const gitignorePath =
|
|
29725
|
+
const gitignorePath = path61.join(projectRoot, ".gitignore");
|
|
29387
29726
|
const entriesToAdd = [
|
|
29388
29727
|
"# prjct Cursor routers (regenerated per-developer)",
|
|
29389
29728
|
".cursor/rules/prjct.mdc",
|
|
@@ -29398,7 +29737,7 @@ async function addCursorToGitignore(projectRoot) {
|
|
|
29398
29737
|
let content = "";
|
|
29399
29738
|
let configExists = false;
|
|
29400
29739
|
try {
|
|
29401
|
-
content = await
|
|
29740
|
+
content = await fs57.readFile(gitignorePath, "utf-8");
|
|
29402
29741
|
configExists = true;
|
|
29403
29742
|
} catch (error) {
|
|
29404
29743
|
if (!isNotFoundError(error)) {
|
|
@@ -29413,7 +29752,7 @@ async function addCursorToGitignore(projectRoot) {
|
|
|
29413
29752
|
${entriesToAdd.join("\n")}
|
|
29414
29753
|
` : `${entriesToAdd.join("\n")}
|
|
29415
29754
|
`;
|
|
29416
|
-
await
|
|
29755
|
+
await fs57.writeFile(gitignorePath, newContent, "utf-8");
|
|
29417
29756
|
return true;
|
|
29418
29757
|
} catch (error) {
|
|
29419
29758
|
logger_default.warn(`Gitignore update warning: ${getErrorMessage2(error)}`);
|
|
@@ -29421,11 +29760,11 @@ ${entriesToAdd.join("\n")}
|
|
|
29421
29760
|
}
|
|
29422
29761
|
}
|
|
29423
29762
|
async function hasCursorProject(projectRoot) {
|
|
29424
|
-
return await fileExists(
|
|
29763
|
+
return await fileExists(path61.join(projectRoot, ".cursor"));
|
|
29425
29764
|
}
|
|
29426
29765
|
async function needsCursorRegeneration(projectRoot) {
|
|
29427
|
-
const cursorDir =
|
|
29428
|
-
const routerPath =
|
|
29766
|
+
const cursorDir = path61.join(projectRoot, ".cursor");
|
|
29767
|
+
const routerPath = path61.join(cursorDir, "rules", "prjct.mdc");
|
|
29429
29768
|
return await fileExists(cursorDir) && !await fileExists(routerPath);
|
|
29430
29769
|
}
|
|
29431
29770
|
async function installWindsurfProject(projectRoot) {
|
|
@@ -29436,26 +29775,26 @@ async function installWindsurfProject(projectRoot) {
|
|
|
29436
29775
|
gitignoreUpdated: false
|
|
29437
29776
|
};
|
|
29438
29777
|
try {
|
|
29439
|
-
const windsurfDir =
|
|
29440
|
-
const rulesDir =
|
|
29441
|
-
const workflowsDir =
|
|
29442
|
-
const routerDest =
|
|
29443
|
-
const routerSource =
|
|
29444
|
-
const windsurfWorkflowsSource =
|
|
29445
|
-
await
|
|
29446
|
-
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 });
|
|
29447
29786
|
if (await fileExists(routerSource)) {
|
|
29448
|
-
await
|
|
29787
|
+
await fs57.copyFile(routerSource, routerDest);
|
|
29449
29788
|
result.rulesCreated = true;
|
|
29450
29789
|
}
|
|
29451
29790
|
if (await fileExists(windsurfWorkflowsSource)) {
|
|
29452
|
-
const workflowFiles = (await
|
|
29791
|
+
const workflowFiles = (await fs57.readdir(windsurfWorkflowsSource)).filter(
|
|
29453
29792
|
(f) => f.endsWith(".md")
|
|
29454
29793
|
);
|
|
29455
29794
|
for (const file of workflowFiles) {
|
|
29456
|
-
const src =
|
|
29457
|
-
const dest =
|
|
29458
|
-
await
|
|
29795
|
+
const src = path61.join(windsurfWorkflowsSource, file);
|
|
29796
|
+
const dest = path61.join(workflowsDir, file);
|
|
29797
|
+
await fs57.copyFile(src, dest);
|
|
29459
29798
|
}
|
|
29460
29799
|
result.workflowsCreated = workflowFiles.length > 0;
|
|
29461
29800
|
}
|
|
@@ -29469,7 +29808,7 @@ async function installWindsurfProject(projectRoot) {
|
|
|
29469
29808
|
}
|
|
29470
29809
|
async function addWindsurfToGitignore(projectRoot) {
|
|
29471
29810
|
try {
|
|
29472
|
-
const gitignorePath =
|
|
29811
|
+
const gitignorePath = path61.join(projectRoot, ".gitignore");
|
|
29473
29812
|
const entriesToAdd = [
|
|
29474
29813
|
"# prjct Windsurf routers (regenerated per-developer)",
|
|
29475
29814
|
".windsurf/rules/prjct.md",
|
|
@@ -29484,7 +29823,7 @@ async function addWindsurfToGitignore(projectRoot) {
|
|
|
29484
29823
|
let content = "";
|
|
29485
29824
|
let configExists = false;
|
|
29486
29825
|
try {
|
|
29487
|
-
content = await
|
|
29826
|
+
content = await fs57.readFile(gitignorePath, "utf-8");
|
|
29488
29827
|
configExists = true;
|
|
29489
29828
|
} catch (error) {
|
|
29490
29829
|
if (!isNotFoundError(error)) {
|
|
@@ -29499,7 +29838,7 @@ async function addWindsurfToGitignore(projectRoot) {
|
|
|
29499
29838
|
${entriesToAdd.join("\n")}
|
|
29500
29839
|
` : `${entriesToAdd.join("\n")}
|
|
29501
29840
|
`;
|
|
29502
|
-
await
|
|
29841
|
+
await fs57.writeFile(gitignorePath, newContent, "utf-8");
|
|
29503
29842
|
return true;
|
|
29504
29843
|
} catch (error) {
|
|
29505
29844
|
logger_default.warn(`Gitignore update warning: ${getErrorMessage2(error)}`);
|
|
@@ -29507,32 +29846,32 @@ ${entriesToAdd.join("\n")}
|
|
|
29507
29846
|
}
|
|
29508
29847
|
}
|
|
29509
29848
|
async function hasWindsurfProject(projectRoot) {
|
|
29510
|
-
return await fileExists(
|
|
29849
|
+
return await fileExists(path61.join(projectRoot, ".windsurf"));
|
|
29511
29850
|
}
|
|
29512
29851
|
async function needsWindsurfRegeneration(projectRoot) {
|
|
29513
|
-
const windsurfDir =
|
|
29514
|
-
const routerPath =
|
|
29852
|
+
const windsurfDir = path61.join(projectRoot, ".windsurf");
|
|
29853
|
+
const routerPath = path61.join(windsurfDir, "rules", "prjct.md");
|
|
29515
29854
|
return await fileExists(windsurfDir) && !await fileExists(routerPath);
|
|
29516
29855
|
}
|
|
29517
29856
|
async function migrateProjectsCliVersion() {
|
|
29518
29857
|
try {
|
|
29519
|
-
const projectsDir =
|
|
29858
|
+
const projectsDir = path61.join(os18.homedir(), ".prjct-cli", "projects");
|
|
29520
29859
|
if (!await fileExists(projectsDir)) {
|
|
29521
29860
|
return;
|
|
29522
29861
|
}
|
|
29523
|
-
const projectDirs = (await
|
|
29862
|
+
const projectDirs = (await fs57.readdir(projectsDir, { withFileTypes: true })).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
29524
29863
|
let migrated = 0;
|
|
29525
29864
|
for (const projectId of projectDirs) {
|
|
29526
|
-
const projectJsonPath =
|
|
29865
|
+
const projectJsonPath = path61.join(projectsDir, projectId, "project.json");
|
|
29527
29866
|
if (!await fileExists(projectJsonPath)) {
|
|
29528
29867
|
continue;
|
|
29529
29868
|
}
|
|
29530
29869
|
try {
|
|
29531
|
-
const content = await
|
|
29870
|
+
const content = await fs57.readFile(projectJsonPath, "utf8");
|
|
29532
29871
|
const project = JSON.parse(content);
|
|
29533
29872
|
if (project.cliVersion !== VERSION) {
|
|
29534
29873
|
project.cliVersion = VERSION;
|
|
29535
|
-
await
|
|
29874
|
+
await fs57.writeFile(projectJsonPath, JSON.stringify(project, null, 2));
|
|
29536
29875
|
migrated++;
|
|
29537
29876
|
}
|
|
29538
29877
|
} catch (error) {
|
|
@@ -29554,7 +29893,7 @@ async function ensureStatusLineSettings(settingsPath, statusLinePath) {
|
|
|
29554
29893
|
let settings = {};
|
|
29555
29894
|
if (await fileExists(settingsPath)) {
|
|
29556
29895
|
try {
|
|
29557
|
-
settings = JSON.parse(await
|
|
29896
|
+
settings = JSON.parse(await fs57.readFile(settingsPath, "utf8"));
|
|
29558
29897
|
} catch (error) {
|
|
29559
29898
|
if (!(error instanceof SyntaxError)) {
|
|
29560
29899
|
throw error;
|
|
@@ -29562,42 +29901,42 @@ async function ensureStatusLineSettings(settingsPath, statusLinePath) {
|
|
|
29562
29901
|
}
|
|
29563
29902
|
}
|
|
29564
29903
|
settings.statusLine = { type: "command", command: statusLinePath };
|
|
29565
|
-
await
|
|
29904
|
+
await fs57.writeFile(settingsPath, JSON.stringify(settings, null, 2));
|
|
29566
29905
|
}
|
|
29567
29906
|
async function installStatusLine() {
|
|
29568
29907
|
try {
|
|
29569
|
-
const claudeDir =
|
|
29570
|
-
const settingsPath =
|
|
29571
|
-
const claudeStatusLinePath =
|
|
29572
|
-
const prjctStatusLineDir =
|
|
29573
|
-
const prjctStatusLinePath =
|
|
29574
|
-
const prjctThemesDir =
|
|
29575
|
-
const prjctLibDir =
|
|
29576
|
-
const prjctComponentsDir =
|
|
29577
|
-
const prjctConfigPath =
|
|
29578
|
-
const assetsDir =
|
|
29579
|
-
const sourceScript =
|
|
29580
|
-
const sourceThemeDir =
|
|
29581
|
-
const sourceLibDir =
|
|
29582
|
-
const sourceComponentsDir =
|
|
29583
|
-
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");
|
|
29584
29923
|
if (!await fileExists(claudeDir)) {
|
|
29585
|
-
await
|
|
29924
|
+
await fs57.mkdir(claudeDir, { recursive: true });
|
|
29586
29925
|
}
|
|
29587
29926
|
if (!await fileExists(prjctStatusLineDir)) {
|
|
29588
|
-
await
|
|
29927
|
+
await fs57.mkdir(prjctStatusLineDir, { recursive: true });
|
|
29589
29928
|
}
|
|
29590
29929
|
if (!await fileExists(prjctThemesDir)) {
|
|
29591
|
-
await
|
|
29930
|
+
await fs57.mkdir(prjctThemesDir, { recursive: true });
|
|
29592
29931
|
}
|
|
29593
29932
|
if (!await fileExists(prjctLibDir)) {
|
|
29594
|
-
await
|
|
29933
|
+
await fs57.mkdir(prjctLibDir, { recursive: true });
|
|
29595
29934
|
}
|
|
29596
29935
|
if (!await fileExists(prjctComponentsDir)) {
|
|
29597
|
-
await
|
|
29936
|
+
await fs57.mkdir(prjctComponentsDir, { recursive: true });
|
|
29598
29937
|
}
|
|
29599
29938
|
if (await fileExists(prjctStatusLinePath)) {
|
|
29600
|
-
const existingContent = await
|
|
29939
|
+
const existingContent = await fs57.readFile(prjctStatusLinePath, "utf8");
|
|
29601
29940
|
if (existingContent.includes("CLI_VERSION=")) {
|
|
29602
29941
|
const versionMatch = existingContent.match(/CLI_VERSION="([^"]*)"/);
|
|
29603
29942
|
if (versionMatch && versionMatch[1] !== VERSION) {
|
|
@@ -29605,7 +29944,7 @@ async function installStatusLine() {
|
|
|
29605
29944
|
/CLI_VERSION="[^"]*"/,
|
|
29606
29945
|
`CLI_VERSION="${VERSION}"`
|
|
29607
29946
|
);
|
|
29608
|
-
await
|
|
29947
|
+
await fs57.writeFile(prjctStatusLinePath, updatedContent, { mode: 493 });
|
|
29609
29948
|
}
|
|
29610
29949
|
await installStatusLineModules(sourceLibDir, prjctLibDir);
|
|
29611
29950
|
await installStatusLineModules(sourceComponentsDir, prjctComponentsDir);
|
|
@@ -29615,21 +29954,21 @@ async function installStatusLine() {
|
|
|
29615
29954
|
}
|
|
29616
29955
|
}
|
|
29617
29956
|
if (await fileExists(sourceScript)) {
|
|
29618
|
-
let scriptContent = await
|
|
29957
|
+
let scriptContent = await fs57.readFile(sourceScript, "utf8");
|
|
29619
29958
|
scriptContent = scriptContent.replace(/CLI_VERSION="[^"]*"/, `CLI_VERSION="${VERSION}"`);
|
|
29620
|
-
await
|
|
29959
|
+
await fs57.writeFile(prjctStatusLinePath, scriptContent, { mode: 493 });
|
|
29621
29960
|
await installStatusLineModules(sourceLibDir, prjctLibDir);
|
|
29622
29961
|
await installStatusLineModules(sourceComponentsDir, prjctComponentsDir);
|
|
29623
29962
|
if (await fileExists(sourceThemeDir)) {
|
|
29624
|
-
const themes = await
|
|
29963
|
+
const themes = await fs57.readdir(sourceThemeDir);
|
|
29625
29964
|
for (const theme of themes) {
|
|
29626
|
-
const src =
|
|
29627
|
-
const dest =
|
|
29628
|
-
await
|
|
29965
|
+
const src = path61.join(sourceThemeDir, theme);
|
|
29966
|
+
const dest = path61.join(prjctThemesDir, theme);
|
|
29967
|
+
await fs57.copyFile(src, dest);
|
|
29629
29968
|
}
|
|
29630
29969
|
}
|
|
29631
29970
|
if (!await fileExists(prjctConfigPath) && await fileExists(sourceConfigPath)) {
|
|
29632
|
-
await
|
|
29971
|
+
await fs57.copyFile(sourceConfigPath, prjctConfigPath);
|
|
29633
29972
|
}
|
|
29634
29973
|
} else {
|
|
29635
29974
|
const scriptContent = `#!/bin/bash
|
|
@@ -29664,7 +30003,7 @@ if [ -f "$CONFIG" ]; then
|
|
|
29664
30003
|
fi
|
|
29665
30004
|
echo "prjct"
|
|
29666
30005
|
`;
|
|
29667
|
-
await
|
|
30006
|
+
await fs57.writeFile(prjctStatusLinePath, scriptContent, { mode: 493 });
|
|
29668
30007
|
}
|
|
29669
30008
|
await ensureStatusLineSymlink(claudeStatusLinePath, prjctStatusLinePath);
|
|
29670
30009
|
await ensureStatusLineSettings(settingsPath, claudeStatusLinePath);
|
|
@@ -29676,10 +30015,10 @@ echo "prjct"
|
|
|
29676
30015
|
}
|
|
29677
30016
|
async function installContext7MCP() {
|
|
29678
30017
|
try {
|
|
29679
|
-
const claudeDir =
|
|
29680
|
-
const mcpConfigPath =
|
|
30018
|
+
const claudeDir = path61.join(os18.homedir(), ".claude");
|
|
30019
|
+
const mcpConfigPath = path61.join(claudeDir, "mcp.json");
|
|
29681
30020
|
if (!await fileExists(claudeDir)) {
|
|
29682
|
-
await
|
|
30021
|
+
await fs57.mkdir(claudeDir, { recursive: true });
|
|
29683
30022
|
}
|
|
29684
30023
|
const context7Config = {
|
|
29685
30024
|
mcpServers: {
|
|
@@ -29690,16 +30029,16 @@ async function installContext7MCP() {
|
|
|
29690
30029
|
}
|
|
29691
30030
|
};
|
|
29692
30031
|
if (await fileExists(mcpConfigPath)) {
|
|
29693
|
-
const existingContent = await
|
|
30032
|
+
const existingContent = await fs57.readFile(mcpConfigPath, "utf-8");
|
|
29694
30033
|
const existingConfig = JSON.parse(existingContent);
|
|
29695
30034
|
if (existingConfig.mcpServers?.context7) {
|
|
29696
30035
|
return;
|
|
29697
30036
|
}
|
|
29698
30037
|
existingConfig.mcpServers = existingConfig.mcpServers || {};
|
|
29699
30038
|
existingConfig.mcpServers.context7 = context7Config.mcpServers.context7;
|
|
29700
|
-
await
|
|
30039
|
+
await fs57.writeFile(mcpConfigPath, JSON.stringify(existingConfig, null, 2), "utf-8");
|
|
29701
30040
|
} else {
|
|
29702
|
-
await
|
|
30041
|
+
await fs57.writeFile(mcpConfigPath, JSON.stringify(context7Config, null, 2), "utf-8");
|
|
29703
30042
|
}
|
|
29704
30043
|
} catch (error) {
|
|
29705
30044
|
logger_default.warn(`Context7 MCP setup warning: ${getErrorMessage2(error)}`);
|
|
@@ -29709,34 +30048,34 @@ async function installStatusLineModules(sourceDir, destDir) {
|
|
|
29709
30048
|
if (!await fileExists(sourceDir)) {
|
|
29710
30049
|
return;
|
|
29711
30050
|
}
|
|
29712
|
-
const files = await
|
|
30051
|
+
const files = await fs57.readdir(sourceDir);
|
|
29713
30052
|
for (const file of files) {
|
|
29714
30053
|
if (file.endsWith(".sh")) {
|
|
29715
|
-
const src =
|
|
29716
|
-
const dest =
|
|
29717
|
-
await
|
|
29718
|
-
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);
|
|
29719
30058
|
}
|
|
29720
30059
|
}
|
|
29721
30060
|
}
|
|
29722
30061
|
async function ensureStatusLineSymlink(linkPath, targetPath) {
|
|
29723
30062
|
try {
|
|
29724
30063
|
if (await fileExists(linkPath)) {
|
|
29725
|
-
const stats = await
|
|
30064
|
+
const stats = await fs57.lstat(linkPath);
|
|
29726
30065
|
if (stats.isSymbolicLink()) {
|
|
29727
|
-
const existingTarget = await
|
|
30066
|
+
const existingTarget = await fs57.readlink(linkPath);
|
|
29728
30067
|
if (existingTarget === targetPath) {
|
|
29729
30068
|
return;
|
|
29730
30069
|
}
|
|
29731
30070
|
}
|
|
29732
|
-
await
|
|
30071
|
+
await fs57.unlink(linkPath);
|
|
29733
30072
|
}
|
|
29734
|
-
await
|
|
30073
|
+
await fs57.symlink(targetPath, linkPath);
|
|
29735
30074
|
} catch (_error) {
|
|
29736
30075
|
try {
|
|
29737
30076
|
if (await fileExists(targetPath)) {
|
|
29738
|
-
await
|
|
29739
|
-
await
|
|
30077
|
+
await fs57.copyFile(targetPath, linkPath);
|
|
30078
|
+
await fs57.chmod(linkPath, 493);
|
|
29740
30079
|
}
|
|
29741
30080
|
} catch (copyError) {
|
|
29742
30081
|
if (!isNotFoundError(copyError)) {
|
|
@@ -30151,7 +30490,7 @@ var init_registry2 = __esm({
|
|
|
30151
30490
|
});
|
|
30152
30491
|
|
|
30153
30492
|
// core/commands/analytics.ts
|
|
30154
|
-
import
|
|
30493
|
+
import path62 from "node:path";
|
|
30155
30494
|
var AnalyticsCommands;
|
|
30156
30495
|
var init_analytics = __esm({
|
|
30157
30496
|
"core/commands/analytics.ts"() {
|
|
@@ -30178,7 +30517,7 @@ var init_analytics = __esm({
|
|
|
30178
30517
|
output_default.failWithHint("NO_PROJECT_ID");
|
|
30179
30518
|
return { success: false, error: "No project ID found" };
|
|
30180
30519
|
}
|
|
30181
|
-
const projectName =
|
|
30520
|
+
const projectName = path62.basename(projectPath);
|
|
30182
30521
|
const currentTask = await stateStorage.getCurrentTask(projectId);
|
|
30183
30522
|
const queueTasks = await queueStorage.getActiveTasks(projectId);
|
|
30184
30523
|
const shipped = await shippedStorage.getRecent(projectId, 5);
|
|
@@ -30430,8 +30769,8 @@ ${"\u2550".repeat(50)}
|
|
|
30430
30769
|
});
|
|
30431
30770
|
|
|
30432
30771
|
// core/commands/context.ts
|
|
30433
|
-
import
|
|
30434
|
-
import
|
|
30772
|
+
import fs58 from "node:fs/promises";
|
|
30773
|
+
import path63 from "node:path";
|
|
30435
30774
|
var ContextCommands, contextCommands;
|
|
30436
30775
|
var init_context = __esm({
|
|
30437
30776
|
"core/commands/context.ts"() {
|
|
@@ -30557,8 +30896,8 @@ var init_context = __esm({
|
|
|
30557
30896
|
*/
|
|
30558
30897
|
async loadRepoAnalysis(globalPath) {
|
|
30559
30898
|
try {
|
|
30560
|
-
const analysisPath =
|
|
30561
|
-
const content = await
|
|
30899
|
+
const analysisPath = path63.join(globalPath, "analysis", "repo-analysis.json");
|
|
30900
|
+
const content = await fs58.readFile(analysisPath, "utf-8");
|
|
30562
30901
|
const data = JSON.parse(content);
|
|
30563
30902
|
return {
|
|
30564
30903
|
ecosystem: data.ecosystem || "unknown",
|
|
@@ -30577,7 +30916,7 @@ var init_context = __esm({
|
|
|
30577
30916
|
});
|
|
30578
30917
|
|
|
30579
30918
|
// core/commands/cleanup.ts
|
|
30580
|
-
import
|
|
30919
|
+
import path64 from "node:path";
|
|
30581
30920
|
async function cleanupMemory(projectPath) {
|
|
30582
30921
|
const projectId = await config_manager_default.getProjectId(projectPath);
|
|
30583
30922
|
const results = { rotated: [], totalSize: 0, freedSpace: 0 };
|
|
@@ -30593,7 +30932,7 @@ async function cleanupMemory(projectPath) {
|
|
|
30593
30932
|
results.totalSize += sizeMB;
|
|
30594
30933
|
const rotated = await jsonl_helper_exports.rotateJsonLinesIfNeeded(filePath, 10);
|
|
30595
30934
|
if (rotated) {
|
|
30596
|
-
results.rotated.push(
|
|
30935
|
+
results.rotated.push(path64.basename(filePath));
|
|
30597
30936
|
results.freedSpace += sizeMB;
|
|
30598
30937
|
}
|
|
30599
30938
|
}
|
|
@@ -30700,7 +31039,7 @@ var init_cleanup = __esm({
|
|
|
30700
31039
|
});
|
|
30701
31040
|
|
|
30702
31041
|
// core/commands/design.ts
|
|
30703
|
-
import
|
|
31042
|
+
import path65 from "node:path";
|
|
30704
31043
|
async function design(target = null, options = {}, projectPath = process.cwd()) {
|
|
30705
31044
|
try {
|
|
30706
31045
|
const designType = options.type || "architecture";
|
|
@@ -30712,7 +31051,7 @@ async function design(target = null, options = {}, projectPath = process.cwd())
|
|
|
30712
31051
|
const designTarget = target || "system";
|
|
30713
31052
|
output_default.spin(`designing ${designType}...`);
|
|
30714
31053
|
const projectId = await config_manager_default.getProjectId(projectPath);
|
|
30715
|
-
const designsPath =
|
|
31054
|
+
const designsPath = path65.join(
|
|
30716
31055
|
path_manager_default.getGlobalProjectPath(projectId),
|
|
30717
31056
|
"planning",
|
|
30718
31057
|
"designs"
|
|
@@ -30752,7 +31091,7 @@ async function design(target = null, options = {}, projectPath = process.cwd())
|
|
|
30752
31091
|
break;
|
|
30753
31092
|
}
|
|
30754
31093
|
const designFileName = `${designType}-${designTarget.toLowerCase().replace(/\s+/g, "-")}.md`;
|
|
30755
|
-
const designFilePath =
|
|
31094
|
+
const designFilePath = path65.join(designsPath, designFileName);
|
|
30756
31095
|
await file_helper_exports.writeFile(designFilePath, designContent);
|
|
30757
31096
|
await memoryService.log(projectPath, "design_created", {
|
|
30758
31097
|
type: designType,
|
|
@@ -30777,7 +31116,7 @@ var init_design = __esm({
|
|
|
30777
31116
|
});
|
|
30778
31117
|
|
|
30779
31118
|
// core/commands/snapshots.ts
|
|
30780
|
-
import
|
|
31119
|
+
import path66 from "node:path";
|
|
30781
31120
|
async function recover(projectPath = process.cwd()) {
|
|
30782
31121
|
try {
|
|
30783
31122
|
const projectId = await config_manager_default.getProjectId(projectPath);
|
|
@@ -30829,7 +31168,7 @@ async function undo(projectPath = process.cwd()) {
|
|
|
30829
31168
|
output_default.failWithHint("NO_PROJECT_ID");
|
|
30830
31169
|
return { success: false, error: "No project ID found" };
|
|
30831
31170
|
}
|
|
30832
|
-
const snapshotsPath =
|
|
31171
|
+
const snapshotsPath = path66.join(path_manager_default.getGlobalProjectPath(projectId), "snapshots");
|
|
30833
31172
|
await file_helper_exports.ensureDir(snapshotsPath);
|
|
30834
31173
|
const { execSync: execSync5 } = await import("node:child_process");
|
|
30835
31174
|
try {
|
|
@@ -30847,7 +31186,7 @@ async function undo(projectPath = process.cwd()) {
|
|
|
30847
31186
|
cwd: projectPath,
|
|
30848
31187
|
encoding: "utf-8"
|
|
30849
31188
|
});
|
|
30850
|
-
const snapshotFile =
|
|
31189
|
+
const snapshotFile = path66.join(snapshotsPath, "history.json");
|
|
30851
31190
|
let history2 = { snapshots: [], current: -1 };
|
|
30852
31191
|
try {
|
|
30853
31192
|
const content = await file_helper_exports.readFile(snapshotFile);
|
|
@@ -30887,8 +31226,8 @@ async function redo(projectPath = process.cwd()) {
|
|
|
30887
31226
|
output_default.failWithHint("NO_PROJECT_ID");
|
|
30888
31227
|
return { success: false, error: "No project ID found" };
|
|
30889
31228
|
}
|
|
30890
|
-
const snapshotsPath =
|
|
30891
|
-
const snapshotFile =
|
|
31229
|
+
const snapshotsPath = path66.join(path_manager_default.getGlobalProjectPath(projectId), "snapshots");
|
|
31230
|
+
const snapshotFile = path66.join(snapshotsPath, "history.json");
|
|
30892
31231
|
let history2;
|
|
30893
31232
|
try {
|
|
30894
31233
|
const content = await file_helper_exports.readFile(snapshotFile);
|
|
@@ -30947,8 +31286,8 @@ async function history(projectPath = process.cwd()) {
|
|
|
30947
31286
|
output_default.failWithHint("NO_PROJECT_ID");
|
|
30948
31287
|
return { success: false, error: "No project ID found" };
|
|
30949
31288
|
}
|
|
30950
|
-
const snapshotsPath =
|
|
30951
|
-
const snapshotFile =
|
|
31289
|
+
const snapshotsPath = path66.join(path_manager_default.getGlobalProjectPath(projectId), "snapshots");
|
|
31290
|
+
const snapshotFile = path66.join(snapshotsPath, "history.json");
|
|
30952
31291
|
let snapshotHistory;
|
|
30953
31292
|
try {
|
|
30954
31293
|
const content = await file_helper_exports.readFile(snapshotFile);
|
|
@@ -31151,8 +31490,8 @@ ${chalk16.cyan("Performance Report")} ${chalk16.dim(`(last ${days} days)`)}`);
|
|
|
31151
31490
|
});
|
|
31152
31491
|
|
|
31153
31492
|
// core/commands/setup.ts
|
|
31154
|
-
import
|
|
31155
|
-
import
|
|
31493
|
+
import fs59 from "node:fs/promises";
|
|
31494
|
+
import path67 from "node:path";
|
|
31156
31495
|
import chalk17 from "chalk";
|
|
31157
31496
|
var SetupCommands;
|
|
31158
31497
|
var init_setup2 = __esm({
|
|
@@ -31281,7 +31620,7 @@ Please install it first:
|
|
|
31281
31620
|
try {
|
|
31282
31621
|
const claudeDir = path_manager_default.getClaudeDir();
|
|
31283
31622
|
const settingsPath = path_manager_default.getClaudeSettingsPath();
|
|
31284
|
-
const statusLinePath =
|
|
31623
|
+
const statusLinePath = path67.join(claudeDir, "prjct-statusline.sh");
|
|
31285
31624
|
const scriptContent = `#!/bin/bash
|
|
31286
31625
|
# prjct Status Line for Claude Code
|
|
31287
31626
|
# Shows version update notifications and current task
|
|
@@ -31339,11 +31678,11 @@ fi
|
|
|
31339
31678
|
# Default: show prjct branding
|
|
31340
31679
|
echo "\u26A1 prjct"
|
|
31341
31680
|
`;
|
|
31342
|
-
await
|
|
31681
|
+
await fs59.writeFile(statusLinePath, scriptContent, { mode: 493 });
|
|
31343
31682
|
let settings = {};
|
|
31344
31683
|
if (await fileExists(settingsPath)) {
|
|
31345
31684
|
try {
|
|
31346
|
-
settings = JSON.parse(await
|
|
31685
|
+
settings = JSON.parse(await fs59.readFile(settingsPath, "utf8"));
|
|
31347
31686
|
} catch (_error) {
|
|
31348
31687
|
}
|
|
31349
31688
|
}
|
|
@@ -31351,7 +31690,7 @@ echo "\u26A1 prjct"
|
|
|
31351
31690
|
type: "command",
|
|
31352
31691
|
command: statusLinePath
|
|
31353
31692
|
};
|
|
31354
|
-
await
|
|
31693
|
+
await fs59.writeFile(settingsPath, JSON.stringify(settings, null, 2));
|
|
31355
31694
|
return { success: true };
|
|
31356
31695
|
} catch (error) {
|
|
31357
31696
|
return { success: false, error: getErrorMessage2(error) };
|
|
@@ -31407,18 +31746,18 @@ echo "\u26A1 prjct"
|
|
|
31407
31746
|
});
|
|
31408
31747
|
|
|
31409
31748
|
// core/utils/project-commands.ts
|
|
31410
|
-
import
|
|
31749
|
+
import path68 from "node:path";
|
|
31411
31750
|
async function detectPackageManager(projectPath, pkg) {
|
|
31412
31751
|
const declared = pkg?.packageManager?.trim().toLowerCase();
|
|
31413
31752
|
if (declared?.startsWith("pnpm@")) return "pnpm";
|
|
31414
31753
|
if (declared?.startsWith("yarn@")) return "yarn";
|
|
31415
31754
|
if (declared?.startsWith("bun@")) return "bun";
|
|
31416
31755
|
if (declared?.startsWith("npm@")) return "npm";
|
|
31417
|
-
if (await fileExists2(
|
|
31418
|
-
if (await fileExists2(
|
|
31419
|
-
if (await fileExists2(
|
|
31420
|
-
if (await fileExists2(
|
|
31421
|
-
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";
|
|
31422
31761
|
return "npm";
|
|
31423
31762
|
}
|
|
31424
31763
|
function pmRun(pm, scriptName) {
|
|
@@ -31434,7 +31773,7 @@ function pmTest(pm) {
|
|
|
31434
31773
|
return "npm test";
|
|
31435
31774
|
}
|
|
31436
31775
|
async function detectProjectCommands(projectPath) {
|
|
31437
|
-
const pkgPath =
|
|
31776
|
+
const pkgPath = path68.join(projectPath, "package.json");
|
|
31438
31777
|
const pkg = await readJson(pkgPath, null);
|
|
31439
31778
|
if (pkg) {
|
|
31440
31779
|
const pm = await detectPackageManager(projectPath, pkg);
|
|
@@ -31451,27 +31790,27 @@ async function detectProjectCommands(projectPath) {
|
|
|
31451
31790
|
}
|
|
31452
31791
|
return result;
|
|
31453
31792
|
}
|
|
31454
|
-
if (await fileExists2(
|
|
31793
|
+
if (await fileExists2(path68.join(projectPath, "pytest.ini"))) {
|
|
31455
31794
|
return { stack: "python", test: { tool: "pytest", command: "pytest" } };
|
|
31456
31795
|
}
|
|
31457
|
-
const pyproject = await readFile(
|
|
31796
|
+
const pyproject = await readFile(path68.join(projectPath, "pyproject.toml"), "");
|
|
31458
31797
|
if (pyproject.includes("[tool.pytest") || pyproject.includes("pytest")) {
|
|
31459
31798
|
return { stack: "python", test: { tool: "pytest", command: "pytest" } };
|
|
31460
31799
|
}
|
|
31461
|
-
if (await fileExists2(
|
|
31800
|
+
if (await fileExists2(path68.join(projectPath, "Cargo.toml"))) {
|
|
31462
31801
|
return { stack: "rust", test: { tool: "cargo", command: "cargo test" } };
|
|
31463
31802
|
}
|
|
31464
|
-
if (await fileExists2(
|
|
31803
|
+
if (await fileExists2(path68.join(projectPath, "go.mod"))) {
|
|
31465
31804
|
return { stack: "go", test: { tool: "go", command: "go test ./..." } };
|
|
31466
31805
|
}
|
|
31467
31806
|
const files = await listFiles(projectPath);
|
|
31468
31807
|
if (files.some((f) => f.endsWith(".sln") || f.endsWith(".csproj") || f.endsWith(".fsproj"))) {
|
|
31469
31808
|
return { stack: "dotnet", test: { tool: "dotnet", command: "dotnet test" } };
|
|
31470
31809
|
}
|
|
31471
|
-
if (await fileExists2(
|
|
31810
|
+
if (await fileExists2(path68.join(projectPath, "pom.xml"))) {
|
|
31472
31811
|
return { stack: "java", test: { tool: "maven", command: "mvn test" } };
|
|
31473
31812
|
}
|
|
31474
|
-
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")))) {
|
|
31475
31814
|
return { stack: "java", test: { tool: "gradle", command: "./gradlew test" } };
|
|
31476
31815
|
}
|
|
31477
31816
|
return { stack: "unknown" };
|
|
@@ -31646,7 +31985,7 @@ var init_workflow_preferences = __esm({
|
|
|
31646
31985
|
});
|
|
31647
31986
|
|
|
31648
31987
|
// core/commands/shipping.ts
|
|
31649
|
-
import
|
|
31988
|
+
import path69 from "node:path";
|
|
31650
31989
|
var ShippingCommands;
|
|
31651
31990
|
var init_shipping = __esm({
|
|
31652
31991
|
"core/commands/shipping.ts"() {
|
|
@@ -31792,7 +32131,7 @@ ${result.stderr}`.trim();
|
|
|
31792
32131
|
*/
|
|
31793
32132
|
async _bumpVersion(projectPath) {
|
|
31794
32133
|
try {
|
|
31795
|
-
const pkgPath =
|
|
32134
|
+
const pkgPath = path69.join(projectPath, "package.json");
|
|
31796
32135
|
const pkg = await file_helper_exports.readJson(pkgPath, { version: "0.0.0" });
|
|
31797
32136
|
const oldVersion = pkg?.version || "0.0.0";
|
|
31798
32137
|
const [major, minor, patch] = oldVersion.split(".").map(Number);
|
|
@@ -31814,7 +32153,7 @@ ${result.stderr}`.trim();
|
|
|
31814
32153
|
*/
|
|
31815
32154
|
async _updateChangelog(feature, version, projectPath) {
|
|
31816
32155
|
try {
|
|
31817
|
-
const changelogPath =
|
|
32156
|
+
const changelogPath = path69.join(projectPath, "CHANGELOG.md");
|
|
31818
32157
|
const changelog = await file_helper_exports.readFile(changelogPath, "# Changelog\n\n");
|
|
31819
32158
|
const entry = `## [${version}] - ${date_helper_exports.formatDate(/* @__PURE__ */ new Date())}
|
|
31820
32159
|
|
|
@@ -32858,11 +33197,11 @@ var init_linear = __esm({
|
|
|
32858
33197
|
});
|
|
32859
33198
|
|
|
32860
33199
|
// core/utils/project-credentials.ts
|
|
32861
|
-
import
|
|
33200
|
+
import fs60 from "node:fs/promises";
|
|
32862
33201
|
import os19 from "node:os";
|
|
32863
|
-
import
|
|
33202
|
+
import path70 from "node:path";
|
|
32864
33203
|
function getCredentialsPath(projectId) {
|
|
32865
|
-
return
|
|
33204
|
+
return path70.join(os19.homedir(), ".prjct-cli", "projects", projectId, "config", "credentials.json");
|
|
32866
33205
|
}
|
|
32867
33206
|
async function getProjectCredentials(projectId) {
|
|
32868
33207
|
const credPath = getCredentialsPath(projectId);
|
|
@@ -32870,7 +33209,7 @@ async function getProjectCredentials(projectId) {
|
|
|
32870
33209
|
return {};
|
|
32871
33210
|
}
|
|
32872
33211
|
try {
|
|
32873
|
-
return JSON.parse(await
|
|
33212
|
+
return JSON.parse(await fs60.readFile(credPath, "utf-8"));
|
|
32874
33213
|
} catch (error) {
|
|
32875
33214
|
console.error("[project-credentials] Failed to read credentials:", getErrorMessage2(error));
|
|
32876
33215
|
return {};
|
|
@@ -33542,7 +33881,7 @@ var require_package = __commonJS({
|
|
|
33542
33881
|
"package.json"(exports, module) {
|
|
33543
33882
|
module.exports = {
|
|
33544
33883
|
name: "prjct-cli",
|
|
33545
|
-
version: "1.
|
|
33884
|
+
version: "1.18.0",
|
|
33546
33885
|
description: "Context layer for AI agents. Project context for Claude Code, Gemini CLI, and more.",
|
|
33547
33886
|
main: "core/index.ts",
|
|
33548
33887
|
bin: {
|
|
@@ -33649,7 +33988,7 @@ var require_package = __commonJS({
|
|
|
33649
33988
|
// core/index.ts
|
|
33650
33989
|
var core_exports = {};
|
|
33651
33990
|
import os20 from "node:os";
|
|
33652
|
-
import
|
|
33991
|
+
import path71 from "node:path";
|
|
33653
33992
|
import chalk20 from "chalk";
|
|
33654
33993
|
async function main() {
|
|
33655
33994
|
const [commandName, ...rawArgs] = process.argv.slice(2);
|
|
@@ -33754,7 +34093,8 @@ async function main() {
|
|
|
33754
34093
|
preview: options.preview === true || options["dry-run"] === true,
|
|
33755
34094
|
yes: options.yes === true,
|
|
33756
34095
|
json: options.json === true,
|
|
33757
|
-
package: options.package ? String(options.package) : void 0
|
|
34096
|
+
package: options.package ? String(options.package) : void 0,
|
|
34097
|
+
full: options.full === true
|
|
33758
34098
|
}), "sync"),
|
|
33759
34099
|
seal: /* @__PURE__ */ __name(() => commands.seal(process.cwd(), { json: options.json === true }), "seal"),
|
|
33760
34100
|
verify: /* @__PURE__ */ __name(() => commands.verify(process.cwd(), { json: options.json === true }), "verify"),
|
|
@@ -33862,13 +34202,13 @@ function parseCommandArgs(_cmd, rawArgs) {
|
|
|
33862
34202
|
}
|
|
33863
34203
|
async function displayVersion(version) {
|
|
33864
34204
|
const detection = await detectAllProviders();
|
|
33865
|
-
const claudeCommandPath =
|
|
33866
|
-
const geminiCommandPath =
|
|
34205
|
+
const claudeCommandPath = path71.join(os20.homedir(), ".claude", "commands", "p.md");
|
|
34206
|
+
const geminiCommandPath = path71.join(os20.homedir(), ".gemini", "commands", "p.toml");
|
|
33867
34207
|
const [claudeConfigured, geminiConfigured, cursorConfigured, cursorExists] = await Promise.all([
|
|
33868
34208
|
fileExists(claudeCommandPath),
|
|
33869
34209
|
fileExists(geminiCommandPath),
|
|
33870
|
-
fileExists(
|
|
33871
|
-
fileExists(
|
|
34210
|
+
fileExists(path71.join(process.cwd(), ".cursor", "commands", "sync.md")),
|
|
34211
|
+
fileExists(path71.join(process.cwd(), ".cursor"))
|
|
33872
34212
|
]);
|
|
33873
34213
|
const antigravityDetection = await detectAntigravity();
|
|
33874
34214
|
console.log(`
|
|
@@ -34007,7 +34347,7 @@ init_ai_provider();
|
|
|
34007
34347
|
init_config_manager();
|
|
34008
34348
|
init_editors_config();
|
|
34009
34349
|
import os21 from "node:os";
|
|
34010
|
-
import
|
|
34350
|
+
import path72 from "node:path";
|
|
34011
34351
|
import chalk21 from "chalk";
|
|
34012
34352
|
|
|
34013
34353
|
// core/server/server.ts
|
|
@@ -34828,13 +35168,13 @@ async function checkRoutersInstalled() {
|
|
|
34828
35168
|
const home = os21.homedir();
|
|
34829
35169
|
const detection = await detectAllProviders();
|
|
34830
35170
|
if (detection.claude.installed) {
|
|
34831
|
-
const claudeRouter =
|
|
35171
|
+
const claudeRouter = path72.join(home, ".claude", "commands", "p.md");
|
|
34832
35172
|
if (!await fileExists(claudeRouter)) {
|
|
34833
35173
|
return false;
|
|
34834
35174
|
}
|
|
34835
35175
|
}
|
|
34836
35176
|
if (detection.gemini.installed) {
|
|
34837
|
-
const geminiRouter =
|
|
35177
|
+
const geminiRouter = path72.join(home, ".gemini", "commands", "p.toml");
|
|
34838
35178
|
if (!await fileExists(geminiRouter)) {
|
|
34839
35179
|
return false;
|
|
34840
35180
|
}
|
|
@@ -34975,7 +35315,7 @@ if (args[0] === "start" || args[0] === "setup") {
|
|
|
34975
35315
|
console.error('No prjct project found. Run "prjct init" first.');
|
|
34976
35316
|
process.exitCode = 1;
|
|
34977
35317
|
} else {
|
|
34978
|
-
const linearCliPath =
|
|
35318
|
+
const linearCliPath = path72.join(__dirname, "..", "core", "cli", "linear.ts");
|
|
34979
35319
|
const linearArgs = ["--project", projectId, ...args.slice(1)];
|
|
34980
35320
|
const child = spawn("bun", [linearCliPath, ...linearArgs], {
|
|
34981
35321
|
stdio: "inherit",
|
|
@@ -35002,12 +35342,12 @@ if (args[0] === "start" || args[0] === "setup") {
|
|
|
35002
35342
|
windsurfDetected,
|
|
35003
35343
|
windsurfConfigured
|
|
35004
35344
|
] = await Promise.all([
|
|
35005
|
-
fileExists(
|
|
35006
|
-
fileExists(
|
|
35007
|
-
fileExists(
|
|
35008
|
-
fileExists(
|
|
35009
|
-
fileExists(
|
|
35010
|
-
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"))
|
|
35011
35351
|
]);
|
|
35012
35352
|
console.log(`
|
|
35013
35353
|
${chalk21.cyan("p/")} prjct v${VERSION}
|
|
@@ -35046,7 +35386,7 @@ ${chalk21.dim("Run 'prjct init' to configure (Cursor/Windsurf IDE)")}
|
|
|
35046
35386
|
${chalk21.cyan("https://prjct.app")}
|
|
35047
35387
|
`);
|
|
35048
35388
|
} else {
|
|
35049
|
-
const configPath =
|
|
35389
|
+
const configPath = path72.join(os21.homedir(), ".prjct-cli", "config", "installed-editors.json");
|
|
35050
35390
|
const routersInstalled = await checkRoutersInstalled();
|
|
35051
35391
|
if (!await fileExists(configPath) || !routersInstalled) {
|
|
35052
35392
|
console.log(`
|