prjct-cli 1.7.0 → 1.7.2
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 +63 -1
- package/core/__tests__/storage/safe-reader.test.ts +262 -0
- package/core/__tests__/workflow/state-machine.test.ts +216 -0
- package/core/schemas/shipped.ts +3 -3
- package/core/schemas/state.ts +6 -1
- package/core/storage/ideas-storage.ts +2 -1
- package/core/storage/metrics-storage.ts +2 -1
- package/core/storage/queue-storage.ts +2 -1
- package/core/storage/safe-reader.ts +105 -0
- package/core/storage/shipped-storage.ts +2 -1
- package/core/storage/state-storage.ts +300 -31
- package/core/storage/storage-manager.ts +19 -3
- package/core/utils/file-helper.ts +10 -2
- package/core/utils/next-steps.ts +2 -0
- package/core/workflow/state-machine.ts +23 -10
- package/dist/bin/prjct.mjs +953 -647
- package/package.json +1 -1
package/dist/bin/prjct.mjs
CHANGED
|
@@ -932,6 +932,60 @@ var init_author_detector = __esm({
|
|
|
932
932
|
}
|
|
933
933
|
});
|
|
934
934
|
|
|
935
|
+
// core/storage/safe-reader.ts
|
|
936
|
+
import fs4 from "node:fs/promises";
|
|
937
|
+
async function safeRead(filePath, schema) {
|
|
938
|
+
let content;
|
|
939
|
+
try {
|
|
940
|
+
content = await fs4.readFile(filePath, "utf-8");
|
|
941
|
+
} catch (error) {
|
|
942
|
+
if (isNotFoundError(error)) {
|
|
943
|
+
return null;
|
|
944
|
+
}
|
|
945
|
+
throw error;
|
|
946
|
+
}
|
|
947
|
+
let raw;
|
|
948
|
+
try {
|
|
949
|
+
raw = JSON.parse(content);
|
|
950
|
+
} catch {
|
|
951
|
+
await createBackup(filePath, content);
|
|
952
|
+
logCorruption(filePath, "Malformed JSON");
|
|
953
|
+
return null;
|
|
954
|
+
}
|
|
955
|
+
const result = schema.safeParse(raw);
|
|
956
|
+
if (result.success) {
|
|
957
|
+
return raw;
|
|
958
|
+
}
|
|
959
|
+
await createBackup(filePath, content);
|
|
960
|
+
logCorruption(filePath, formatZodError(result.error));
|
|
961
|
+
return null;
|
|
962
|
+
}
|
|
963
|
+
async function createBackup(filePath, content) {
|
|
964
|
+
const backupPath = `${filePath}.backup`;
|
|
965
|
+
try {
|
|
966
|
+
await fs4.writeFile(backupPath, content, "utf-8");
|
|
967
|
+
} catch {
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
function logCorruption(filePath, reason2) {
|
|
971
|
+
console.error(`[prjct] Warning: Corrupted storage file: ${filePath}`);
|
|
972
|
+
console.error(`[prjct] Reason: ${reason2}`);
|
|
973
|
+
console.error(`[prjct] A .backup file has been created. Returning defaults.`);
|
|
974
|
+
}
|
|
975
|
+
function formatZodError(error) {
|
|
976
|
+
return error.issues.slice(0, 3).map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; ");
|
|
977
|
+
}
|
|
978
|
+
var init_safe_reader = __esm({
|
|
979
|
+
"core/storage/safe-reader.ts"() {
|
|
980
|
+
"use strict";
|
|
981
|
+
init_fs();
|
|
982
|
+
__name(safeRead, "safeRead");
|
|
983
|
+
__name(createBackup, "createBackup");
|
|
984
|
+
__name(logCorruption, "logCorruption");
|
|
985
|
+
__name(formatZodError, "formatZodError");
|
|
986
|
+
}
|
|
987
|
+
});
|
|
988
|
+
|
|
935
989
|
// core/utils/file-helper.ts
|
|
936
990
|
var file_helper_exports = {};
|
|
937
991
|
__export(file_helper_exports, {
|
|
@@ -958,11 +1012,15 @@ __export(file_helper_exports, {
|
|
|
958
1012
|
writeJson: () => writeJson,
|
|
959
1013
|
writeLines: () => writeLines
|
|
960
1014
|
});
|
|
961
|
-
import
|
|
1015
|
+
import fs5 from "node:fs/promises";
|
|
962
1016
|
import path4 from "node:path";
|
|
963
|
-
async function readJson(filePath, defaultValue = null) {
|
|
1017
|
+
async function readJson(filePath, defaultValue = null, schema) {
|
|
1018
|
+
if (schema) {
|
|
1019
|
+
const data = await safeRead(filePath, schema);
|
|
1020
|
+
return data ?? defaultValue;
|
|
1021
|
+
}
|
|
964
1022
|
try {
|
|
965
|
-
const content = await
|
|
1023
|
+
const content = await fs5.readFile(filePath, "utf-8");
|
|
966
1024
|
return JSON.parse(content);
|
|
967
1025
|
} catch (error) {
|
|
968
1026
|
if (isNotFoundError(error)) {
|
|
@@ -973,11 +1031,11 @@ async function readJson(filePath, defaultValue = null) {
|
|
|
973
1031
|
}
|
|
974
1032
|
async function writeJson(filePath, data, indent = 2) {
|
|
975
1033
|
const content = JSON.stringify(data, null, indent);
|
|
976
|
-
await
|
|
1034
|
+
await fs5.writeFile(filePath, content, "utf-8");
|
|
977
1035
|
}
|
|
978
1036
|
async function readFile(filePath, defaultValue = "") {
|
|
979
1037
|
try {
|
|
980
|
-
return await
|
|
1038
|
+
return await fs5.readFile(filePath, "utf-8");
|
|
981
1039
|
} catch (error) {
|
|
982
1040
|
if (isNotFoundError(error)) {
|
|
983
1041
|
return defaultValue;
|
|
@@ -987,32 +1045,32 @@ async function readFile(filePath, defaultValue = "") {
|
|
|
987
1045
|
}
|
|
988
1046
|
async function writeFile(filePath, content) {
|
|
989
1047
|
const dir = path4.dirname(filePath);
|
|
990
|
-
await
|
|
991
|
-
await
|
|
1048
|
+
await fs5.mkdir(dir, { recursive: true });
|
|
1049
|
+
await fs5.writeFile(filePath, content, "utf-8");
|
|
992
1050
|
}
|
|
993
1051
|
async function atomicWrite(filePath, content) {
|
|
994
1052
|
const dir = path4.dirname(filePath);
|
|
995
|
-
await
|
|
1053
|
+
await fs5.mkdir(dir, { recursive: true });
|
|
996
1054
|
const tempPath = `${filePath}.${Date.now()}.tmp`;
|
|
997
|
-
await
|
|
998
|
-
await
|
|
1055
|
+
await fs5.writeFile(tempPath, content, "utf-8");
|
|
1056
|
+
await fs5.rename(tempPath, filePath);
|
|
999
1057
|
}
|
|
1000
1058
|
async function appendToFile(filePath, content) {
|
|
1001
|
-
await
|
|
1059
|
+
await fs5.appendFile(filePath, content, "utf-8");
|
|
1002
1060
|
}
|
|
1003
1061
|
async function appendLine(filePath, line) {
|
|
1004
1062
|
const dir = path4.dirname(filePath);
|
|
1005
|
-
await
|
|
1006
|
-
await
|
|
1063
|
+
await fs5.mkdir(dir, { recursive: true });
|
|
1064
|
+
await fs5.appendFile(filePath, `${line}
|
|
1007
1065
|
`, "utf-8");
|
|
1008
1066
|
}
|
|
1009
1067
|
async function prependToFile(filePath, content) {
|
|
1010
1068
|
try {
|
|
1011
|
-
const existing = await
|
|
1012
|
-
await
|
|
1069
|
+
const existing = await fs5.readFile(filePath, "utf-8");
|
|
1070
|
+
await fs5.writeFile(filePath, content + existing, "utf-8");
|
|
1013
1071
|
} catch (error) {
|
|
1014
1072
|
if (isNotFoundError(error)) {
|
|
1015
|
-
await
|
|
1073
|
+
await fs5.writeFile(filePath, content, "utf-8");
|
|
1016
1074
|
} else {
|
|
1017
1075
|
throw error;
|
|
1018
1076
|
}
|
|
@@ -1020,7 +1078,7 @@ async function prependToFile(filePath, content) {
|
|
|
1020
1078
|
}
|
|
1021
1079
|
async function fileExists2(filePath) {
|
|
1022
1080
|
try {
|
|
1023
|
-
await
|
|
1081
|
+
await fs5.access(filePath);
|
|
1024
1082
|
return true;
|
|
1025
1083
|
} catch (error) {
|
|
1026
1084
|
if (isNotFoundError(error)) {
|
|
@@ -1031,7 +1089,7 @@ async function fileExists2(filePath) {
|
|
|
1031
1089
|
}
|
|
1032
1090
|
async function dirExists(dirPath) {
|
|
1033
1091
|
try {
|
|
1034
|
-
const stats = await
|
|
1092
|
+
const stats = await fs5.stat(dirPath);
|
|
1035
1093
|
return stats.isDirectory();
|
|
1036
1094
|
} catch (error) {
|
|
1037
1095
|
if (isNotFoundError(error)) {
|
|
@@ -1041,11 +1099,11 @@ async function dirExists(dirPath) {
|
|
|
1041
1099
|
}
|
|
1042
1100
|
}
|
|
1043
1101
|
async function ensureDir(dirPath) {
|
|
1044
|
-
await
|
|
1102
|
+
await fs5.mkdir(dirPath, { recursive: true });
|
|
1045
1103
|
}
|
|
1046
1104
|
async function deleteFile(filePath) {
|
|
1047
1105
|
try {
|
|
1048
|
-
await
|
|
1106
|
+
await fs5.unlink(filePath);
|
|
1049
1107
|
return true;
|
|
1050
1108
|
} catch (error) {
|
|
1051
1109
|
if (isNotFoundError(error)) {
|
|
@@ -1056,7 +1114,7 @@ async function deleteFile(filePath) {
|
|
|
1056
1114
|
}
|
|
1057
1115
|
async function deleteDir(dirPath) {
|
|
1058
1116
|
try {
|
|
1059
|
-
await
|
|
1117
|
+
await fs5.rm(dirPath, { recursive: true, force: true });
|
|
1060
1118
|
return true;
|
|
1061
1119
|
} catch (error) {
|
|
1062
1120
|
if (isNotFoundError(error)) {
|
|
@@ -1067,7 +1125,7 @@ async function deleteDir(dirPath) {
|
|
|
1067
1125
|
}
|
|
1068
1126
|
async function listFiles(dirPath, options = {}) {
|
|
1069
1127
|
try {
|
|
1070
|
-
const entries = await
|
|
1128
|
+
const entries = await fs5.readdir(dirPath, { withFileTypes: true });
|
|
1071
1129
|
let files = entries;
|
|
1072
1130
|
if (options.filesOnly) {
|
|
1073
1131
|
files = files.filter((entry) => entry.isFile());
|
|
@@ -1087,18 +1145,18 @@ async function listFiles(dirPath, options = {}) {
|
|
|
1087
1145
|
}
|
|
1088
1146
|
}
|
|
1089
1147
|
async function getFileSize(filePath) {
|
|
1090
|
-
const stats = await
|
|
1148
|
+
const stats = await fs5.stat(filePath);
|
|
1091
1149
|
return stats.size;
|
|
1092
1150
|
}
|
|
1093
1151
|
async function getFileModifiedTime(filePath) {
|
|
1094
|
-
const stats = await
|
|
1152
|
+
const stats = await fs5.stat(filePath);
|
|
1095
1153
|
return stats.mtime;
|
|
1096
1154
|
}
|
|
1097
1155
|
async function copyFile(sourcePath, destPath) {
|
|
1098
|
-
await
|
|
1156
|
+
await fs5.copyFile(sourcePath, destPath);
|
|
1099
1157
|
}
|
|
1100
1158
|
async function moveFile(oldPath, newPath) {
|
|
1101
|
-
await
|
|
1159
|
+
await fs5.rename(oldPath, newPath);
|
|
1102
1160
|
}
|
|
1103
1161
|
async function readLines(filePath) {
|
|
1104
1162
|
const content = await readFile(filePath, "");
|
|
@@ -1117,6 +1175,7 @@ function getFileNameWithoutExtension(filePath) {
|
|
|
1117
1175
|
var init_file_helper = __esm({
|
|
1118
1176
|
"core/utils/file-helper.ts"() {
|
|
1119
1177
|
"use strict";
|
|
1178
|
+
init_safe_reader();
|
|
1120
1179
|
init_fs();
|
|
1121
1180
|
__name(readJson, "readJson");
|
|
1122
1181
|
__name(writeJson, "writeJson");
|
|
@@ -1145,7 +1204,7 @@ var init_file_helper = __esm({
|
|
|
1145
1204
|
|
|
1146
1205
|
// core/infrastructure/path-manager.ts
|
|
1147
1206
|
import crypto2 from "node:crypto";
|
|
1148
|
-
import
|
|
1207
|
+
import fs6 from "node:fs/promises";
|
|
1149
1208
|
import os3 from "node:os";
|
|
1150
1209
|
import path5 from "node:path";
|
|
1151
1210
|
import { globSync } from "glob";
|
|
@@ -1285,17 +1344,17 @@ var init_path_manager = __esm({
|
|
|
1285
1344
|
const sessionsDir = path5.join(this.getGlobalProjectPath(projectId), "sessions");
|
|
1286
1345
|
const sessions = [];
|
|
1287
1346
|
try {
|
|
1288
|
-
const years = await
|
|
1347
|
+
const years = await fs6.readdir(sessionsDir, { withFileTypes: true });
|
|
1289
1348
|
for (const yearEntry of years) {
|
|
1290
1349
|
if (!yearEntry.isDirectory()) continue;
|
|
1291
1350
|
if (year && yearEntry.name !== year.toString()) continue;
|
|
1292
1351
|
const yearPath = path5.join(sessionsDir, yearEntry.name);
|
|
1293
|
-
const months = await
|
|
1352
|
+
const months = await fs6.readdir(yearPath, { withFileTypes: true });
|
|
1294
1353
|
for (const monthEntry of months) {
|
|
1295
1354
|
if (!monthEntry.isDirectory()) continue;
|
|
1296
1355
|
if (month && monthEntry.name !== month.toString().padStart(2, "0")) continue;
|
|
1297
1356
|
const monthPath = path5.join(yearPath, monthEntry.name);
|
|
1298
|
-
const days = await
|
|
1357
|
+
const days = await fs6.readdir(monthPath, { withFileTypes: true });
|
|
1299
1358
|
for (const dayEntry of days) {
|
|
1300
1359
|
if (!dayEntry.isDirectory()) continue;
|
|
1301
1360
|
sessions.push({
|
|
@@ -1333,7 +1392,7 @@ var init_path_manager = __esm({
|
|
|
1333
1392
|
async listProjects() {
|
|
1334
1393
|
try {
|
|
1335
1394
|
await this.ensureGlobalStructure();
|
|
1336
|
-
const entries = await
|
|
1395
|
+
const entries = await fs6.readdir(this.globalProjectsDir, { withFileTypes: true });
|
|
1337
1396
|
return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
1338
1397
|
} catch (_error) {
|
|
1339
1398
|
return [];
|
|
@@ -1473,7 +1532,7 @@ var init_path_manager = __esm({
|
|
|
1473
1532
|
const packageJsonPath = path5.join(projectPath, "package.json");
|
|
1474
1533
|
if (await fileExists2(packageJsonPath)) {
|
|
1475
1534
|
try {
|
|
1476
|
-
const content = await
|
|
1535
|
+
const content = await fs6.readFile(packageJsonPath, "utf-8");
|
|
1477
1536
|
const pkg = JSON.parse(content);
|
|
1478
1537
|
if (pkg.workspaces) {
|
|
1479
1538
|
result.isMonorepo = true;
|
|
@@ -1496,14 +1555,14 @@ var init_path_manager = __esm({
|
|
|
1496
1555
|
let patterns = [];
|
|
1497
1556
|
try {
|
|
1498
1557
|
if (type === "pnpm") {
|
|
1499
|
-
const yaml = await
|
|
1558
|
+
const yaml = await fs6.readFile(path5.join(rootPath, "pnpm-workspace.yaml"), "utf-8");
|
|
1500
1559
|
const match = yaml.match(/packages:\s*\n((?:\s*-\s*.+\n?)+)/);
|
|
1501
1560
|
if (match) {
|
|
1502
1561
|
patterns = match[1].split("\n").map((line) => line.replace(/^\s*-\s*['"]?|['"]?\s*$/g, "")).filter(Boolean);
|
|
1503
1562
|
}
|
|
1504
1563
|
} else if (type === "npm" || type === "lerna") {
|
|
1505
1564
|
const packageJsonPath = path5.join(rootPath, "package.json");
|
|
1506
|
-
const content = await
|
|
1565
|
+
const content = await fs6.readFile(packageJsonPath, "utf-8");
|
|
1507
1566
|
const pkg = JSON.parse(content);
|
|
1508
1567
|
if (Array.isArray(pkg.workspaces)) {
|
|
1509
1568
|
patterns = pkg.workspaces;
|
|
@@ -1513,7 +1572,7 @@ var init_path_manager = __esm({
|
|
|
1513
1572
|
if (type === "lerna") {
|
|
1514
1573
|
const lernaPath = path5.join(rootPath, "lerna.json");
|
|
1515
1574
|
if (await fileExists2(lernaPath)) {
|
|
1516
|
-
const lernaContent = await
|
|
1575
|
+
const lernaContent = await fs6.readFile(lernaPath, "utf-8");
|
|
1517
1576
|
const lerna = JSON.parse(lernaContent);
|
|
1518
1577
|
if (lerna.packages) {
|
|
1519
1578
|
patterns = lerna.packages;
|
|
@@ -1524,7 +1583,7 @@ var init_path_manager = __esm({
|
|
|
1524
1583
|
patterns = ["apps/*", "libs/*", "packages/*"];
|
|
1525
1584
|
} else if (type === "turborepo") {
|
|
1526
1585
|
const packageJsonPath = path5.join(rootPath, "package.json");
|
|
1527
|
-
const content = await
|
|
1586
|
+
const content = await fs6.readFile(packageJsonPath, "utf-8");
|
|
1528
1587
|
const pkg = JSON.parse(content);
|
|
1529
1588
|
if (Array.isArray(pkg.workspaces)) {
|
|
1530
1589
|
patterns = pkg.workspaces;
|
|
@@ -1544,7 +1603,7 @@ var init_path_manager = __esm({
|
|
|
1544
1603
|
const packageJsonPath = path5.join(packagePath, "package.json");
|
|
1545
1604
|
if (await fileExists2(packageJsonPath)) {
|
|
1546
1605
|
try {
|
|
1547
|
-
const content = await
|
|
1606
|
+
const content = await fs6.readFile(packageJsonPath, "utf-8");
|
|
1548
1607
|
const pkg = JSON.parse(content);
|
|
1549
1608
|
const prjctMdPath = path5.join(packagePath, "PRJCT.md");
|
|
1550
1609
|
packages.push({
|
|
@@ -1600,7 +1659,7 @@ var init_path_manager = __esm({
|
|
|
1600
1659
|
});
|
|
1601
1660
|
|
|
1602
1661
|
// core/infrastructure/config-manager.ts
|
|
1603
|
-
import
|
|
1662
|
+
import fs7 from "node:fs/promises";
|
|
1604
1663
|
import path6 from "node:path";
|
|
1605
1664
|
import * as jsonc from "jsonc-parser";
|
|
1606
1665
|
function parseJsonc(content) {
|
|
@@ -1639,7 +1698,7 @@ var init_config_manager = __esm({
|
|
|
1639
1698
|
async readConfig(projectPath) {
|
|
1640
1699
|
try {
|
|
1641
1700
|
const configPath = path_manager_default.getLocalConfigPath(projectPath);
|
|
1642
|
-
const content = await
|
|
1701
|
+
const content = await fs7.readFile(configPath, "utf-8");
|
|
1643
1702
|
return parseJsonc(content);
|
|
1644
1703
|
} catch (error) {
|
|
1645
1704
|
if (isNotFoundError(error)) {
|
|
@@ -1655,9 +1714,9 @@ var init_config_manager = __esm({
|
|
|
1655
1714
|
async writeConfig(projectPath, config) {
|
|
1656
1715
|
const configPath = path_manager_default.getLocalConfigPath(projectPath);
|
|
1657
1716
|
const configDir = path_manager_default.getLegacyPrjctPath(projectPath);
|
|
1658
|
-
await
|
|
1717
|
+
await fs7.mkdir(configDir, { recursive: true });
|
|
1659
1718
|
const content = JSON.stringify(config, null, 2);
|
|
1660
|
-
await
|
|
1719
|
+
await fs7.writeFile(configPath, `${content}
|
|
1661
1720
|
`, "utf-8");
|
|
1662
1721
|
}
|
|
1663
1722
|
/**
|
|
@@ -1668,7 +1727,7 @@ var init_config_manager = __esm({
|
|
|
1668
1727
|
async readGlobalConfig(projectId) {
|
|
1669
1728
|
try {
|
|
1670
1729
|
const configPath = path_manager_default.getGlobalProjectConfigPath(projectId);
|
|
1671
|
-
const content = await
|
|
1730
|
+
const content = await fs7.readFile(configPath, "utf-8");
|
|
1672
1731
|
return parseJsonc(content);
|
|
1673
1732
|
} catch (error) {
|
|
1674
1733
|
if (isNotFoundError(error)) {
|
|
@@ -1686,9 +1745,9 @@ var init_config_manager = __esm({
|
|
|
1686
1745
|
async writeGlobalConfig(projectId, config) {
|
|
1687
1746
|
const configPath = path_manager_default.getGlobalProjectConfigPath(projectId);
|
|
1688
1747
|
const configDir = path_manager_default.getGlobalProjectPath(projectId);
|
|
1689
|
-
await
|
|
1748
|
+
await fs7.mkdir(configDir, { recursive: true });
|
|
1690
1749
|
const content = JSON.stringify(config, null, 2);
|
|
1691
|
-
await
|
|
1750
|
+
await fs7.writeFile(configPath, `${content}
|
|
1692
1751
|
`, "utf-8");
|
|
1693
1752
|
}
|
|
1694
1753
|
/**
|
|
@@ -1778,7 +1837,7 @@ var init_config_manager = __esm({
|
|
|
1778
1837
|
if (!config || !config.projectId) return true;
|
|
1779
1838
|
const globalPath = path_manager_default.getGlobalProjectPath(config.projectId);
|
|
1780
1839
|
try {
|
|
1781
|
-
const coreFiles = await
|
|
1840
|
+
const coreFiles = await fs7.readdir(path6.join(globalPath, "core"));
|
|
1782
1841
|
return coreFiles.length === 0;
|
|
1783
1842
|
} catch (error) {
|
|
1784
1843
|
if (isNotFoundError(error)) {
|
|
@@ -1901,7 +1960,7 @@ var init_config_manager = __esm({
|
|
|
1901
1960
|
});
|
|
1902
1961
|
|
|
1903
1962
|
// core/infrastructure/editors-config.ts
|
|
1904
|
-
import
|
|
1963
|
+
import fs8 from "node:fs/promises";
|
|
1905
1964
|
import os4 from "node:os";
|
|
1906
1965
|
import path7 from "node:path";
|
|
1907
1966
|
var EditorsConfig, editorsConfig, editors_config_default;
|
|
@@ -1926,7 +1985,7 @@ var init_editors_config = __esm({
|
|
|
1926
1985
|
*/
|
|
1927
1986
|
async ensureConfigDir() {
|
|
1928
1987
|
try {
|
|
1929
|
-
await
|
|
1988
|
+
await fs8.mkdir(this.configDir, { recursive: true });
|
|
1930
1989
|
} catch (error) {
|
|
1931
1990
|
console.error("[editors-config] Error creating config directory:", getErrorMessage2(error));
|
|
1932
1991
|
}
|
|
@@ -1936,7 +1995,7 @@ var init_editors_config = __esm({
|
|
|
1936
1995
|
*/
|
|
1937
1996
|
async loadConfig() {
|
|
1938
1997
|
try {
|
|
1939
|
-
const content = await
|
|
1998
|
+
const content = await fs8.readFile(this.configFile, "utf-8");
|
|
1940
1999
|
return JSON.parse(content);
|
|
1941
2000
|
} catch (error) {
|
|
1942
2001
|
if (error.code === "ENOENT") {
|
|
@@ -1960,7 +2019,7 @@ var init_editors_config = __esm({
|
|
|
1960
2019
|
lastInstall: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1961
2020
|
path: installPath
|
|
1962
2021
|
};
|
|
1963
|
-
await
|
|
2022
|
+
await fs8.writeFile(this.configFile, JSON.stringify(config, null, 2), "utf-8");
|
|
1964
2023
|
return true;
|
|
1965
2024
|
} catch (error) {
|
|
1966
2025
|
console.error("[editors-config] Error saving config:", getErrorMessage2(error));
|
|
@@ -2000,7 +2059,7 @@ var init_editors_config = __esm({
|
|
|
2000
2059
|
}
|
|
2001
2060
|
config.version = version;
|
|
2002
2061
|
config.lastInstall = (/* @__PURE__ */ new Date()).toISOString();
|
|
2003
|
-
await
|
|
2062
|
+
await fs8.writeFile(this.configFile, JSON.stringify(config, null, 2), "utf-8");
|
|
2004
2063
|
return true;
|
|
2005
2064
|
} catch (error) {
|
|
2006
2065
|
console.error("[editors-config] Error updating version:", getErrorMessage2(error));
|
|
@@ -2012,7 +2071,7 @@ var init_editors_config = __esm({
|
|
|
2012
2071
|
*/
|
|
2013
2072
|
async configExists() {
|
|
2014
2073
|
try {
|
|
2015
|
-
await
|
|
2074
|
+
await fs8.access(this.configFile);
|
|
2016
2075
|
return true;
|
|
2017
2076
|
} catch (_error) {
|
|
2018
2077
|
return false;
|
|
@@ -2026,7 +2085,7 @@ var init_editors_config = __esm({
|
|
|
2026
2085
|
try {
|
|
2027
2086
|
const exists = await this.configExists();
|
|
2028
2087
|
if (exists) {
|
|
2029
|
-
await
|
|
2088
|
+
await fs8.unlink(this.configFile);
|
|
2030
2089
|
}
|
|
2031
2090
|
return true;
|
|
2032
2091
|
} catch (error) {
|
|
@@ -2709,7 +2768,7 @@ __export(session_tracker_exports, {
|
|
|
2709
2768
|
default: () => session_tracker_default,
|
|
2710
2769
|
sessionTracker: () => sessionTracker
|
|
2711
2770
|
});
|
|
2712
|
-
import
|
|
2771
|
+
import fs11 from "node:fs/promises";
|
|
2713
2772
|
import path10 from "node:path";
|
|
2714
2773
|
var SESSION_FILENAME, DEFAULT_IDLE_TIMEOUT_MS, MAX_COMMAND_HISTORY, MAX_FILE_HISTORY, SessionTracker, sessionTracker, session_tracker_default;
|
|
2715
2774
|
var init_session_tracker = __esm({
|
|
@@ -2735,7 +2794,7 @@ var init_session_tracker = __esm({
|
|
|
2735
2794
|
async read(projectId) {
|
|
2736
2795
|
const filePath = this.getPath(projectId);
|
|
2737
2796
|
try {
|
|
2738
|
-
const content = await
|
|
2797
|
+
const content = await fs11.readFile(filePath, "utf-8");
|
|
2739
2798
|
return JSON.parse(content);
|
|
2740
2799
|
} catch (error) {
|
|
2741
2800
|
if (isNotFoundError(error) || error instanceof SyntaxError) {
|
|
@@ -2749,8 +2808,8 @@ var init_session_tracker = __esm({
|
|
|
2749
2808
|
*/
|
|
2750
2809
|
async write(projectId, data) {
|
|
2751
2810
|
const filePath = this.getPath(projectId);
|
|
2752
|
-
await
|
|
2753
|
-
await
|
|
2811
|
+
await fs11.mkdir(path10.dirname(filePath), { recursive: true });
|
|
2812
|
+
await fs11.writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
2754
2813
|
}
|
|
2755
2814
|
getDefault() {
|
|
2756
2815
|
return {
|
|
@@ -2912,7 +2971,7 @@ var start_exports = {};
|
|
|
2912
2971
|
__export(start_exports, {
|
|
2913
2972
|
runStart: () => runStart
|
|
2914
2973
|
});
|
|
2915
|
-
import
|
|
2974
|
+
import fs12 from "node:fs/promises";
|
|
2916
2975
|
import os5 from "node:os";
|
|
2917
2976
|
import path11 from "node:path";
|
|
2918
2977
|
import chalk3 from "chalk";
|
|
@@ -3018,14 +3077,14 @@ async function installRouter(provider) {
|
|
|
3018
3077
|
}
|
|
3019
3078
|
try {
|
|
3020
3079
|
const commandsDir = path11.join(config.configDir, "commands");
|
|
3021
|
-
await
|
|
3080
|
+
await fs12.mkdir(commandsDir, { recursive: true });
|
|
3022
3081
|
const { getPackageRoot: getPackageRoot2 } = await Promise.resolve().then(() => (init_version(), version_exports));
|
|
3023
3082
|
const packageRoot = getPackageRoot2();
|
|
3024
3083
|
const routerFile = provider === "claude" ? "p.md" : "p.toml";
|
|
3025
3084
|
const src = path11.join(packageRoot, "templates", "commands", routerFile);
|
|
3026
3085
|
const dest = path11.join(commandsDir, routerFile);
|
|
3027
3086
|
if (await fileExists(src)) {
|
|
3028
|
-
await
|
|
3087
|
+
await fs12.copyFile(src, dest);
|
|
3029
3088
|
return true;
|
|
3030
3089
|
}
|
|
3031
3090
|
return false;
|
|
@@ -3042,16 +3101,16 @@ async function installGlobalConfig(provider) {
|
|
|
3042
3101
|
return false;
|
|
3043
3102
|
}
|
|
3044
3103
|
try {
|
|
3045
|
-
await
|
|
3104
|
+
await fs12.mkdir(config.configDir, { recursive: true });
|
|
3046
3105
|
const { getPackageRoot: getPackageRoot2 } = await Promise.resolve().then(() => (init_version(), version_exports));
|
|
3047
3106
|
const packageRoot = getPackageRoot2();
|
|
3048
3107
|
const configFile = provider === "claude" ? "CLAUDE.md" : "GEMINI.md";
|
|
3049
3108
|
const src = path11.join(packageRoot, "templates", "global", configFile);
|
|
3050
3109
|
const dest = path11.join(config.configDir, configFile);
|
|
3051
3110
|
if (await fileExists(src)) {
|
|
3052
|
-
const content = await
|
|
3111
|
+
const content = await fs12.readFile(src, "utf-8");
|
|
3053
3112
|
if (await fileExists(dest)) {
|
|
3054
|
-
const existing = await
|
|
3113
|
+
const existing = await fs12.readFile(dest, "utf-8");
|
|
3055
3114
|
const startMarker = "<!-- prjct:start - DO NOT REMOVE THIS MARKER -->";
|
|
3056
3115
|
const endMarker = "<!-- prjct:end - DO NOT REMOVE THIS MARKER -->";
|
|
3057
3116
|
if (existing.includes(startMarker) && existing.includes(endMarker)) {
|
|
@@ -3061,14 +3120,14 @@ async function installGlobalConfig(provider) {
|
|
|
3061
3120
|
content.indexOf(startMarker),
|
|
3062
3121
|
content.indexOf(endMarker) + endMarker.length
|
|
3063
3122
|
);
|
|
3064
|
-
await
|
|
3123
|
+
await fs12.writeFile(dest, before + prjctSection + after);
|
|
3065
3124
|
} else {
|
|
3066
|
-
await
|
|
3125
|
+
await fs12.writeFile(dest, `${existing}
|
|
3067
3126
|
|
|
3068
3127
|
${content}`);
|
|
3069
3128
|
}
|
|
3070
3129
|
} else {
|
|
3071
|
-
await
|
|
3130
|
+
await fs12.writeFile(dest, content);
|
|
3072
3131
|
}
|
|
3073
3132
|
return true;
|
|
3074
3133
|
}
|
|
@@ -3082,7 +3141,7 @@ ${content}`);
|
|
|
3082
3141
|
}
|
|
3083
3142
|
async function saveSetupConfig(providers) {
|
|
3084
3143
|
const configDir = path11.join(os5.homedir(), ".prjct-cli", "config");
|
|
3085
|
-
await
|
|
3144
|
+
await fs12.mkdir(configDir, { recursive: true });
|
|
3086
3145
|
const configPath = path11.join(configDir, "installed-editors.json");
|
|
3087
3146
|
const config = {
|
|
3088
3147
|
version: VERSION,
|
|
@@ -3093,7 +3152,7 @@ async function saveSetupConfig(providers) {
|
|
|
3093
3152
|
lastInstall: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3094
3153
|
path: path11.join(os5.homedir(), `.${providers[0]}`, "commands")
|
|
3095
3154
|
};
|
|
3096
|
-
await
|
|
3155
|
+
await fs12.writeFile(configPath, JSON.stringify(config, null, 2));
|
|
3097
3156
|
}
|
|
3098
3157
|
function showCompletion(providers) {
|
|
3099
3158
|
console.log(`
|
|
@@ -3123,7 +3182,7 @@ async function runStart() {
|
|
|
3123
3182
|
showBanner();
|
|
3124
3183
|
const configPath = path11.join(os5.homedir(), ".prjct-cli", "config", "installed-editors.json");
|
|
3125
3184
|
if (await fileExists(configPath)) {
|
|
3126
|
-
const existing = JSON.parse(await
|
|
3185
|
+
const existing = JSON.parse(await fs12.readFile(configPath, "utf-8"));
|
|
3127
3186
|
if (existing.version === VERSION) {
|
|
3128
3187
|
console.log(` ${chalk3.yellow("\u2139")} Already configured for v${VERSION}`);
|
|
3129
3188
|
console.log(` ${chalk3.dim("Run with --force to reconfigure")}
|
|
@@ -3477,7 +3536,7 @@ var init_cache = __esm({
|
|
|
3477
3536
|
});
|
|
3478
3537
|
|
|
3479
3538
|
// core/storage/storage-manager.ts
|
|
3480
|
-
import
|
|
3539
|
+
import fs13 from "node:fs/promises";
|
|
3481
3540
|
import path12 from "node:path";
|
|
3482
3541
|
var StorageManager;
|
|
3483
3542
|
var init_storage_manager = __esm({
|
|
@@ -3488,15 +3547,18 @@ var init_storage_manager = __esm({
|
|
|
3488
3547
|
init_fs();
|
|
3489
3548
|
init_cache();
|
|
3490
3549
|
init_date_helper();
|
|
3550
|
+
init_safe_reader();
|
|
3491
3551
|
StorageManager = class {
|
|
3492
3552
|
static {
|
|
3493
3553
|
__name(this, "StorageManager");
|
|
3494
3554
|
}
|
|
3495
3555
|
filename;
|
|
3496
3556
|
cache;
|
|
3497
|
-
|
|
3557
|
+
schema;
|
|
3558
|
+
constructor(filename, schema) {
|
|
3498
3559
|
this.filename = filename;
|
|
3499
3560
|
this.cache = new TTLCache({ ttl: 5e3, maxSize: 50 });
|
|
3561
|
+
this.schema = schema ?? null;
|
|
3500
3562
|
}
|
|
3501
3563
|
/**
|
|
3502
3564
|
* Get file path for storage JSON
|
|
@@ -3513,7 +3575,9 @@ var init_storage_manager = __esm({
|
|
|
3513
3575
|
return path_manager_default.getFilePath(projectId, layer, mdFilename);
|
|
3514
3576
|
}
|
|
3515
3577
|
/**
|
|
3516
|
-
* Read data from storage
|
|
3578
|
+
* Read data from storage with optional Zod validation.
|
|
3579
|
+
* When a schema is provided (via constructor), validates after JSON.parse.
|
|
3580
|
+
* On corruption: creates .backup file, logs warning, returns default.
|
|
3517
3581
|
*/
|
|
3518
3582
|
async read(projectId) {
|
|
3519
3583
|
const cached = this.cache.get(projectId);
|
|
@@ -3521,8 +3585,16 @@ var init_storage_manager = __esm({
|
|
|
3521
3585
|
return cached;
|
|
3522
3586
|
}
|
|
3523
3587
|
const filePath = this.getStoragePath(projectId);
|
|
3588
|
+
if (this.schema) {
|
|
3589
|
+
const data = await safeRead(filePath, this.schema);
|
|
3590
|
+
if (data !== null) {
|
|
3591
|
+
this.cache.set(projectId, data);
|
|
3592
|
+
return data;
|
|
3593
|
+
}
|
|
3594
|
+
return this.getDefault();
|
|
3595
|
+
}
|
|
3524
3596
|
try {
|
|
3525
|
-
const content = await
|
|
3597
|
+
const content = await fs13.readFile(filePath, "utf-8");
|
|
3526
3598
|
const data = JSON.parse(content);
|
|
3527
3599
|
this.cache.set(projectId, data);
|
|
3528
3600
|
return data;
|
|
@@ -3539,13 +3611,13 @@ var init_storage_manager = __esm({
|
|
|
3539
3611
|
async write(projectId, data) {
|
|
3540
3612
|
const storagePath = this.getStoragePath(projectId);
|
|
3541
3613
|
const contextPath = this.getContextPath(projectId, this.getMdFilename());
|
|
3542
|
-
await
|
|
3543
|
-
await
|
|
3614
|
+
await fs13.mkdir(path12.dirname(storagePath), { recursive: true });
|
|
3615
|
+
await fs13.mkdir(path12.dirname(contextPath), { recursive: true });
|
|
3544
3616
|
const tempPath = `${storagePath}.${Date.now()}.tmp`;
|
|
3545
|
-
await
|
|
3546
|
-
await
|
|
3617
|
+
await fs13.writeFile(tempPath, JSON.stringify(data, null, 2), "utf-8");
|
|
3618
|
+
await fs13.rename(tempPath, storagePath);
|
|
3547
3619
|
const md2 = this.toMarkdown(data);
|
|
3548
|
-
await
|
|
3620
|
+
await fs13.writeFile(contextPath, md2, "utf-8");
|
|
3549
3621
|
this.cache.set(projectId, data);
|
|
3550
3622
|
}
|
|
3551
3623
|
/**
|
|
@@ -3593,7 +3665,7 @@ var init_storage_manager = __esm({
|
|
|
3593
3665
|
async exists(projectId) {
|
|
3594
3666
|
const filePath = this.getStoragePath(projectId);
|
|
3595
3667
|
try {
|
|
3596
|
-
await
|
|
3668
|
+
await fs13.access(filePath);
|
|
3597
3669
|
return true;
|
|
3598
3670
|
} catch (error) {
|
|
3599
3671
|
if (isNotFoundError(error)) {
|
|
@@ -3635,7 +3707,7 @@ var init_metrics_storage = __esm({
|
|
|
3635
3707
|
__name(this, "MetricsStorage");
|
|
3636
3708
|
}
|
|
3637
3709
|
constructor() {
|
|
3638
|
-
super("metrics.json");
|
|
3710
|
+
super("metrics.json", MetricsJsonSchema);
|
|
3639
3711
|
}
|
|
3640
3712
|
getDefault() {
|
|
3641
3713
|
return { ...DEFAULT_METRICS };
|
|
@@ -3855,7 +3927,7 @@ var init_metrics_storage = __esm({
|
|
|
3855
3927
|
|
|
3856
3928
|
// core/context-tools/files-tool.ts
|
|
3857
3929
|
import { exec as execCallback2 } from "node:child_process";
|
|
3858
|
-
import
|
|
3930
|
+
import fs14 from "node:fs/promises";
|
|
3859
3931
|
import path13 from "node:path";
|
|
3860
3932
|
import { promisify as promisify3 } from "node:util";
|
|
3861
3933
|
async function findRelevantFiles(taskDescription, projectPath, options = {}) {
|
|
@@ -3985,7 +4057,7 @@ async function getAllCodeFiles(projectPath) {
|
|
|
3985
4057
|
const files = [];
|
|
3986
4058
|
async function walk(dir, relativePath = "") {
|
|
3987
4059
|
try {
|
|
3988
|
-
const entries = await
|
|
4060
|
+
const entries = await fs14.readdir(dir, { withFileTypes: true });
|
|
3989
4061
|
for (const entry of entries) {
|
|
3990
4062
|
const fullPath = path13.join(dir, entry.name);
|
|
3991
4063
|
const relPath = path13.join(relativePath, entry.name);
|
|
@@ -4289,14 +4361,14 @@ var init_files_tool = __esm({
|
|
|
4289
4361
|
|
|
4290
4362
|
// core/context-tools/imports-tool.ts
|
|
4291
4363
|
import { exec as execCallback3 } from "node:child_process";
|
|
4292
|
-
import
|
|
4364
|
+
import fs15 from "node:fs/promises";
|
|
4293
4365
|
import path14 from "node:path";
|
|
4294
4366
|
import { promisify as promisify4 } from "node:util";
|
|
4295
4367
|
async function analyzeImports(filePath, projectPath = process.cwd(), options = {}) {
|
|
4296
4368
|
const absolutePath = path14.isAbsolute(filePath) ? filePath : path14.join(projectPath, filePath);
|
|
4297
4369
|
let content;
|
|
4298
4370
|
try {
|
|
4299
|
-
content = await
|
|
4371
|
+
content = await fs15.readFile(absolutePath, "utf-8");
|
|
4300
4372
|
} catch (error) {
|
|
4301
4373
|
if (isNotFoundError(error)) {
|
|
4302
4374
|
return {
|
|
@@ -4388,7 +4460,7 @@ async function tryResolve(basePath, projectPath) {
|
|
|
4388
4460
|
for (const ext of extensions) {
|
|
4389
4461
|
const fullPath = basePath + ext;
|
|
4390
4462
|
try {
|
|
4391
|
-
const stat = await
|
|
4463
|
+
const stat = await fs15.stat(fullPath);
|
|
4392
4464
|
if (stat.isFile()) {
|
|
4393
4465
|
return path14.relative(projectPath, fullPath);
|
|
4394
4466
|
}
|
|
@@ -4917,13 +4989,13 @@ var init_token_counter = __esm({
|
|
|
4917
4989
|
});
|
|
4918
4990
|
|
|
4919
4991
|
// core/context-tools/signatures-tool.ts
|
|
4920
|
-
import
|
|
4992
|
+
import fs16 from "node:fs/promises";
|
|
4921
4993
|
import path15 from "node:path";
|
|
4922
4994
|
async function extractSignatures(filePath, projectPath = process.cwd()) {
|
|
4923
4995
|
const absolutePath = path15.isAbsolute(filePath) ? filePath : path15.join(projectPath, filePath);
|
|
4924
4996
|
let content;
|
|
4925
4997
|
try {
|
|
4926
|
-
content = await
|
|
4998
|
+
content = await fs16.readFile(absolutePath, "utf-8");
|
|
4927
4999
|
} catch (error) {
|
|
4928
5000
|
if (isNotFoundError(error)) {
|
|
4929
5001
|
return {
|
|
@@ -4967,7 +5039,7 @@ async function extractDirectorySignatures(dirPath, projectPath = process.cwd(),
|
|
|
4967
5039
|
const absolutePath = path15.isAbsolute(dirPath) ? dirPath : path15.join(projectPath, dirPath);
|
|
4968
5040
|
const results = [];
|
|
4969
5041
|
async function processDir(dir) {
|
|
4970
|
-
const entries = await
|
|
5042
|
+
const entries = await fs16.readdir(dir, { withFileTypes: true });
|
|
4971
5043
|
for (const entry of entries) {
|
|
4972
5044
|
const fullPath = path15.join(dir, entry.name);
|
|
4973
5045
|
const relativePath = path15.relative(projectPath, fullPath);
|
|
@@ -5269,13 +5341,13 @@ var init_signatures_tool = __esm({
|
|
|
5269
5341
|
});
|
|
5270
5342
|
|
|
5271
5343
|
// core/context-tools/summary-tool.ts
|
|
5272
|
-
import
|
|
5344
|
+
import fs17 from "node:fs/promises";
|
|
5273
5345
|
import path16 from "node:path";
|
|
5274
5346
|
async function summarizeFile(filePath, projectPath = process.cwd()) {
|
|
5275
5347
|
const absolutePath = path16.isAbsolute(filePath) ? filePath : path16.join(projectPath, filePath);
|
|
5276
5348
|
let content;
|
|
5277
5349
|
try {
|
|
5278
|
-
content = await
|
|
5350
|
+
content = await fs17.readFile(absolutePath, "utf-8");
|
|
5279
5351
|
} catch (error) {
|
|
5280
5352
|
if (isNotFoundError(error)) {
|
|
5281
5353
|
return {
|
|
@@ -5313,7 +5385,7 @@ async function summarizeDirectory(dirPath, projectPath = process.cwd(), options
|
|
|
5313
5385
|
const absolutePath = path16.isAbsolute(dirPath) ? dirPath : path16.join(projectPath, dirPath);
|
|
5314
5386
|
const results = [];
|
|
5315
5387
|
async function processDir(dir) {
|
|
5316
|
-
const entries = await
|
|
5388
|
+
const entries = await fs17.readdir(dir, { withFileTypes: true });
|
|
5317
5389
|
for (const entry of entries) {
|
|
5318
5390
|
const fullPath = path16.join(dir, entry.name);
|
|
5319
5391
|
const relativePath = path16.relative(projectPath, fullPath);
|
|
@@ -5575,11 +5647,11 @@ async function runSignaturesTool(args2, projectPath) {
|
|
|
5575
5647
|
}
|
|
5576
5648
|
};
|
|
5577
5649
|
}
|
|
5578
|
-
const
|
|
5650
|
+
const fs53 = await import("node:fs/promises");
|
|
5579
5651
|
const path65 = await import("node:path");
|
|
5580
5652
|
const fullPath = path65.isAbsolute(filePath) ? filePath : path65.join(projectPath, filePath);
|
|
5581
5653
|
try {
|
|
5582
|
-
const stat = await
|
|
5654
|
+
const stat = await fs53.stat(fullPath);
|
|
5583
5655
|
if (stat.isDirectory()) {
|
|
5584
5656
|
const results = await extractDirectorySignatures(filePath, projectPath, {
|
|
5585
5657
|
recursive: args2.includes("--recursive") || args2.includes("-r")
|
|
@@ -5646,11 +5718,11 @@ async function runSummaryTool(args2, projectPath) {
|
|
|
5646
5718
|
}
|
|
5647
5719
|
};
|
|
5648
5720
|
}
|
|
5649
|
-
const
|
|
5721
|
+
const fs53 = await import("node:fs/promises");
|
|
5650
5722
|
const path65 = await import("node:path");
|
|
5651
5723
|
const fullPath = path65.isAbsolute(targetPath) ? targetPath : path65.join(projectPath, targetPath);
|
|
5652
5724
|
try {
|
|
5653
|
-
const stat = await
|
|
5725
|
+
const stat = await fs53.stat(fullPath);
|
|
5654
5726
|
if (stat.isDirectory()) {
|
|
5655
5727
|
const results = await summarizeDirectory(targetPath, projectPath, {
|
|
5656
5728
|
recursive: args2.includes("--recursive") || args2.includes("-r")
|
|
@@ -5810,7 +5882,7 @@ var hooks_service_exports = {};
|
|
|
5810
5882
|
__export(hooks_service_exports, {
|
|
5811
5883
|
hooksService: () => hooksService
|
|
5812
5884
|
});
|
|
5813
|
-
import
|
|
5885
|
+
import fs18 from "node:fs/promises";
|
|
5814
5886
|
import path17 from "node:path";
|
|
5815
5887
|
import chalk4 from "chalk";
|
|
5816
5888
|
function getPostCommitScript() {
|
|
@@ -5893,7 +5965,7 @@ function selectStrategy(detected) {
|
|
|
5893
5965
|
async function installLefthook(projectPath, hooks) {
|
|
5894
5966
|
const configFile = await fileExists(path17.join(projectPath, "lefthook.yml")) ? "lefthook.yml" : "lefthook.yaml";
|
|
5895
5967
|
const configPath = path17.join(projectPath, configFile);
|
|
5896
|
-
let content = await
|
|
5968
|
+
let content = await fs18.readFile(configPath, "utf-8");
|
|
5897
5969
|
for (const hook of hooks) {
|
|
5898
5970
|
const sectionName = hook;
|
|
5899
5971
|
const commandName = `prjct-sync-${hook}`;
|
|
@@ -5922,7 +5994,7 @@ ${sectionName}:
|
|
|
5922
5994
|
${hookBlock}`;
|
|
5923
5995
|
}
|
|
5924
5996
|
}
|
|
5925
|
-
await
|
|
5997
|
+
await fs18.writeFile(configPath, content, "utf-8");
|
|
5926
5998
|
return true;
|
|
5927
5999
|
}
|
|
5928
6000
|
async function installHusky(projectPath, hooks) {
|
|
@@ -5931,13 +6003,13 @@ async function installHusky(projectPath, hooks) {
|
|
|
5931
6003
|
const hookPath = path17.join(huskyDir, hook);
|
|
5932
6004
|
const script = hook === "post-commit" ? getPostCommitScript() : getPostCheckoutScript();
|
|
5933
6005
|
if (await fileExists(hookPath)) {
|
|
5934
|
-
const existing = await
|
|
6006
|
+
const existing = await fs18.readFile(hookPath, "utf-8");
|
|
5935
6007
|
if (existing.includes("prjct sync")) {
|
|
5936
6008
|
continue;
|
|
5937
6009
|
}
|
|
5938
|
-
await
|
|
6010
|
+
await fs18.appendFile(hookPath, "\n# prjct auto-sync\nprjct sync --quiet --yes &\n");
|
|
5939
6011
|
} else {
|
|
5940
|
-
await
|
|
6012
|
+
await fs18.writeFile(hookPath, script, { mode: 493 });
|
|
5941
6013
|
}
|
|
5942
6014
|
}
|
|
5943
6015
|
return true;
|
|
@@ -5945,24 +6017,24 @@ async function installHusky(projectPath, hooks) {
|
|
|
5945
6017
|
async function installDirect(projectPath, hooks) {
|
|
5946
6018
|
const hooksDir = path17.join(projectPath, ".git", "hooks");
|
|
5947
6019
|
if (!await fileExists(hooksDir)) {
|
|
5948
|
-
await
|
|
6020
|
+
await fs18.mkdir(hooksDir, { recursive: true });
|
|
5949
6021
|
}
|
|
5950
6022
|
for (const hook of hooks) {
|
|
5951
6023
|
const hookPath = path17.join(hooksDir, hook);
|
|
5952
6024
|
const script = hook === "post-commit" ? getPostCommitScript() : getPostCheckoutScript();
|
|
5953
6025
|
if (await fileExists(hookPath)) {
|
|
5954
|
-
const existing = await
|
|
6026
|
+
const existing = await fs18.readFile(hookPath, "utf-8");
|
|
5955
6027
|
if (existing.includes("prjct sync")) {
|
|
5956
6028
|
continue;
|
|
5957
6029
|
}
|
|
5958
|
-
await
|
|
6030
|
+
await fs18.appendFile(
|
|
5959
6031
|
hookPath,
|
|
5960
6032
|
`
|
|
5961
6033
|
# prjct auto-sync
|
|
5962
6034
|
${script.split("\n").slice(1).join("\n")}`
|
|
5963
6035
|
);
|
|
5964
6036
|
} else {
|
|
5965
|
-
await
|
|
6037
|
+
await fs18.writeFile(hookPath, script, { mode: 493 });
|
|
5966
6038
|
}
|
|
5967
6039
|
}
|
|
5968
6040
|
return true;
|
|
@@ -5971,10 +6043,10 @@ async function uninstallLefthook(projectPath) {
|
|
|
5971
6043
|
const configFile = await fileExists(path17.join(projectPath, "lefthook.yml")) ? "lefthook.yml" : "lefthook.yaml";
|
|
5972
6044
|
const configPath = path17.join(projectPath, configFile);
|
|
5973
6045
|
if (!await fileExists(configPath)) return false;
|
|
5974
|
-
let content = await
|
|
6046
|
+
let content = await fs18.readFile(configPath, "utf-8");
|
|
5975
6047
|
content = content.replace(/\s*prjct-sync-[\w-]+:[\s\S]*?(?=\n\S|\n*$)/g, "");
|
|
5976
6048
|
content = content.replace(/^(post-commit|post-checkout):\s*commands:\s*$/gm, "");
|
|
5977
|
-
await
|
|
6049
|
+
await fs18.writeFile(configPath, `${content.trimEnd()}
|
|
5978
6050
|
`, "utf-8");
|
|
5979
6051
|
return true;
|
|
5980
6052
|
}
|
|
@@ -5983,13 +6055,13 @@ async function uninstallHusky(projectPath) {
|
|
|
5983
6055
|
for (const hook of ["post-commit", "post-checkout"]) {
|
|
5984
6056
|
const hookPath = path17.join(huskyDir, hook);
|
|
5985
6057
|
if (!await fileExists(hookPath)) continue;
|
|
5986
|
-
const content = await
|
|
6058
|
+
const content = await fs18.readFile(hookPath, "utf-8");
|
|
5987
6059
|
if (!content.includes("prjct sync")) continue;
|
|
5988
6060
|
const cleaned = content.split("\n").filter((line) => !line.includes("prjct sync") && !line.includes("prjct auto-sync")).join("\n");
|
|
5989
6061
|
if (cleaned.trim() === "#!/bin/sh" || cleaned.trim() === "#!/usr/bin/env sh") {
|
|
5990
|
-
await
|
|
6062
|
+
await fs18.unlink(hookPath);
|
|
5991
6063
|
} else {
|
|
5992
|
-
await
|
|
6064
|
+
await fs18.writeFile(hookPath, cleaned, { mode: 493 });
|
|
5993
6065
|
}
|
|
5994
6066
|
}
|
|
5995
6067
|
return true;
|
|
@@ -5999,13 +6071,13 @@ async function uninstallDirect(projectPath) {
|
|
|
5999
6071
|
for (const hook of ["post-commit", "post-checkout"]) {
|
|
6000
6072
|
const hookPath = path17.join(hooksDir, hook);
|
|
6001
6073
|
if (!await fileExists(hookPath)) continue;
|
|
6002
|
-
const content = await
|
|
6074
|
+
const content = await fs18.readFile(hookPath, "utf-8");
|
|
6003
6075
|
if (!content.includes("prjct sync")) continue;
|
|
6004
6076
|
if (content.includes("Installed by: prjct hooks install")) {
|
|
6005
|
-
await
|
|
6077
|
+
await fs18.unlink(hookPath);
|
|
6006
6078
|
} else {
|
|
6007
6079
|
const cleaned = content.split("\n").filter((line) => !line.includes("prjct sync") && !line.includes("prjct auto-sync")).join("\n");
|
|
6008
|
-
await
|
|
6080
|
+
await fs18.writeFile(hookPath, cleaned, { mode: 493 });
|
|
6009
6081
|
}
|
|
6010
6082
|
}
|
|
6011
6083
|
return true;
|
|
@@ -6231,17 +6303,17 @@ var init_hooks_service = __esm({
|
|
|
6231
6303
|
const configFile = await fileExists(path17.join(projectPath, "lefthook.yml")) ? "lefthook.yml" : "lefthook.yaml";
|
|
6232
6304
|
const configPath = path17.join(projectPath, configFile);
|
|
6233
6305
|
if (!await fileExists(configPath)) return false;
|
|
6234
|
-
const content = await
|
|
6306
|
+
const content = await fs18.readFile(configPath, "utf-8");
|
|
6235
6307
|
return content.includes(`prjct-sync-${hook}`);
|
|
6236
6308
|
}
|
|
6237
6309
|
if (strategy === "husky") {
|
|
6238
6310
|
const hookPath2 = path17.join(projectPath, ".husky", hook);
|
|
6239
6311
|
if (!await fileExists(hookPath2)) return false;
|
|
6240
|
-
return (await
|
|
6312
|
+
return (await fs18.readFile(hookPath2, "utf-8")).includes("prjct sync");
|
|
6241
6313
|
}
|
|
6242
6314
|
const hookPath = path17.join(projectPath, ".git", "hooks", hook);
|
|
6243
6315
|
if (!await fileExists(hookPath)) return false;
|
|
6244
|
-
return (await
|
|
6316
|
+
return (await fs18.readFile(hookPath, "utf-8")).includes("prjct sync");
|
|
6245
6317
|
}
|
|
6246
6318
|
async getHookPath(projectPath, hook, strategy) {
|
|
6247
6319
|
if (strategy === "lefthook") {
|
|
@@ -6264,7 +6336,7 @@ var init_hooks_service = __esm({
|
|
|
6264
6336
|
"project.json"
|
|
6265
6337
|
);
|
|
6266
6338
|
if (!await fileExists(projectJsonPath)) return null;
|
|
6267
|
-
const project = JSON.parse(await
|
|
6339
|
+
const project = JSON.parse(await fs18.readFile(projectJsonPath, "utf-8"));
|
|
6268
6340
|
return project.hooks || null;
|
|
6269
6341
|
} catch {
|
|
6270
6342
|
return null;
|
|
@@ -6282,9 +6354,9 @@ var init_hooks_service = __esm({
|
|
|
6282
6354
|
"project.json"
|
|
6283
6355
|
);
|
|
6284
6356
|
if (!await fileExists(projectJsonPath)) return;
|
|
6285
|
-
const project = JSON.parse(await
|
|
6357
|
+
const project = JSON.parse(await fs18.readFile(projectJsonPath, "utf-8"));
|
|
6286
6358
|
project.hooks = config;
|
|
6287
|
-
await
|
|
6359
|
+
await fs18.writeFile(projectJsonPath, JSON.stringify(project, null, 2));
|
|
6288
6360
|
} catch {
|
|
6289
6361
|
}
|
|
6290
6362
|
}
|
|
@@ -6300,7 +6372,7 @@ __export(doctor_service_exports, {
|
|
|
6300
6372
|
doctorService: () => doctorService
|
|
6301
6373
|
});
|
|
6302
6374
|
import { execSync } from "node:child_process";
|
|
6303
|
-
import
|
|
6375
|
+
import fs19 from "node:fs/promises";
|
|
6304
6376
|
import path18 from "node:path";
|
|
6305
6377
|
import chalk5 from "chalk";
|
|
6306
6378
|
var DoctorService, doctorService;
|
|
@@ -6416,7 +6488,7 @@ var init_doctor_service = __esm({
|
|
|
6416
6488
|
async checkPrjctConfig() {
|
|
6417
6489
|
const configPath = path18.join(this.projectPath, ".prjct", "prjct.config.json");
|
|
6418
6490
|
try {
|
|
6419
|
-
await
|
|
6491
|
+
await fs19.access(configPath);
|
|
6420
6492
|
return {
|
|
6421
6493
|
name: "prjct config",
|
|
6422
6494
|
status: "ok",
|
|
@@ -6440,7 +6512,7 @@ var init_doctor_service = __esm({
|
|
|
6440
6512
|
}
|
|
6441
6513
|
const claudePath = path18.join(this.globalPath, "context", "CLAUDE.md");
|
|
6442
6514
|
try {
|
|
6443
|
-
const stat = await
|
|
6515
|
+
const stat = await fs19.stat(claudePath);
|
|
6444
6516
|
const ageMs = Date.now() - stat.mtimeMs;
|
|
6445
6517
|
const ageHours = Math.floor(ageMs / (1e3 * 60 * 60));
|
|
6446
6518
|
const ageDays = Math.floor(ageHours / 24);
|
|
@@ -6514,7 +6586,7 @@ var init_doctor_service = __esm({
|
|
|
6514
6586
|
}
|
|
6515
6587
|
const statePath = path18.join(this.globalPath, "storage", "state.json");
|
|
6516
6588
|
try {
|
|
6517
|
-
const content = await
|
|
6589
|
+
const content = await fs19.readFile(statePath, "utf-8");
|
|
6518
6590
|
const state = JSON.parse(content);
|
|
6519
6591
|
if (state.currentTask) {
|
|
6520
6592
|
return {
|
|
@@ -6611,13 +6683,13 @@ var init_doctor_service = __esm({
|
|
|
6611
6683
|
});
|
|
6612
6684
|
|
|
6613
6685
|
// core/infrastructure/command-installer.ts
|
|
6614
|
-
import
|
|
6686
|
+
import fs20 from "node:fs/promises";
|
|
6615
6687
|
import os6 from "node:os";
|
|
6616
6688
|
import path19 from "node:path";
|
|
6617
6689
|
async function loadModuleConfig() {
|
|
6618
6690
|
try {
|
|
6619
6691
|
const configPath = path19.join(PACKAGE_ROOT, "templates/global/modules/module-config.json");
|
|
6620
|
-
const content = await
|
|
6692
|
+
const content = await fs20.readFile(configPath, "utf-8");
|
|
6621
6693
|
return JSON.parse(content);
|
|
6622
6694
|
} catch {
|
|
6623
6695
|
return null;
|
|
@@ -6628,7 +6700,7 @@ async function composeGlobalTemplate(profile) {
|
|
|
6628
6700
|
const modulesDir = path19.join(PACKAGE_ROOT, "templates/global/modules");
|
|
6629
6701
|
if (!config) {
|
|
6630
6702
|
const legacyPath = path19.join(PACKAGE_ROOT, "templates/global/CLAUDE.md");
|
|
6631
|
-
return
|
|
6703
|
+
return fs20.readFile(legacyPath, "utf-8");
|
|
6632
6704
|
}
|
|
6633
6705
|
const profileName = profile || config.default;
|
|
6634
6706
|
const selectedProfile = config.profiles[profileName];
|
|
@@ -6636,7 +6708,7 @@ async function composeGlobalTemplate(profile) {
|
|
|
6636
6708
|
const defaultProfile = config.profiles[config.default];
|
|
6637
6709
|
if (!defaultProfile) {
|
|
6638
6710
|
const legacyPath = path19.join(PACKAGE_ROOT, "templates/global/CLAUDE.md");
|
|
6639
|
-
return
|
|
6711
|
+
return fs20.readFile(legacyPath, "utf-8");
|
|
6640
6712
|
}
|
|
6641
6713
|
}
|
|
6642
6714
|
const modules = (selectedProfile || config.profiles[config.default]).modules;
|
|
@@ -6645,7 +6717,7 @@ async function composeGlobalTemplate(profile) {
|
|
|
6645
6717
|
for (const moduleName of modules) {
|
|
6646
6718
|
try {
|
|
6647
6719
|
const modulePath = path19.join(modulesDir, moduleName);
|
|
6648
|
-
const content = await
|
|
6720
|
+
const content = await fs20.readFile(modulePath, "utf-8");
|
|
6649
6721
|
parts.push("");
|
|
6650
6722
|
parts.push(content);
|
|
6651
6723
|
} catch {
|
|
@@ -6661,14 +6733,14 @@ async function installDocs() {
|
|
|
6661
6733
|
try {
|
|
6662
6734
|
const docsDir = path19.join(os6.homedir(), ".prjct-cli", "docs");
|
|
6663
6735
|
const templateDocsDir = path19.join(PACKAGE_ROOT, "templates/global/docs");
|
|
6664
|
-
await
|
|
6665
|
-
const docFiles = await
|
|
6736
|
+
await fs20.mkdir(docsDir, { recursive: true });
|
|
6737
|
+
const docFiles = await fs20.readdir(templateDocsDir);
|
|
6666
6738
|
for (const file of docFiles) {
|
|
6667
6739
|
if (file.endsWith(".md")) {
|
|
6668
6740
|
const srcPath = path19.join(templateDocsDir, file);
|
|
6669
6741
|
const destPath = path19.join(docsDir, file);
|
|
6670
|
-
const content = await
|
|
6671
|
-
await
|
|
6742
|
+
const content = await fs20.readFile(srcPath, "utf-8");
|
|
6743
|
+
await fs20.writeFile(destPath, content, "utf-8");
|
|
6672
6744
|
}
|
|
6673
6745
|
}
|
|
6674
6746
|
return { success: true };
|
|
@@ -6689,23 +6761,23 @@ async function installGlobalConfig2() {
|
|
|
6689
6761
|
};
|
|
6690
6762
|
}
|
|
6691
6763
|
try {
|
|
6692
|
-
await
|
|
6764
|
+
await fs20.mkdir(activeProvider.configDir, { recursive: true });
|
|
6693
6765
|
const globalConfigPath = path19.join(activeProvider.configDir, activeProvider.contextFile);
|
|
6694
6766
|
const templatePath = path19.join(PACKAGE_ROOT, "templates", "global", activeProvider.contextFile);
|
|
6695
6767
|
let templateContent = "";
|
|
6696
6768
|
try {
|
|
6697
|
-
templateContent = await
|
|
6769
|
+
templateContent = await fs20.readFile(templatePath, "utf-8");
|
|
6698
6770
|
} catch (_error) {
|
|
6699
6771
|
if (providerName === "claude") {
|
|
6700
6772
|
try {
|
|
6701
6773
|
templateContent = await composeGlobalTemplate("standard");
|
|
6702
6774
|
} catch {
|
|
6703
6775
|
const fallbackTemplatePath = path19.join(PACKAGE_ROOT, "templates/global/CLAUDE.md");
|
|
6704
|
-
templateContent = await
|
|
6776
|
+
templateContent = await fs20.readFile(fallbackTemplatePath, "utf-8");
|
|
6705
6777
|
}
|
|
6706
6778
|
} else {
|
|
6707
6779
|
const fallbackTemplatePath = path19.join(PACKAGE_ROOT, "templates/global/CLAUDE.md");
|
|
6708
|
-
templateContent = await
|
|
6780
|
+
templateContent = await fs20.readFile(fallbackTemplatePath, "utf-8");
|
|
6709
6781
|
if (providerName === "gemini") {
|
|
6710
6782
|
templateContent = templateContent.replace(/Claude/g, "Gemini");
|
|
6711
6783
|
}
|
|
@@ -6714,7 +6786,7 @@ async function installGlobalConfig2() {
|
|
|
6714
6786
|
let existingContent = "";
|
|
6715
6787
|
let fileExists3 = false;
|
|
6716
6788
|
try {
|
|
6717
|
-
existingContent = await
|
|
6789
|
+
existingContent = await fs20.readFile(globalConfigPath, "utf-8");
|
|
6718
6790
|
fileExists3 = true;
|
|
6719
6791
|
} catch (error) {
|
|
6720
6792
|
if (isNotFoundError(error)) {
|
|
@@ -6724,7 +6796,7 @@ async function installGlobalConfig2() {
|
|
|
6724
6796
|
}
|
|
6725
6797
|
}
|
|
6726
6798
|
if (!fileExists3) {
|
|
6727
|
-
await
|
|
6799
|
+
await fs20.writeFile(globalConfigPath, templateContent, "utf-8");
|
|
6728
6800
|
return {
|
|
6729
6801
|
success: true,
|
|
6730
6802
|
action: "created",
|
|
@@ -6738,7 +6810,7 @@ async function installGlobalConfig2() {
|
|
|
6738
6810
|
const updatedContent = `${existingContent}
|
|
6739
6811
|
|
|
6740
6812
|
${templateContent}`;
|
|
6741
|
-
await
|
|
6813
|
+
await fs20.writeFile(globalConfigPath, updatedContent, "utf-8");
|
|
6742
6814
|
return {
|
|
6743
6815
|
success: true,
|
|
6744
6816
|
action: "appended",
|
|
@@ -6754,7 +6826,7 @@ ${templateContent}`;
|
|
|
6754
6826
|
templateContent.indexOf(endMarker) + endMarker.length
|
|
6755
6827
|
);
|
|
6756
6828
|
const updatedContent = beforeMarker + prjctSection + afterMarker;
|
|
6757
|
-
await
|
|
6829
|
+
await fs20.writeFile(globalConfigPath, updatedContent, "utf-8");
|
|
6758
6830
|
return {
|
|
6759
6831
|
success: true,
|
|
6760
6832
|
action: "updated",
|
|
@@ -6826,7 +6898,7 @@ var init_command_installer = __esm({
|
|
|
6826
6898
|
async detectActiveProvider() {
|
|
6827
6899
|
await this.ensureInit();
|
|
6828
6900
|
try {
|
|
6829
|
-
await
|
|
6901
|
+
await fs20.access(this.claudeConfigPath);
|
|
6830
6902
|
return true;
|
|
6831
6903
|
} catch (error) {
|
|
6832
6904
|
if (isNotFoundError(error)) {
|
|
@@ -6846,7 +6918,7 @@ var init_command_installer = __esm({
|
|
|
6846
6918
|
*/
|
|
6847
6919
|
async getCommandFiles() {
|
|
6848
6920
|
try {
|
|
6849
|
-
const files = await
|
|
6921
|
+
const files = await fs20.readdir(this.templatesDir);
|
|
6850
6922
|
return files.filter((f) => f.endsWith(".md"));
|
|
6851
6923
|
} catch (_error) {
|
|
6852
6924
|
return [
|
|
@@ -6887,7 +6959,7 @@ var init_command_installer = __esm({
|
|
|
6887
6959
|
}
|
|
6888
6960
|
try {
|
|
6889
6961
|
await this.installRouter();
|
|
6890
|
-
await
|
|
6962
|
+
await fs20.mkdir(this.claudeCommandsPath, { recursive: true });
|
|
6891
6963
|
const commandFiles = await this.getCommandFiles();
|
|
6892
6964
|
const installed = [];
|
|
6893
6965
|
const errors = [];
|
|
@@ -6895,8 +6967,8 @@ var init_command_installer = __esm({
|
|
|
6895
6967
|
try {
|
|
6896
6968
|
const sourcePath = path19.join(this.templatesDir, file);
|
|
6897
6969
|
const destPath = path19.join(this.claudeCommandsPath, file);
|
|
6898
|
-
const content = await
|
|
6899
|
-
await
|
|
6970
|
+
const content = await fs20.readFile(sourcePath, "utf-8");
|
|
6971
|
+
await fs20.writeFile(destPath, content, "utf-8");
|
|
6900
6972
|
installed.push(file.replace(".md", ""));
|
|
6901
6973
|
} catch (error) {
|
|
6902
6974
|
errors.push({ file, error: getErrorMessage2(error) });
|
|
@@ -6926,7 +6998,7 @@ var init_command_installer = __esm({
|
|
|
6926
6998
|
for (const file of commandFiles) {
|
|
6927
6999
|
try {
|
|
6928
7000
|
const filePath = path19.join(this.claudeCommandsPath, file);
|
|
6929
|
-
await
|
|
7001
|
+
await fs20.unlink(filePath);
|
|
6930
7002
|
uninstalled.push(file.replace(".md", ""));
|
|
6931
7003
|
} catch (error) {
|
|
6932
7004
|
if (error.code !== "ENOENT") {
|
|
@@ -6935,7 +7007,7 @@ var init_command_installer = __esm({
|
|
|
6935
7007
|
}
|
|
6936
7008
|
}
|
|
6937
7009
|
try {
|
|
6938
|
-
await
|
|
7010
|
+
await fs20.rmdir(this.claudeCommandsPath);
|
|
6939
7011
|
} catch (_error) {
|
|
6940
7012
|
}
|
|
6941
7013
|
return {
|
|
@@ -6962,8 +7034,8 @@ var init_command_installer = __esm({
|
|
|
6962
7034
|
};
|
|
6963
7035
|
}
|
|
6964
7036
|
try {
|
|
6965
|
-
await
|
|
6966
|
-
const files = await
|
|
7037
|
+
await fs20.access(this.claudeCommandsPath);
|
|
7038
|
+
const files = await fs20.readdir(this.claudeCommandsPath);
|
|
6967
7039
|
const installedCommands = files.filter((f) => f.endsWith(".md")).map((f) => f.replace(".md", ""));
|
|
6968
7040
|
return {
|
|
6969
7041
|
installed: installedCommands.length > 0,
|
|
@@ -7012,7 +7084,7 @@ var init_command_installer = __esm({
|
|
|
7012
7084
|
async verifyTemplate(commandName) {
|
|
7013
7085
|
try {
|
|
7014
7086
|
const templatePath = path19.join(this.templatesDir, `${commandName}.md`);
|
|
7015
|
-
await
|
|
7087
|
+
await fs20.access(templatePath);
|
|
7016
7088
|
return true;
|
|
7017
7089
|
} catch (error) {
|
|
7018
7090
|
if (isNotFoundError(error)) {
|
|
@@ -7032,9 +7104,9 @@ var init_command_installer = __esm({
|
|
|
7032
7104
|
try {
|
|
7033
7105
|
const routerSource = path19.join(this.templatesDir, routerFile);
|
|
7034
7106
|
const routerDest = path19.join(activeProvider.configDir, "commands", routerFile);
|
|
7035
|
-
await
|
|
7036
|
-
const content = await
|
|
7037
|
-
await
|
|
7107
|
+
await fs20.mkdir(path19.dirname(routerDest), { recursive: true });
|
|
7108
|
+
const content = await fs20.readFile(routerSource, "utf-8");
|
|
7109
|
+
await fs20.writeFile(routerDest, content, "utf-8");
|
|
7038
7110
|
return true;
|
|
7039
7111
|
} catch (error) {
|
|
7040
7112
|
if (isNotFoundError(error)) {
|
|
@@ -7053,11 +7125,11 @@ var init_command_installer = __esm({
|
|
|
7053
7125
|
const commandsRoot = path19.join(activeProvider.configDir, "commands");
|
|
7054
7126
|
let removed = 0;
|
|
7055
7127
|
try {
|
|
7056
|
-
const files = await
|
|
7128
|
+
const files = await fs20.readdir(commandsRoot);
|
|
7057
7129
|
const legacyFiles = files.filter((f) => f.startsWith("p.") && f.endsWith(".md"));
|
|
7058
7130
|
for (const file of legacyFiles) {
|
|
7059
7131
|
try {
|
|
7060
|
-
await
|
|
7132
|
+
await fs20.unlink(path19.join(commandsRoot, file));
|
|
7061
7133
|
removed++;
|
|
7062
7134
|
} catch {
|
|
7063
7135
|
}
|
|
@@ -7082,11 +7154,11 @@ var init_command_installer = __esm({
|
|
|
7082
7154
|
}
|
|
7083
7155
|
try {
|
|
7084
7156
|
await this.installRouter();
|
|
7085
|
-
await
|
|
7157
|
+
await fs20.mkdir(this.claudeCommandsPath, { recursive: true });
|
|
7086
7158
|
const templateFiles = await this.getCommandFiles();
|
|
7087
7159
|
let installedFiles = [];
|
|
7088
7160
|
try {
|
|
7089
|
-
installedFiles = await
|
|
7161
|
+
installedFiles = await fs20.readdir(this.claudeCommandsPath);
|
|
7090
7162
|
installedFiles = installedFiles.filter((f) => f.endsWith(".md"));
|
|
7091
7163
|
} catch (error) {
|
|
7092
7164
|
if (isNotFoundError(error)) {
|
|
@@ -7107,8 +7179,8 @@ var init_command_installer = __esm({
|
|
|
7107
7179
|
const sourcePath = path19.join(this.templatesDir, file);
|
|
7108
7180
|
const destPath = path19.join(this.claudeCommandsPath, file);
|
|
7109
7181
|
const exists = installedFiles.includes(file);
|
|
7110
|
-
const content = await
|
|
7111
|
-
await
|
|
7182
|
+
const content = await fs20.readFile(sourcePath, "utf-8");
|
|
7183
|
+
await fs20.writeFile(destPath, content, "utf-8");
|
|
7112
7184
|
if (!exists) {
|
|
7113
7185
|
results.added++;
|
|
7114
7186
|
} else {
|
|
@@ -7492,7 +7564,7 @@ var init_chain_of_thought = __esm({
|
|
|
7492
7564
|
});
|
|
7493
7565
|
|
|
7494
7566
|
// core/agentic/context-builder.ts
|
|
7495
|
-
import
|
|
7567
|
+
import fs21 from "node:fs/promises";
|
|
7496
7568
|
var ContextBuilder, contextBuilder, context_builder_default;
|
|
7497
7569
|
var init_context_builder = __esm({
|
|
7498
7570
|
"core/agentic/context-builder.ts"() {
|
|
@@ -7571,7 +7643,7 @@ var init_context_builder = __esm({
|
|
|
7571
7643
|
for (const [, filePath] of filteredEntries) {
|
|
7572
7644
|
if (this._cache.has(filePath)) {
|
|
7573
7645
|
try {
|
|
7574
|
-
const stat = await
|
|
7646
|
+
const stat = await fs21.stat(filePath);
|
|
7575
7647
|
const cachedMtime = this._mtimes.get(filePath);
|
|
7576
7648
|
if (!cachedMtime || stat.mtimeMs > cachedMtime) {
|
|
7577
7649
|
this._cache.delete(filePath);
|
|
@@ -7599,8 +7671,8 @@ var init_context_builder = __esm({
|
|
|
7599
7671
|
const readPromises = uncachedEntries.map(async ([key, filePath]) => {
|
|
7600
7672
|
try {
|
|
7601
7673
|
const [content, stat] = await Promise.all([
|
|
7602
|
-
|
|
7603
|
-
|
|
7674
|
+
fs21.readFile(filePath, "utf-8"),
|
|
7675
|
+
fs21.stat(filePath)
|
|
7604
7676
|
]);
|
|
7605
7677
|
return { key, filePath, content, mtime: stat.mtimeMs };
|
|
7606
7678
|
} catch (error) {
|
|
@@ -7674,7 +7746,7 @@ var init_context_builder = __esm({
|
|
|
7674
7746
|
if (uncachedPaths.length > 0) {
|
|
7675
7747
|
const readPromises = uncachedPaths.map(async (filePath) => {
|
|
7676
7748
|
try {
|
|
7677
|
-
const content = await
|
|
7749
|
+
const content = await fs21.readFile(filePath, "utf-8");
|
|
7678
7750
|
return { filePath, content };
|
|
7679
7751
|
} catch (error) {
|
|
7680
7752
|
if (isNotFoundError(error)) {
|
|
@@ -7708,7 +7780,7 @@ var init_context_builder = __esm({
|
|
|
7708
7780
|
*/
|
|
7709
7781
|
async fileExists(filePath) {
|
|
7710
7782
|
try {
|
|
7711
|
-
await
|
|
7783
|
+
await fs21.access(filePath);
|
|
7712
7784
|
return true;
|
|
7713
7785
|
} catch (error) {
|
|
7714
7786
|
if (isNotFoundError(error)) {
|
|
@@ -7735,7 +7807,7 @@ var init_context_builder = __esm({
|
|
|
7735
7807
|
|
|
7736
7808
|
// core/agentic/ground-truth.ts
|
|
7737
7809
|
import { exec as exec6 } from "node:child_process";
|
|
7738
|
-
import
|
|
7810
|
+
import fs22 from "node:fs/promises";
|
|
7739
7811
|
import os7 from "node:os";
|
|
7740
7812
|
import path20 from "node:path";
|
|
7741
7813
|
import { promisify as promisify6 } from "node:util";
|
|
@@ -7774,7 +7846,7 @@ async function verifyDone(context2) {
|
|
|
7774
7846
|
const actual = {};
|
|
7775
7847
|
const nowPath = context2.paths.now;
|
|
7776
7848
|
try {
|
|
7777
|
-
const nowContent = await
|
|
7849
|
+
const nowContent = await fs22.readFile(nowPath, "utf-8");
|
|
7778
7850
|
actual.nowExists = true;
|
|
7779
7851
|
actual.nowContent = nowContent.trim();
|
|
7780
7852
|
actual.nowLength = nowContent.length;
|
|
@@ -7802,7 +7874,7 @@ async function verifyDone(context2) {
|
|
|
7802
7874
|
}
|
|
7803
7875
|
const nextPath = context2.paths.next;
|
|
7804
7876
|
try {
|
|
7805
|
-
const nextContent = await
|
|
7877
|
+
const nextContent = await fs22.readFile(nextPath, "utf-8");
|
|
7806
7878
|
actual.nextExists = true;
|
|
7807
7879
|
const tasks = nextContent.match(/- \[ \]/g) || [];
|
|
7808
7880
|
actual.pendingTasks = tasks.length;
|
|
@@ -7816,7 +7888,7 @@ async function verifyDone(context2) {
|
|
|
7816
7888
|
}
|
|
7817
7889
|
const metricsPath = context2.paths.metrics;
|
|
7818
7890
|
try {
|
|
7819
|
-
await
|
|
7891
|
+
await fs22.access(path20.dirname(metricsPath), fs22.constants.W_OK);
|
|
7820
7892
|
actual.metricsWritable = true;
|
|
7821
7893
|
} catch (error) {
|
|
7822
7894
|
if (isNotFoundError(error)) {
|
|
@@ -7852,7 +7924,7 @@ async function verifyShip(context2) {
|
|
|
7852
7924
|
}
|
|
7853
7925
|
const pkgPath = path20.join(context2.projectPath, "package.json");
|
|
7854
7926
|
try {
|
|
7855
|
-
const pkgContent = await
|
|
7927
|
+
const pkgContent = await fs22.readFile(pkgPath, "utf-8");
|
|
7856
7928
|
const pkg = JSON.parse(pkgContent);
|
|
7857
7929
|
actual.currentVersion = pkg.version;
|
|
7858
7930
|
actual.hasPackageJson = true;
|
|
@@ -7868,7 +7940,7 @@ async function verifyShip(context2) {
|
|
|
7868
7940
|
}
|
|
7869
7941
|
const shippedPath = context2.paths.shipped;
|
|
7870
7942
|
try {
|
|
7871
|
-
const shippedContent = await
|
|
7943
|
+
const shippedContent = await fs22.readFile(shippedPath, "utf-8");
|
|
7872
7944
|
actual.shippedExists = true;
|
|
7873
7945
|
const featureName = context2.params.feature || context2.params.description;
|
|
7874
7946
|
if (featureName) {
|
|
@@ -7888,7 +7960,7 @@ async function verifyShip(context2) {
|
|
|
7888
7960
|
}
|
|
7889
7961
|
if (actual.hasPackageJson) {
|
|
7890
7962
|
try {
|
|
7891
|
-
const pkgContent = await
|
|
7963
|
+
const pkgContent = await fs22.readFile(pkgPath, "utf-8");
|
|
7892
7964
|
const pkg = JSON.parse(pkgContent);
|
|
7893
7965
|
actual.hasTestScript = !!pkg.scripts?.test;
|
|
7894
7966
|
} catch (error) {
|
|
@@ -7912,7 +7984,7 @@ async function verifyFeature(context2) {
|
|
|
7912
7984
|
const actual = {};
|
|
7913
7985
|
const nextPath = context2.paths.next;
|
|
7914
7986
|
try {
|
|
7915
|
-
const nextContent = await
|
|
7987
|
+
const nextContent = await fs22.readFile(nextPath, "utf-8");
|
|
7916
7988
|
actual.nextExists = true;
|
|
7917
7989
|
const tasks = nextContent.match(/- \[[ x]\]/g) || [];
|
|
7918
7990
|
actual.taskCount = tasks.length;
|
|
@@ -7931,7 +8003,7 @@ async function verifyFeature(context2) {
|
|
|
7931
8003
|
}
|
|
7932
8004
|
const roadmapPath = context2.paths.roadmap;
|
|
7933
8005
|
try {
|
|
7934
|
-
const roadmapContent = await
|
|
8006
|
+
const roadmapContent = await fs22.readFile(roadmapPath, "utf-8");
|
|
7935
8007
|
actual.roadmapExists = true;
|
|
7936
8008
|
const featureName = context2.params.description || context2.params.feature;
|
|
7937
8009
|
if (featureName) {
|
|
@@ -7950,7 +8022,7 @@ async function verifyFeature(context2) {
|
|
|
7950
8022
|
}
|
|
7951
8023
|
const nowPath = context2.paths.now;
|
|
7952
8024
|
try {
|
|
7953
|
-
const nowContent = await
|
|
8025
|
+
const nowContent = await fs22.readFile(nowPath, "utf-8");
|
|
7954
8026
|
actual.hasActiveTask = nowContent.trim().length > 0 && !nowContent.includes("No current task");
|
|
7955
8027
|
if (actual.hasActiveTask) {
|
|
7956
8028
|
recommendations.push("Consider completing current task first with /p:done");
|
|
@@ -7975,7 +8047,7 @@ async function verifyNow(context2) {
|
|
|
7975
8047
|
const actual = {};
|
|
7976
8048
|
const nowPath = context2.paths.now;
|
|
7977
8049
|
try {
|
|
7978
|
-
const nowContent = await
|
|
8050
|
+
const nowContent = await fs22.readFile(nowPath, "utf-8");
|
|
7979
8051
|
actual.nowExists = true;
|
|
7980
8052
|
actual.nowContent = nowContent.trim();
|
|
7981
8053
|
const hasRealTask = nowContent.trim().length > 0 && !nowContent.includes("No current task") && !nowContent.match(/^#\s*NOW\s*$/m);
|
|
@@ -7995,7 +8067,7 @@ async function verifyNow(context2) {
|
|
|
7995
8067
|
}
|
|
7996
8068
|
const nextPath = context2.paths.next;
|
|
7997
8069
|
try {
|
|
7998
|
-
const nextContent = await
|
|
8070
|
+
const nextContent = await fs22.readFile(nextPath, "utf-8");
|
|
7999
8071
|
const pendingTasks = (nextContent.match(/- \[ \]/g) || []).length;
|
|
8000
8072
|
actual.pendingTasks = pendingTasks;
|
|
8001
8073
|
if (!context2.params.task && pendingTasks > 0) {
|
|
@@ -8021,7 +8093,7 @@ async function verifyInit(context2) {
|
|
|
8021
8093
|
const actual = {};
|
|
8022
8094
|
const configPath = path20.join(context2.projectPath, ".prjct/prjct.config.json");
|
|
8023
8095
|
try {
|
|
8024
|
-
const configContent = await
|
|
8096
|
+
const configContent = await fs22.readFile(configPath, "utf-8");
|
|
8025
8097
|
actual.alreadyInitialized = true;
|
|
8026
8098
|
actual.existingConfig = JSON.parse(configContent);
|
|
8027
8099
|
warnings.push("Project already initialized");
|
|
@@ -8038,12 +8110,12 @@ async function verifyInit(context2) {
|
|
|
8038
8110
|
}
|
|
8039
8111
|
const globalPath = path20.join(os7.homedir(), ".prjct-cli");
|
|
8040
8112
|
try {
|
|
8041
|
-
await
|
|
8113
|
+
await fs22.access(globalPath, fs22.constants.W_OK);
|
|
8042
8114
|
actual.globalPathWritable = true;
|
|
8043
8115
|
} catch (error) {
|
|
8044
8116
|
if (isNotFoundError(error)) {
|
|
8045
8117
|
try {
|
|
8046
|
-
await
|
|
8118
|
+
await fs22.mkdir(globalPath, { recursive: true });
|
|
8047
8119
|
actual.globalPathWritable = true;
|
|
8048
8120
|
actual.globalPathCreated = true;
|
|
8049
8121
|
} catch (_mkdirError) {
|
|
@@ -8070,7 +8142,7 @@ async function verifySync(context2) {
|
|
|
8070
8142
|
const actual = {};
|
|
8071
8143
|
const configPath = path20.join(context2.projectPath, ".prjct/prjct.config.json");
|
|
8072
8144
|
try {
|
|
8073
|
-
const configContent = await
|
|
8145
|
+
const configContent = await fs22.readFile(configPath, "utf-8");
|
|
8074
8146
|
actual.hasConfig = true;
|
|
8075
8147
|
actual.config = JSON.parse(configContent);
|
|
8076
8148
|
} catch (error) {
|
|
@@ -8091,7 +8163,7 @@ async function verifySync(context2) {
|
|
|
8091
8163
|
const projectId = actual.config?.projectId;
|
|
8092
8164
|
const globalProjectPath = path20.join(os7.homedir(), ".prjct-cli/projects", projectId || "");
|
|
8093
8165
|
try {
|
|
8094
|
-
await
|
|
8166
|
+
await fs22.access(globalProjectPath);
|
|
8095
8167
|
actual.globalStorageExists = true;
|
|
8096
8168
|
} catch (error) {
|
|
8097
8169
|
if (isNotFoundError(error)) {
|
|
@@ -8117,7 +8189,7 @@ async function verifyAnalyze(context2) {
|
|
|
8117
8189
|
actual.detectedFiles = [];
|
|
8118
8190
|
for (const file of files) {
|
|
8119
8191
|
try {
|
|
8120
|
-
await
|
|
8192
|
+
await fs22.access(path20.join(context2.projectPath, file));
|
|
8121
8193
|
actual.detectedFiles.push(file);
|
|
8122
8194
|
} catch (error) {
|
|
8123
8195
|
if (!isNotFoundError(error)) {
|
|
@@ -8133,7 +8205,7 @@ async function verifyAnalyze(context2) {
|
|
|
8133
8205
|
actual.detectedSrcDirs = [];
|
|
8134
8206
|
for (const dir of srcDirs) {
|
|
8135
8207
|
try {
|
|
8136
|
-
const stat = await
|
|
8208
|
+
const stat = await fs22.stat(path20.join(context2.projectPath, dir));
|
|
8137
8209
|
if (stat.isDirectory()) {
|
|
8138
8210
|
;
|
|
8139
8211
|
actual.detectedSrcDirs.push(dir);
|
|
@@ -8158,9 +8230,9 @@ async function verifySpec(context2) {
|
|
|
8158
8230
|
const actual = {};
|
|
8159
8231
|
const specsPath = context2.paths.specs;
|
|
8160
8232
|
try {
|
|
8161
|
-
await
|
|
8233
|
+
await fs22.access(specsPath);
|
|
8162
8234
|
actual.specsExists = true;
|
|
8163
|
-
const files = await
|
|
8235
|
+
const files = await fs22.readdir(specsPath);
|
|
8164
8236
|
actual.existingSpecs = files.filter((f) => f.endsWith(".md"));
|
|
8165
8237
|
actual.specCount = actual.existingSpecs.length;
|
|
8166
8238
|
} catch (error) {
|
|
@@ -9385,7 +9457,7 @@ var init_shipped = __esm({
|
|
|
9385
9457
|
agent: z9.string().optional(),
|
|
9386
9458
|
// "fe+be", "be", "fe"
|
|
9387
9459
|
description: z9.string().optional(),
|
|
9388
|
-
changes: z9.array(ShipChangeSchema),
|
|
9460
|
+
changes: z9.array(ShipChangeSchema).optional(),
|
|
9389
9461
|
codeSnippets: z9.array(z9.string()).optional(),
|
|
9390
9462
|
commit: CommitInfoSchema.optional(),
|
|
9391
9463
|
codeMetrics: CodeMetricsSchema.optional(),
|
|
@@ -9398,7 +9470,7 @@ var init_shipped = __esm({
|
|
|
9398
9470
|
featureId: z9.string().optional()
|
|
9399
9471
|
});
|
|
9400
9472
|
ShippedJsonSchema = z9.object({
|
|
9401
|
-
|
|
9473
|
+
shipped: z9.array(ShippedItemSchema),
|
|
9402
9474
|
lastUpdated: z9.string()
|
|
9403
9475
|
});
|
|
9404
9476
|
}
|
|
@@ -9419,7 +9491,8 @@ var init_state = __esm({
|
|
|
9419
9491
|
"completed",
|
|
9420
9492
|
"blocked",
|
|
9421
9493
|
"paused",
|
|
9422
|
-
"failed"
|
|
9494
|
+
"failed",
|
|
9495
|
+
"skipped"
|
|
9423
9496
|
]);
|
|
9424
9497
|
ActivityTypeSchema = z10.enum([
|
|
9425
9498
|
"task_completed",
|
|
@@ -9457,8 +9530,12 @@ var init_state = __esm({
|
|
|
9457
9530
|
// ISO8601
|
|
9458
9531
|
output: z10.string().optional(),
|
|
9459
9532
|
// Brief output description
|
|
9460
|
-
summary: SubtaskSummarySchema.optional()
|
|
9533
|
+
summary: SubtaskSummarySchema.optional(),
|
|
9461
9534
|
// Full summary for context handoff
|
|
9535
|
+
skipReason: z10.string().optional(),
|
|
9536
|
+
// Why this subtask was skipped
|
|
9537
|
+
blockReason: z10.string().optional()
|
|
9538
|
+
// What is blocking this subtask
|
|
9462
9539
|
});
|
|
9463
9540
|
SubtaskProgressSchema = z10.object({
|
|
9464
9541
|
completed: z10.number(),
|
|
@@ -9498,6 +9575,9 @@ var init_state = __esm({
|
|
|
9498
9575
|
StateJsonSchema = z10.object({
|
|
9499
9576
|
currentTask: CurrentTaskSchema.nullable(),
|
|
9500
9577
|
previousTask: PreviousTaskSchema.nullable().optional(),
|
|
9578
|
+
// deprecated: use pausedTasks
|
|
9579
|
+
pausedTasks: z10.array(PreviousTaskSchema).optional(),
|
|
9580
|
+
// replaces previousTask
|
|
9501
9581
|
lastUpdated: z10.string()
|
|
9502
9582
|
});
|
|
9503
9583
|
QueueTaskSchema = z10.object({
|
|
@@ -9592,7 +9672,7 @@ __export(jsonl_helper_exports, {
|
|
|
9592
9672
|
writeJsonLines: () => writeJsonLines
|
|
9593
9673
|
});
|
|
9594
9674
|
import fsSync from "node:fs";
|
|
9595
|
-
import
|
|
9675
|
+
import fs23 from "node:fs/promises";
|
|
9596
9676
|
import path21 from "node:path";
|
|
9597
9677
|
import readline from "node:readline";
|
|
9598
9678
|
function parseJsonLines(content) {
|
|
@@ -9612,7 +9692,7 @@ function stringifyJsonLines(objects) {
|
|
|
9612
9692
|
}
|
|
9613
9693
|
async function readJsonLines(filePath) {
|
|
9614
9694
|
try {
|
|
9615
|
-
const content = await
|
|
9695
|
+
const content = await fs23.readFile(filePath, "utf-8");
|
|
9616
9696
|
return parseJsonLines(content);
|
|
9617
9697
|
} catch (error) {
|
|
9618
9698
|
if (isNotFoundError(error)) {
|
|
@@ -9623,16 +9703,16 @@ async function readJsonLines(filePath) {
|
|
|
9623
9703
|
}
|
|
9624
9704
|
async function writeJsonLines(filePath, objects) {
|
|
9625
9705
|
const content = stringifyJsonLines(objects);
|
|
9626
|
-
await
|
|
9706
|
+
await fs23.writeFile(filePath, content, "utf-8");
|
|
9627
9707
|
}
|
|
9628
9708
|
async function appendJsonLine(filePath, object) {
|
|
9629
9709
|
const line = `${JSON.stringify(object)}
|
|
9630
9710
|
`;
|
|
9631
|
-
await
|
|
9711
|
+
await fs23.appendFile(filePath, line, "utf-8");
|
|
9632
9712
|
}
|
|
9633
9713
|
async function appendJsonLines(filePath, objects) {
|
|
9634
9714
|
const content = stringifyJsonLines(objects);
|
|
9635
|
-
await
|
|
9715
|
+
await fs23.appendFile(filePath, content, "utf-8");
|
|
9636
9716
|
}
|
|
9637
9717
|
async function filterJsonLines(filePath, predicate) {
|
|
9638
9718
|
const entries = await readJsonLines(filePath);
|
|
@@ -9640,7 +9720,7 @@ async function filterJsonLines(filePath, predicate) {
|
|
|
9640
9720
|
}
|
|
9641
9721
|
async function countJsonLines(filePath) {
|
|
9642
9722
|
try {
|
|
9643
|
-
const content = await
|
|
9723
|
+
const content = await fs23.readFile(filePath, "utf-8");
|
|
9644
9724
|
const lines = content.split("\n").filter((line) => line.trim());
|
|
9645
9725
|
return lines.length;
|
|
9646
9726
|
} catch (error) {
|
|
@@ -9699,7 +9779,7 @@ async function readJsonLinesStreaming(filePath, maxLines = STORAGE_LIMITS.JSONL_
|
|
|
9699
9779
|
}
|
|
9700
9780
|
async function getFileSizeMB(filePath) {
|
|
9701
9781
|
try {
|
|
9702
|
-
const stats = await
|
|
9782
|
+
const stats = await fs23.stat(filePath);
|
|
9703
9783
|
return stats.size / (1024 * 1024);
|
|
9704
9784
|
} catch (error) {
|
|
9705
9785
|
if (isNotFoundError(error)) {
|
|
@@ -9718,7 +9798,7 @@ async function rotateJsonLinesIfNeeded(filePath, maxSizeMB = STORAGE_LIMITS.ROTA
|
|
|
9718
9798
|
const ext = path21.extname(filePath);
|
|
9719
9799
|
const base = path21.basename(filePath, ext);
|
|
9720
9800
|
const archivePath = path21.join(dir, `${base}-${timestamp}${ext}`);
|
|
9721
|
-
await
|
|
9801
|
+
await fs23.rename(filePath, archivePath);
|
|
9722
9802
|
console.log(
|
|
9723
9803
|
`\u{1F4E6} Rotated ${path21.basename(filePath)} (${sizeMB.toFixed(1)}MB) \u2192 ${path21.basename(archivePath)}`
|
|
9724
9804
|
);
|
|
@@ -9798,7 +9878,7 @@ var init_memory = __esm({
|
|
|
9798
9878
|
});
|
|
9799
9879
|
|
|
9800
9880
|
// core/agentic/memory-system.ts
|
|
9801
|
-
import
|
|
9881
|
+
import fs24 from "node:fs/promises";
|
|
9802
9882
|
import path22 from "node:path";
|
|
9803
9883
|
var CachedStore, SessionStore, HistoryStore, PatternStore, SemanticMemories, MemorySystem, memorySystem, memory_system_default;
|
|
9804
9884
|
var init_memory_system = __esm({
|
|
@@ -9865,7 +9945,7 @@ var init_memory_system = __esm({
|
|
|
9865
9945
|
}
|
|
9866
9946
|
const filePath = this.getPath(projectId);
|
|
9867
9947
|
try {
|
|
9868
|
-
const content = await
|
|
9948
|
+
const content = await fs24.readFile(filePath, "utf-8");
|
|
9869
9949
|
this._data = JSON.parse(content);
|
|
9870
9950
|
this.afterLoad(this._data);
|
|
9871
9951
|
} catch (error) {
|
|
@@ -9901,8 +9981,8 @@ var init_memory_system = __esm({
|
|
|
9901
9981
|
async save(projectId) {
|
|
9902
9982
|
if (!this._data) return;
|
|
9903
9983
|
const filePath = this.getPath(projectId);
|
|
9904
|
-
await
|
|
9905
|
-
await
|
|
9984
|
+
await fs24.mkdir(path22.dirname(filePath), { recursive: true });
|
|
9985
|
+
await fs24.writeFile(filePath, JSON.stringify(this._data, null, 2), "utf-8");
|
|
9906
9986
|
}
|
|
9907
9987
|
/**
|
|
9908
9988
|
* Access the cached data without triggering a disk read.
|
|
@@ -10691,6 +10771,7 @@ var init_ideas_storage = __esm({
|
|
|
10691
10771
|
"core/storage/ideas-storage.ts"() {
|
|
10692
10772
|
"use strict";
|
|
10693
10773
|
init_schemas2();
|
|
10774
|
+
init_ideas();
|
|
10694
10775
|
init_date_helper();
|
|
10695
10776
|
init_storage_manager();
|
|
10696
10777
|
IdeasStorage = class extends StorageManager {
|
|
@@ -10698,7 +10779,7 @@ var init_ideas_storage = __esm({
|
|
|
10698
10779
|
__name(this, "IdeasStorage");
|
|
10699
10780
|
}
|
|
10700
10781
|
constructor() {
|
|
10701
|
-
super("ideas.json");
|
|
10782
|
+
super("ideas.json", IdeasJsonSchema);
|
|
10702
10783
|
}
|
|
10703
10784
|
getDefault() {
|
|
10704
10785
|
return {
|
|
@@ -10891,7 +10972,7 @@ var init_ideas_storage = __esm({
|
|
|
10891
10972
|
|
|
10892
10973
|
// core/storage/index-storage.ts
|
|
10893
10974
|
import crypto4 from "node:crypto";
|
|
10894
|
-
import
|
|
10975
|
+
import fs25 from "node:fs/promises";
|
|
10895
10976
|
import path23 from "node:path";
|
|
10896
10977
|
function getDefaultChecksums() {
|
|
10897
10978
|
return {
|
|
@@ -10924,7 +11005,7 @@ var init_index_storage = __esm({
|
|
|
10924
11005
|
*/
|
|
10925
11006
|
async ensureIndexDir(projectId) {
|
|
10926
11007
|
const indexPath = this.getIndexPath(projectId);
|
|
10927
|
-
await
|
|
11008
|
+
await fs25.mkdir(indexPath, { recursive: true });
|
|
10928
11009
|
return indexPath;
|
|
10929
11010
|
}
|
|
10930
11011
|
// ==========================================================================
|
|
@@ -10936,7 +11017,7 @@ var init_index_storage = __esm({
|
|
|
10936
11017
|
async readIndex(projectId) {
|
|
10937
11018
|
const filePath = path23.join(this.getIndexPath(projectId), "project-index.json");
|
|
10938
11019
|
try {
|
|
10939
|
-
const content = await
|
|
11020
|
+
const content = await fs25.readFile(filePath, "utf-8");
|
|
10940
11021
|
const index = JSON.parse(content);
|
|
10941
11022
|
if (index.version !== INDEX_VERSION) {
|
|
10942
11023
|
return null;
|
|
@@ -10955,7 +11036,7 @@ var init_index_storage = __esm({
|
|
|
10955
11036
|
async writeIndex(projectId, index) {
|
|
10956
11037
|
await this.ensureIndexDir(projectId);
|
|
10957
11038
|
const filePath = path23.join(this.getIndexPath(projectId), "project-index.json");
|
|
10958
|
-
await
|
|
11039
|
+
await fs25.writeFile(filePath, JSON.stringify(index, null, 2), "utf-8");
|
|
10959
11040
|
}
|
|
10960
11041
|
/**
|
|
10961
11042
|
* Check if index exists and is valid
|
|
@@ -10973,7 +11054,7 @@ var init_index_storage = __esm({
|
|
|
10973
11054
|
async readChecksums(projectId) {
|
|
10974
11055
|
const filePath = path23.join(this.getIndexPath(projectId), "checksums.json");
|
|
10975
11056
|
try {
|
|
10976
|
-
const content = await
|
|
11057
|
+
const content = await fs25.readFile(filePath, "utf-8");
|
|
10977
11058
|
return JSON.parse(content);
|
|
10978
11059
|
} catch (error) {
|
|
10979
11060
|
if (isNotFoundError(error)) {
|
|
@@ -10988,14 +11069,14 @@ var init_index_storage = __esm({
|
|
|
10988
11069
|
async writeChecksums(projectId, checksums) {
|
|
10989
11070
|
await this.ensureIndexDir(projectId);
|
|
10990
11071
|
const filePath = path23.join(this.getIndexPath(projectId), "checksums.json");
|
|
10991
|
-
await
|
|
11072
|
+
await fs25.writeFile(filePath, JSON.stringify(checksums, null, 2), "utf-8");
|
|
10992
11073
|
}
|
|
10993
11074
|
/**
|
|
10994
11075
|
* Calculate checksum for a file
|
|
10995
11076
|
*/
|
|
10996
11077
|
async calculateChecksum(filePath) {
|
|
10997
11078
|
try {
|
|
10998
|
-
const content = await
|
|
11079
|
+
const content = await fs25.readFile(filePath);
|
|
10999
11080
|
return crypto4.createHash("md5").update(content).digest("hex");
|
|
11000
11081
|
} catch {
|
|
11001
11082
|
return "";
|
|
@@ -11033,7 +11114,7 @@ var init_index_storage = __esm({
|
|
|
11033
11114
|
async readScores(projectId) {
|
|
11034
11115
|
const filePath = path23.join(this.getIndexPath(projectId), "file-scores.json");
|
|
11035
11116
|
try {
|
|
11036
|
-
const content = await
|
|
11117
|
+
const content = await fs25.readFile(filePath, "utf-8");
|
|
11037
11118
|
const data = JSON.parse(content);
|
|
11038
11119
|
return data.scores || [];
|
|
11039
11120
|
} catch (error) {
|
|
@@ -11054,7 +11135,7 @@ var init_index_storage = __esm({
|
|
|
11054
11135
|
lastUpdated: getTimestamp(),
|
|
11055
11136
|
scores
|
|
11056
11137
|
};
|
|
11057
|
-
await
|
|
11138
|
+
await fs25.writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
11058
11139
|
}
|
|
11059
11140
|
// ==========================================================================
|
|
11060
11141
|
// UTILITY METHODS
|
|
@@ -11065,8 +11146,8 @@ var init_index_storage = __esm({
|
|
|
11065
11146
|
async clearIndex(projectId) {
|
|
11066
11147
|
const indexPath = this.getIndexPath(projectId);
|
|
11067
11148
|
try {
|
|
11068
|
-
const files = await
|
|
11069
|
-
await Promise.all(files.map((file) =>
|
|
11149
|
+
const files = await fs25.readdir(indexPath);
|
|
11150
|
+
await Promise.all(files.map((file) => fs25.unlink(path23.join(indexPath, file))));
|
|
11070
11151
|
} catch (error) {
|
|
11071
11152
|
if (!isNotFoundError(error)) {
|
|
11072
11153
|
throw error;
|
|
@@ -11094,7 +11175,7 @@ var init_index_storage = __esm({
|
|
|
11094
11175
|
async readDomains(projectId) {
|
|
11095
11176
|
const filePath = path23.join(this.getIndexPath(projectId), "domains.json");
|
|
11096
11177
|
try {
|
|
11097
|
-
const content = await
|
|
11178
|
+
const content = await fs25.readFile(filePath, "utf-8");
|
|
11098
11179
|
const domains = JSON.parse(content);
|
|
11099
11180
|
if (domains.version !== INDEX_VERSION) {
|
|
11100
11181
|
return null;
|
|
@@ -11113,7 +11194,7 @@ var init_index_storage = __esm({
|
|
|
11113
11194
|
async writeDomains(projectId, domains) {
|
|
11114
11195
|
await this.ensureIndexDir(projectId);
|
|
11115
11196
|
const filePath = path23.join(this.getIndexPath(projectId), "domains.json");
|
|
11116
|
-
await
|
|
11197
|
+
await fs25.writeFile(filePath, JSON.stringify(domains, null, 2), "utf-8");
|
|
11117
11198
|
}
|
|
11118
11199
|
// ==========================================================================
|
|
11119
11200
|
// CATEGORIES CACHE
|
|
@@ -11124,7 +11205,7 @@ var init_index_storage = __esm({
|
|
|
11124
11205
|
async readCategories(projectId) {
|
|
11125
11206
|
const filePath = path23.join(this.getIndexPath(projectId), "categories-cache.json");
|
|
11126
11207
|
try {
|
|
11127
|
-
const content = await
|
|
11208
|
+
const content = await fs25.readFile(filePath, "utf-8");
|
|
11128
11209
|
const cache2 = JSON.parse(content);
|
|
11129
11210
|
if (cache2.version !== INDEX_VERSION) {
|
|
11130
11211
|
return null;
|
|
@@ -11143,7 +11224,7 @@ var init_index_storage = __esm({
|
|
|
11143
11224
|
async writeCategories(projectId, cache2) {
|
|
11144
11225
|
await this.ensureIndexDir(projectId);
|
|
11145
11226
|
const filePath = path23.join(this.getIndexPath(projectId), "categories-cache.json");
|
|
11146
|
-
await
|
|
11227
|
+
await fs25.writeFile(filePath, JSON.stringify(cache2, null, 2), "utf-8");
|
|
11147
11228
|
}
|
|
11148
11229
|
/**
|
|
11149
11230
|
* Get file categories for specific paths
|
|
@@ -11183,6 +11264,7 @@ var init_queue_storage = __esm({
|
|
|
11183
11264
|
"core/storage/queue-storage.ts"() {
|
|
11184
11265
|
"use strict";
|
|
11185
11266
|
init_schemas2();
|
|
11267
|
+
init_state();
|
|
11186
11268
|
init_date_helper();
|
|
11187
11269
|
init_storage_manager();
|
|
11188
11270
|
QueueStorage = class extends StorageManager {
|
|
@@ -11190,7 +11272,7 @@ var init_queue_storage = __esm({
|
|
|
11190
11272
|
__name(this, "QueueStorage");
|
|
11191
11273
|
}
|
|
11192
11274
|
constructor() {
|
|
11193
|
-
super("queue.json");
|
|
11275
|
+
super("queue.json", QueueJsonSchema);
|
|
11194
11276
|
}
|
|
11195
11277
|
getDefault() {
|
|
11196
11278
|
return {
|
|
@@ -11423,6 +11505,7 @@ var init_shipped_storage = __esm({
|
|
|
11423
11505
|
"core/storage/shipped-storage.ts"() {
|
|
11424
11506
|
"use strict";
|
|
11425
11507
|
init_schemas2();
|
|
11508
|
+
init_shipped();
|
|
11426
11509
|
init_date_helper();
|
|
11427
11510
|
init_storage_manager();
|
|
11428
11511
|
ShippedStorage = class extends StorageManager {
|
|
@@ -11430,7 +11513,7 @@ var init_shipped_storage = __esm({
|
|
|
11430
11513
|
__name(this, "ShippedStorage");
|
|
11431
11514
|
}
|
|
11432
11515
|
constructor() {
|
|
11433
|
-
super("shipped.json");
|
|
11516
|
+
super("shipped.json", ShippedJsonSchema);
|
|
11434
11517
|
}
|
|
11435
11518
|
getDefault() {
|
|
11436
11519
|
return {
|
|
@@ -11817,21 +11900,172 @@ var init_markdown_builder = __esm({
|
|
|
11817
11900
|
}
|
|
11818
11901
|
});
|
|
11819
11902
|
|
|
11903
|
+
// core/workflow/state-machine.ts
|
|
11904
|
+
var WORKFLOW_STATES, WorkflowStateMachine, workflowStateMachine;
|
|
11905
|
+
var init_state_machine = __esm({
|
|
11906
|
+
"core/workflow/state-machine.ts"() {
|
|
11907
|
+
"use strict";
|
|
11908
|
+
WORKFLOW_STATES = {
|
|
11909
|
+
idle: {
|
|
11910
|
+
transitions: ["task", "next"],
|
|
11911
|
+
prompt: "p. task <description> Start working",
|
|
11912
|
+
description: "No active task"
|
|
11913
|
+
},
|
|
11914
|
+
working: {
|
|
11915
|
+
transitions: ["done", "pause"],
|
|
11916
|
+
prompt: "p. done Complete task | p. pause Switch context",
|
|
11917
|
+
description: "Task in progress"
|
|
11918
|
+
},
|
|
11919
|
+
paused: {
|
|
11920
|
+
transitions: ["resume", "task", "ship"],
|
|
11921
|
+
prompt: "p. resume Continue | p. task <new> Start different | p. ship Ship directly",
|
|
11922
|
+
description: "Task paused"
|
|
11923
|
+
},
|
|
11924
|
+
completed: {
|
|
11925
|
+
transitions: ["ship", "task", "next", "pause", "reopen"],
|
|
11926
|
+
prompt: "p. ship Ship it | p. task <next> Start next | p. reopen Reopen for rework",
|
|
11927
|
+
description: "Task completed"
|
|
11928
|
+
},
|
|
11929
|
+
shipped: {
|
|
11930
|
+
transitions: ["task", "next"],
|
|
11931
|
+
prompt: "p. task <description> Start new task",
|
|
11932
|
+
description: "Feature shipped"
|
|
11933
|
+
}
|
|
11934
|
+
};
|
|
11935
|
+
WorkflowStateMachine = class {
|
|
11936
|
+
static {
|
|
11937
|
+
__name(this, "WorkflowStateMachine");
|
|
11938
|
+
}
|
|
11939
|
+
/**
|
|
11940
|
+
* Get current state from storage state
|
|
11941
|
+
*/
|
|
11942
|
+
getCurrentState(storageState) {
|
|
11943
|
+
const task = storageState?.currentTask;
|
|
11944
|
+
if (!task) {
|
|
11945
|
+
const hasPaused = (storageState?.pausedTasks?.length || 0) > 0 || storageState?.previousTask?.status === "paused";
|
|
11946
|
+
return hasPaused ? "paused" : "idle";
|
|
11947
|
+
}
|
|
11948
|
+
const status = (typeof task.status === "string" ? task.status : "").toLowerCase();
|
|
11949
|
+
switch (status) {
|
|
11950
|
+
case "in_progress":
|
|
11951
|
+
case "working":
|
|
11952
|
+
return "working";
|
|
11953
|
+
case "paused":
|
|
11954
|
+
return "paused";
|
|
11955
|
+
case "completed":
|
|
11956
|
+
case "done":
|
|
11957
|
+
return "completed";
|
|
11958
|
+
case "shipped":
|
|
11959
|
+
return "shipped";
|
|
11960
|
+
default:
|
|
11961
|
+
return task ? "working" : "idle";
|
|
11962
|
+
}
|
|
11963
|
+
}
|
|
11964
|
+
/**
|
|
11965
|
+
* Check if a command is valid for the current state
|
|
11966
|
+
*/
|
|
11967
|
+
canTransition(currentState, command) {
|
|
11968
|
+
const stateConfig = WORKFLOW_STATES[currentState];
|
|
11969
|
+
if (stateConfig.transitions.includes(command)) {
|
|
11970
|
+
return { valid: true };
|
|
11971
|
+
}
|
|
11972
|
+
const validCommands = stateConfig.transitions.map((c) => `p. ${c}`).join(", ");
|
|
11973
|
+
return {
|
|
11974
|
+
valid: false,
|
|
11975
|
+
error: `Cannot run 'p. ${command}' in ${currentState} state`,
|
|
11976
|
+
suggestion: `Valid commands: ${validCommands}`
|
|
11977
|
+
};
|
|
11978
|
+
}
|
|
11979
|
+
/**
|
|
11980
|
+
* Get the next state after a command
|
|
11981
|
+
*/
|
|
11982
|
+
getNextState(currentState, command) {
|
|
11983
|
+
switch (command) {
|
|
11984
|
+
case "task":
|
|
11985
|
+
return "working";
|
|
11986
|
+
case "done":
|
|
11987
|
+
return "completed";
|
|
11988
|
+
case "pause":
|
|
11989
|
+
return "paused";
|
|
11990
|
+
case "resume":
|
|
11991
|
+
return "working";
|
|
11992
|
+
case "ship":
|
|
11993
|
+
return "shipped";
|
|
11994
|
+
case "reopen":
|
|
11995
|
+
return "working";
|
|
11996
|
+
case "next":
|
|
11997
|
+
return currentState;
|
|
11998
|
+
// next doesn't change state
|
|
11999
|
+
default:
|
|
12000
|
+
return currentState;
|
|
12001
|
+
}
|
|
12002
|
+
}
|
|
12003
|
+
/**
|
|
12004
|
+
* Get state definition
|
|
12005
|
+
*/
|
|
12006
|
+
getStateInfo(state) {
|
|
12007
|
+
return WORKFLOW_STATES[state];
|
|
12008
|
+
}
|
|
12009
|
+
/**
|
|
12010
|
+
* Get prompt for current state
|
|
12011
|
+
*/
|
|
12012
|
+
getPrompt(state) {
|
|
12013
|
+
return WORKFLOW_STATES[state].prompt;
|
|
12014
|
+
}
|
|
12015
|
+
/**
|
|
12016
|
+
* Get valid commands for current state
|
|
12017
|
+
*/
|
|
12018
|
+
getValidCommands(state) {
|
|
12019
|
+
return WORKFLOW_STATES[state].transitions;
|
|
12020
|
+
}
|
|
12021
|
+
/**
|
|
12022
|
+
* Format next steps for display
|
|
12023
|
+
*/
|
|
12024
|
+
formatNextSteps(state) {
|
|
12025
|
+
const stateConfig = WORKFLOW_STATES[state];
|
|
12026
|
+
return stateConfig.transitions.map((cmd) => {
|
|
12027
|
+
switch (cmd) {
|
|
12028
|
+
case "task":
|
|
12029
|
+
return "p. task <desc> Start new task";
|
|
12030
|
+
case "done":
|
|
12031
|
+
return "p. done Complete current task";
|
|
12032
|
+
case "pause":
|
|
12033
|
+
return "p. pause Pause and switch context";
|
|
12034
|
+
case "resume":
|
|
12035
|
+
return "p. resume Continue paused task";
|
|
12036
|
+
case "ship":
|
|
12037
|
+
return "p. ship Ship the feature";
|
|
12038
|
+
case "reopen":
|
|
12039
|
+
return "p. reopen Reopen for rework";
|
|
12040
|
+
case "next":
|
|
12041
|
+
return "p. next View task queue";
|
|
12042
|
+
default:
|
|
12043
|
+
return `p. ${cmd}`;
|
|
12044
|
+
}
|
|
12045
|
+
});
|
|
12046
|
+
}
|
|
12047
|
+
};
|
|
12048
|
+
workflowStateMachine = new WorkflowStateMachine();
|
|
12049
|
+
}
|
|
12050
|
+
});
|
|
12051
|
+
|
|
11820
12052
|
// core/storage/state-storage.ts
|
|
11821
12053
|
var StateStorage, stateStorage;
|
|
11822
12054
|
var init_state_storage = __esm({
|
|
11823
12055
|
"core/storage/state-storage.ts"() {
|
|
11824
12056
|
"use strict";
|
|
11825
12057
|
init_schemas2();
|
|
12058
|
+
init_state();
|
|
11826
12059
|
init_date_helper();
|
|
11827
12060
|
init_markdown_builder();
|
|
12061
|
+
init_state_machine();
|
|
11828
12062
|
init_storage_manager();
|
|
11829
12063
|
StateStorage = class extends StorageManager {
|
|
11830
12064
|
static {
|
|
11831
12065
|
__name(this, "StateStorage");
|
|
11832
12066
|
}
|
|
11833
12067
|
constructor() {
|
|
11834
|
-
super("state.json");
|
|
12068
|
+
super("state.json", StateJsonSchema);
|
|
11835
12069
|
}
|
|
11836
12070
|
getDefault() {
|
|
11837
12071
|
return {
|
|
@@ -11858,7 +12092,7 @@ var init_state_storage = __esm({
|
|
|
11858
12092
|
`**Progress**: ${task.subtaskProgress?.completed || 0}/${task.subtaskProgress?.total || 0} (${task.subtaskProgress?.percentage || 0}%)`
|
|
11859
12093
|
).blank().raw("| # | Domain | Description | Status | Agent |").raw("|---|--------|-------------|--------|-------|");
|
|
11860
12094
|
task.subtasks.forEach((subtask, index) => {
|
|
11861
|
-
const statusIcon = subtask.status === "completed" ? "\u2705" : subtask.status === "in_progress" ? "\u25B6\uFE0F" : subtask.status === "failed" ? "\u274C" : "\u23F3";
|
|
12095
|
+
const statusIcon = subtask.status === "completed" ? "\u2705" : subtask.status === "in_progress" ? "\u25B6\uFE0F" : subtask.status === "failed" ? "\u274C" : subtask.status === "skipped" ? "\u23ED\uFE0F" : subtask.status === "blocked" ? "\u{1F6AB}" : "\u23F3";
|
|
11862
12096
|
const isActive = index === task.currentSubtaskIndex ? " **\u2190 Active**" : "";
|
|
11863
12097
|
m.raw(
|
|
11864
12098
|
`| ${index + 1} | ${subtask.domain} | ${subtask.description} | ${statusIcon} ${subtask.status}${isActive} | ${subtask.agent} |`
|
|
@@ -11886,10 +12120,29 @@ var init_state_storage = __esm({
|
|
|
11886
12120
|
}
|
|
11887
12121
|
}).when(!data.currentTask, (m) => {
|
|
11888
12122
|
m.italic("No active task. Use /p:work to start.");
|
|
11889
|
-
}).
|
|
11890
|
-
|
|
12123
|
+
}).when((data.pausedTasks?.length || 0) > 0 || !!data.previousTask, (m) => {
|
|
12124
|
+
const paused = data.pausedTasks?.length ? data.pausedTasks : data.previousTask ? [data.previousTask] : [];
|
|
12125
|
+
if (paused.length === 0) return;
|
|
12126
|
+
m.hr().h2(`Paused (${paused.length})`);
|
|
12127
|
+
paused.forEach((prev, i) => {
|
|
12128
|
+
m.raw(`${i + 1}. **${prev.description}**`).raw(` Paused: ${toRelative(prev.pausedAt)}`);
|
|
12129
|
+
if (prev.pauseReason) m.raw(` Reason: ${prev.pauseReason}`);
|
|
12130
|
+
});
|
|
12131
|
+
m.blank().italic("Use /p:resume to continue");
|
|
11891
12132
|
}).blank().build();
|
|
11892
12133
|
}
|
|
12134
|
+
// =========== Transition Validation ===========
|
|
12135
|
+
/**
|
|
12136
|
+
* Validate a state transition through the state machine.
|
|
12137
|
+
* Throws if the transition is invalid.
|
|
12138
|
+
*/
|
|
12139
|
+
validateTransition(state, command) {
|
|
12140
|
+
const currentState = workflowStateMachine.getCurrentState(state);
|
|
12141
|
+
const result = workflowStateMachine.canTransition(currentState, command);
|
|
12142
|
+
if (!result.valid) {
|
|
12143
|
+
throw new Error(`${result.error}. ${result.suggestion || ""}`.trim());
|
|
12144
|
+
}
|
|
12145
|
+
}
|
|
11893
12146
|
// =========== Domain Methods ===========
|
|
11894
12147
|
/**
|
|
11895
12148
|
* Get current active task
|
|
@@ -11902,12 +12155,14 @@ var init_state_storage = __esm({
|
|
|
11902
12155
|
* Start a new task
|
|
11903
12156
|
*/
|
|
11904
12157
|
async startTask(projectId, task) {
|
|
12158
|
+
const state = await this.read(projectId);
|
|
12159
|
+
this.validateTransition(state, "task");
|
|
11905
12160
|
const currentTask = {
|
|
11906
12161
|
...task,
|
|
11907
12162
|
startedAt: getTimestamp()
|
|
11908
12163
|
};
|
|
11909
|
-
await this.update(projectId, (
|
|
11910
|
-
...
|
|
12164
|
+
await this.update(projectId, (state2) => ({
|
|
12165
|
+
...state2,
|
|
11911
12166
|
currentTask,
|
|
11912
12167
|
lastUpdated: getTimestamp()
|
|
11913
12168
|
}));
|
|
@@ -11928,6 +12183,7 @@ var init_state_storage = __esm({
|
|
|
11928
12183
|
if (!completedTask) {
|
|
11929
12184
|
return null;
|
|
11930
12185
|
}
|
|
12186
|
+
this.validateTransition(state, "done");
|
|
11931
12187
|
await this.update(projectId, () => ({
|
|
11932
12188
|
currentTask: null,
|
|
11933
12189
|
previousTask: null,
|
|
@@ -11941,15 +12197,20 @@ var init_state_storage = __esm({
|
|
|
11941
12197
|
});
|
|
11942
12198
|
return completedTask;
|
|
11943
12199
|
}
|
|
12200
|
+
/** Max number of paused tasks (configurable) */
|
|
12201
|
+
maxPausedTasks = 5;
|
|
12202
|
+
/** Staleness threshold in days */
|
|
12203
|
+
stalenessThresholdDays = 30;
|
|
11944
12204
|
/**
|
|
11945
|
-
* Pause current task
|
|
12205
|
+
* Pause current task — pushes onto pausedTasks[] array
|
|
11946
12206
|
*/
|
|
11947
12207
|
async pauseTask(projectId, reason2) {
|
|
11948
12208
|
const state = await this.read(projectId);
|
|
11949
12209
|
if (!state.currentTask) {
|
|
11950
12210
|
return null;
|
|
11951
12211
|
}
|
|
11952
|
-
|
|
12212
|
+
this.validateTransition(state, "pause");
|
|
12213
|
+
const pausedTask = {
|
|
11953
12214
|
id: state.currentTask.id,
|
|
11954
12215
|
description: state.currentTask.description,
|
|
11955
12216
|
status: "paused",
|
|
@@ -11957,45 +12218,111 @@ var init_state_storage = __esm({
|
|
|
11957
12218
|
pausedAt: getTimestamp(),
|
|
11958
12219
|
pauseReason: reason2
|
|
11959
12220
|
};
|
|
12221
|
+
const existingPaused = this.getPausedTasksFromState(state);
|
|
12222
|
+
const pausedTasks = [pausedTask, ...existingPaused].slice(0, this.maxPausedTasks);
|
|
11960
12223
|
await this.update(projectId, () => ({
|
|
11961
12224
|
currentTask: null,
|
|
11962
|
-
previousTask,
|
|
12225
|
+
previousTask: null,
|
|
12226
|
+
// deprecated, keep null for compat
|
|
12227
|
+
pausedTasks,
|
|
11963
12228
|
lastUpdated: getTimestamp()
|
|
11964
12229
|
}));
|
|
11965
12230
|
await this.publishEvent(projectId, "task.paused", {
|
|
11966
|
-
taskId:
|
|
11967
|
-
description:
|
|
11968
|
-
pausedAt:
|
|
11969
|
-
reason: reason2
|
|
12231
|
+
taskId: pausedTask.id,
|
|
12232
|
+
description: pausedTask.description,
|
|
12233
|
+
pausedAt: pausedTask.pausedAt,
|
|
12234
|
+
reason: reason2,
|
|
12235
|
+
pausedCount: pausedTasks.length
|
|
11970
12236
|
});
|
|
11971
|
-
return
|
|
12237
|
+
return pausedTask;
|
|
11972
12238
|
}
|
|
11973
12239
|
/**
|
|
11974
|
-
* Resume paused task
|
|
12240
|
+
* Resume most recent paused task (or by ID)
|
|
11975
12241
|
*/
|
|
11976
|
-
async resumeTask(projectId) {
|
|
12242
|
+
async resumeTask(projectId, taskId) {
|
|
11977
12243
|
const state = await this.read(projectId);
|
|
11978
|
-
|
|
12244
|
+
const pausedTasks = this.getPausedTasksFromState(state);
|
|
12245
|
+
if (pausedTasks.length === 0) {
|
|
11979
12246
|
return null;
|
|
11980
12247
|
}
|
|
12248
|
+
this.validateTransition(state, "resume");
|
|
12249
|
+
let targetIndex = 0;
|
|
12250
|
+
if (taskId) {
|
|
12251
|
+
targetIndex = pausedTasks.findIndex((t) => t.id === taskId);
|
|
12252
|
+
if (targetIndex === -1) return null;
|
|
12253
|
+
}
|
|
12254
|
+
const target = pausedTasks[targetIndex];
|
|
12255
|
+
const remaining = pausedTasks.filter((_, i) => i !== targetIndex);
|
|
11981
12256
|
const currentTask = {
|
|
11982
|
-
id:
|
|
11983
|
-
description:
|
|
12257
|
+
id: target.id,
|
|
12258
|
+
description: target.description,
|
|
11984
12259
|
startedAt: getTimestamp(),
|
|
11985
12260
|
sessionId: generateUUID()
|
|
11986
12261
|
};
|
|
11987
12262
|
await this.update(projectId, () => ({
|
|
11988
12263
|
currentTask,
|
|
11989
12264
|
previousTask: null,
|
|
12265
|
+
// deprecated, keep null
|
|
12266
|
+
pausedTasks: remaining,
|
|
11990
12267
|
lastUpdated: getTimestamp()
|
|
11991
12268
|
}));
|
|
11992
12269
|
await this.publishEvent(projectId, "task.resumed", {
|
|
11993
12270
|
taskId: currentTask.id,
|
|
11994
12271
|
description: currentTask.description,
|
|
11995
|
-
resumedAt: currentTask.startedAt
|
|
12272
|
+
resumedAt: currentTask.startedAt,
|
|
12273
|
+
remainingPaused: remaining.length
|
|
11996
12274
|
});
|
|
11997
12275
|
return currentTask;
|
|
11998
12276
|
}
|
|
12277
|
+
/**
|
|
12278
|
+
* Get paused tasks from state, migrating from legacy previousTask if needed
|
|
12279
|
+
*/
|
|
12280
|
+
getPausedTasksFromState(state) {
|
|
12281
|
+
const paused = state.pausedTasks || [];
|
|
12282
|
+
if (state.previousTask && state.previousTask.status === "paused") {
|
|
12283
|
+
const alreadyInArray = paused.some((t) => t.id === state.previousTask.id);
|
|
12284
|
+
if (!alreadyInArray) {
|
|
12285
|
+
return [state.previousTask, ...paused];
|
|
12286
|
+
}
|
|
12287
|
+
}
|
|
12288
|
+
return paused;
|
|
12289
|
+
}
|
|
12290
|
+
/**
|
|
12291
|
+
* Get stale paused tasks (older than threshold)
|
|
12292
|
+
*/
|
|
12293
|
+
async getStalePausedTasks(projectId) {
|
|
12294
|
+
const state = await this.read(projectId);
|
|
12295
|
+
const pausedTasks = this.getPausedTasksFromState(state);
|
|
12296
|
+
const threshold = Date.now() - this.stalenessThresholdDays * 24 * 60 * 60 * 1e3;
|
|
12297
|
+
return pausedTasks.filter((t) => new Date(t.pausedAt).getTime() < threshold);
|
|
12298
|
+
}
|
|
12299
|
+
/**
|
|
12300
|
+
* Archive stale paused tasks (remove from pausedTasks)
|
|
12301
|
+
* Returns archived tasks
|
|
12302
|
+
*/
|
|
12303
|
+
async archiveStalePausedTasks(projectId) {
|
|
12304
|
+
const state = await this.read(projectId);
|
|
12305
|
+
const pausedTasks = this.getPausedTasksFromState(state);
|
|
12306
|
+
const threshold = Date.now() - this.stalenessThresholdDays * 24 * 60 * 60 * 1e3;
|
|
12307
|
+
const stale = pausedTasks.filter((t) => new Date(t.pausedAt).getTime() < threshold);
|
|
12308
|
+
const fresh = pausedTasks.filter((t) => new Date(t.pausedAt).getTime() >= threshold);
|
|
12309
|
+
if (stale.length === 0) return [];
|
|
12310
|
+
await this.update(projectId, (s) => ({
|
|
12311
|
+
...s,
|
|
12312
|
+
pausedTasks: fresh,
|
|
12313
|
+
previousTask: null,
|
|
12314
|
+
lastUpdated: getTimestamp()
|
|
12315
|
+
}));
|
|
12316
|
+
for (const task of stale) {
|
|
12317
|
+
await this.publishEvent(projectId, "task.archived", {
|
|
12318
|
+
taskId: task.id,
|
|
12319
|
+
description: task.description,
|
|
12320
|
+
pausedAt: task.pausedAt,
|
|
12321
|
+
reason: "staleness"
|
|
12322
|
+
});
|
|
12323
|
+
}
|
|
12324
|
+
return stale;
|
|
12325
|
+
}
|
|
11999
12326
|
/**
|
|
12000
12327
|
* Clear all task state
|
|
12001
12328
|
*/
|
|
@@ -12003,6 +12330,7 @@ var init_state_storage = __esm({
|
|
|
12003
12330
|
await this.update(projectId, () => ({
|
|
12004
12331
|
currentTask: null,
|
|
12005
12332
|
previousTask: null,
|
|
12333
|
+
pausedTasks: [],
|
|
12006
12334
|
lastUpdated: getTimestamp()
|
|
12007
12335
|
}));
|
|
12008
12336
|
}
|
|
@@ -12011,14 +12339,23 @@ var init_state_storage = __esm({
|
|
|
12011
12339
|
*/
|
|
12012
12340
|
async hasTask(projectId) {
|
|
12013
12341
|
const state = await this.read(projectId);
|
|
12014
|
-
|
|
12342
|
+
const paused = this.getPausedTasksFromState(state);
|
|
12343
|
+
return state.currentTask !== null || paused.length > 0;
|
|
12015
12344
|
}
|
|
12016
12345
|
/**
|
|
12017
|
-
* Get paused task
|
|
12346
|
+
* Get most recently paused task
|
|
12018
12347
|
*/
|
|
12019
12348
|
async getPausedTask(projectId) {
|
|
12020
12349
|
const state = await this.read(projectId);
|
|
12021
|
-
|
|
12350
|
+
const paused = this.getPausedTasksFromState(state);
|
|
12351
|
+
return paused[0] || null;
|
|
12352
|
+
}
|
|
12353
|
+
/**
|
|
12354
|
+
* Get all paused tasks
|
|
12355
|
+
*/
|
|
12356
|
+
async getAllPausedTasks(projectId) {
|
|
12357
|
+
const state = await this.read(projectId);
|
|
12358
|
+
return this.getPausedTasksFromState(state);
|
|
12022
12359
|
}
|
|
12023
12360
|
// =========== Subtask Methods ===========
|
|
12024
12361
|
/**
|
|
@@ -12158,41 +12495,152 @@ var init_state_storage = __esm({
|
|
|
12158
12495
|
/**
|
|
12159
12496
|
* Check if all subtasks are complete
|
|
12160
12497
|
*/
|
|
12161
|
-
async areAllSubtasksComplete(projectId) {
|
|
12498
|
+
async areAllSubtasksComplete(projectId) {
|
|
12499
|
+
const state = await this.read(projectId);
|
|
12500
|
+
if (!state.currentTask?.subtasks) return true;
|
|
12501
|
+
return state.currentTask.subtasks.every(
|
|
12502
|
+
(s) => s.status === "completed" || s.status === "failed" || s.status === "skipped"
|
|
12503
|
+
);
|
|
12504
|
+
}
|
|
12505
|
+
/**
|
|
12506
|
+
* Fail current subtask and advance to next
|
|
12507
|
+
* Returns the next subtask (or null if all done/failed)
|
|
12508
|
+
*/
|
|
12509
|
+
async failSubtask(projectId, error) {
|
|
12510
|
+
const state = await this.read(projectId);
|
|
12511
|
+
if (!state.currentTask?.subtasks) return null;
|
|
12512
|
+
const currentIndex = state.currentTask.currentSubtaskIndex || 0;
|
|
12513
|
+
const current = state.currentTask.subtasks[currentIndex];
|
|
12514
|
+
if (!current) return null;
|
|
12515
|
+
const updatedSubtasks = [...state.currentTask.subtasks];
|
|
12516
|
+
updatedSubtasks[currentIndex] = {
|
|
12517
|
+
...current,
|
|
12518
|
+
status: "failed",
|
|
12519
|
+
completedAt: getTimestamp(),
|
|
12520
|
+
output: `Failed: ${error}`
|
|
12521
|
+
};
|
|
12522
|
+
const nextIndex = currentIndex + 1;
|
|
12523
|
+
const total = updatedSubtasks.length;
|
|
12524
|
+
if (nextIndex < total) {
|
|
12525
|
+
updatedSubtasks[nextIndex] = {
|
|
12526
|
+
...updatedSubtasks[nextIndex],
|
|
12527
|
+
status: "in_progress",
|
|
12528
|
+
startedAt: getTimestamp()
|
|
12529
|
+
};
|
|
12530
|
+
}
|
|
12531
|
+
const resolved = updatedSubtasks.filter(
|
|
12532
|
+
(s) => s.status === "completed" || s.status === "failed" || s.status === "skipped"
|
|
12533
|
+
).length;
|
|
12534
|
+
const percentage = Math.round(resolved / total * 100);
|
|
12535
|
+
await this.update(projectId, (s) => ({
|
|
12536
|
+
...s,
|
|
12537
|
+
currentTask: {
|
|
12538
|
+
...s.currentTask,
|
|
12539
|
+
subtasks: updatedSubtasks,
|
|
12540
|
+
currentSubtaskIndex: nextIndex < total ? nextIndex : currentIndex,
|
|
12541
|
+
subtaskProgress: { completed: resolved, total, percentage }
|
|
12542
|
+
},
|
|
12543
|
+
lastUpdated: getTimestamp()
|
|
12544
|
+
}));
|
|
12545
|
+
await this.publishEvent(projectId, "subtask.failed", {
|
|
12546
|
+
taskId: state.currentTask.id,
|
|
12547
|
+
subtaskId: current.id,
|
|
12548
|
+
description: current.description,
|
|
12549
|
+
error
|
|
12550
|
+
});
|
|
12551
|
+
return nextIndex < total ? updatedSubtasks[nextIndex] : null;
|
|
12552
|
+
}
|
|
12553
|
+
/**
|
|
12554
|
+
* Skip current subtask with reason and advance to next
|
|
12555
|
+
* Returns the next subtask (or null if all done)
|
|
12556
|
+
*/
|
|
12557
|
+
async skipSubtask(projectId, reason2) {
|
|
12162
12558
|
const state = await this.read(projectId);
|
|
12163
|
-
if (!state.currentTask?.subtasks) return
|
|
12164
|
-
|
|
12559
|
+
if (!state.currentTask?.subtasks) return null;
|
|
12560
|
+
const currentIndex = state.currentTask.currentSubtaskIndex || 0;
|
|
12561
|
+
const current = state.currentTask.subtasks[currentIndex];
|
|
12562
|
+
if (!current) return null;
|
|
12563
|
+
const updatedSubtasks = [...state.currentTask.subtasks];
|
|
12564
|
+
updatedSubtasks[currentIndex] = {
|
|
12565
|
+
...current,
|
|
12566
|
+
status: "skipped",
|
|
12567
|
+
completedAt: getTimestamp(),
|
|
12568
|
+
output: `Skipped: ${reason2}`,
|
|
12569
|
+
skipReason: reason2
|
|
12570
|
+
};
|
|
12571
|
+
const nextIndex = currentIndex + 1;
|
|
12572
|
+
const total = updatedSubtasks.length;
|
|
12573
|
+
if (nextIndex < total) {
|
|
12574
|
+
updatedSubtasks[nextIndex] = {
|
|
12575
|
+
...updatedSubtasks[nextIndex],
|
|
12576
|
+
status: "in_progress",
|
|
12577
|
+
startedAt: getTimestamp()
|
|
12578
|
+
};
|
|
12579
|
+
}
|
|
12580
|
+
const resolved = updatedSubtasks.filter(
|
|
12581
|
+
(s) => s.status === "completed" || s.status === "failed" || s.status === "skipped"
|
|
12582
|
+
).length;
|
|
12583
|
+
const percentage = Math.round(resolved / total * 100);
|
|
12584
|
+
await this.update(projectId, (s) => ({
|
|
12585
|
+
...s,
|
|
12586
|
+
currentTask: {
|
|
12587
|
+
...s.currentTask,
|
|
12588
|
+
subtasks: updatedSubtasks,
|
|
12589
|
+
currentSubtaskIndex: nextIndex < total ? nextIndex : currentIndex,
|
|
12590
|
+
subtaskProgress: { completed: resolved, total, percentage }
|
|
12591
|
+
},
|
|
12592
|
+
lastUpdated: getTimestamp()
|
|
12593
|
+
}));
|
|
12594
|
+
await this.publishEvent(projectId, "subtask.skipped", {
|
|
12595
|
+
taskId: state.currentTask.id,
|
|
12596
|
+
subtaskId: current.id,
|
|
12597
|
+
description: current.description,
|
|
12598
|
+
reason: reason2
|
|
12599
|
+
});
|
|
12600
|
+
return nextIndex < total ? updatedSubtasks[nextIndex] : null;
|
|
12165
12601
|
}
|
|
12166
12602
|
/**
|
|
12167
|
-
*
|
|
12603
|
+
* Block current subtask with reason, allow proceeding to next
|
|
12604
|
+
* Returns the next subtask (or null if no more)
|
|
12168
12605
|
*/
|
|
12169
|
-
async
|
|
12606
|
+
async blockSubtask(projectId, blocker) {
|
|
12170
12607
|
const state = await this.read(projectId);
|
|
12171
|
-
if (!state.currentTask?.subtasks) return;
|
|
12608
|
+
if (!state.currentTask?.subtasks) return null;
|
|
12172
12609
|
const currentIndex = state.currentTask.currentSubtaskIndex || 0;
|
|
12173
12610
|
const current = state.currentTask.subtasks[currentIndex];
|
|
12174
|
-
if (!current) return;
|
|
12611
|
+
if (!current) return null;
|
|
12175
12612
|
const updatedSubtasks = [...state.currentTask.subtasks];
|
|
12176
12613
|
updatedSubtasks[currentIndex] = {
|
|
12177
12614
|
...current,
|
|
12178
|
-
status: "
|
|
12179
|
-
|
|
12180
|
-
|
|
12615
|
+
status: "blocked",
|
|
12616
|
+
output: `Blocked: ${blocker}`,
|
|
12617
|
+
blockReason: blocker
|
|
12181
12618
|
};
|
|
12619
|
+
const nextIndex = currentIndex + 1;
|
|
12620
|
+
const total = updatedSubtasks.length;
|
|
12621
|
+
if (nextIndex < total) {
|
|
12622
|
+
updatedSubtasks[nextIndex] = {
|
|
12623
|
+
...updatedSubtasks[nextIndex],
|
|
12624
|
+
status: "in_progress",
|
|
12625
|
+
startedAt: getTimestamp()
|
|
12626
|
+
};
|
|
12627
|
+
}
|
|
12182
12628
|
await this.update(projectId, (s) => ({
|
|
12183
12629
|
...s,
|
|
12184
12630
|
currentTask: {
|
|
12185
12631
|
...s.currentTask,
|
|
12186
|
-
subtasks: updatedSubtasks
|
|
12632
|
+
subtasks: updatedSubtasks,
|
|
12633
|
+
currentSubtaskIndex: nextIndex < total ? nextIndex : currentIndex
|
|
12187
12634
|
},
|
|
12188
12635
|
lastUpdated: getTimestamp()
|
|
12189
12636
|
}));
|
|
12190
|
-
await this.publishEvent(projectId, "subtask.
|
|
12637
|
+
await this.publishEvent(projectId, "subtask.blocked", {
|
|
12191
12638
|
taskId: state.currentTask.id,
|
|
12192
12639
|
subtaskId: current.id,
|
|
12193
12640
|
description: current.description,
|
|
12194
|
-
|
|
12641
|
+
blocker
|
|
12195
12642
|
});
|
|
12643
|
+
return nextIndex < total ? updatedSubtasks[nextIndex] : null;
|
|
12196
12644
|
}
|
|
12197
12645
|
};
|
|
12198
12646
|
stateStorage = new StateStorage();
|
|
@@ -12200,7 +12648,7 @@ var init_state_storage = __esm({
|
|
|
12200
12648
|
});
|
|
12201
12649
|
|
|
12202
12650
|
// core/storage/storage.ts
|
|
12203
|
-
import
|
|
12651
|
+
import fs26 from "node:fs/promises";
|
|
12204
12652
|
import os8 from "node:os";
|
|
12205
12653
|
import path24 from "node:path";
|
|
12206
12654
|
function getStorage(projectId) {
|
|
@@ -12238,8 +12686,8 @@ var init_storage = __esm({
|
|
|
12238
12686
|
}
|
|
12239
12687
|
async write(pathArray, data) {
|
|
12240
12688
|
const filePath = this.pathToFile(pathArray);
|
|
12241
|
-
await
|
|
12242
|
-
await
|
|
12689
|
+
await fs26.mkdir(path24.dirname(filePath), { recursive: true });
|
|
12690
|
+
await fs26.writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
12243
12691
|
eventBus.publish({
|
|
12244
12692
|
type: inferEventType(pathArray, "write"),
|
|
12245
12693
|
path: pathArray,
|
|
@@ -12254,7 +12702,7 @@ var init_storage = __esm({
|
|
|
12254
12702
|
async read(pathArray) {
|
|
12255
12703
|
const filePath = this.pathToFile(pathArray);
|
|
12256
12704
|
try {
|
|
12257
|
-
const content = await
|
|
12705
|
+
const content = await fs26.readFile(filePath, "utf-8");
|
|
12258
12706
|
return JSON.parse(content);
|
|
12259
12707
|
} catch (error) {
|
|
12260
12708
|
if (isNotFoundError(error) || error instanceof SyntaxError) {
|
|
@@ -12266,7 +12714,7 @@ var init_storage = __esm({
|
|
|
12266
12714
|
async list(prefix) {
|
|
12267
12715
|
const dir = path24.join(this.basePath, `${prefix[0]}s`);
|
|
12268
12716
|
try {
|
|
12269
|
-
const files = await
|
|
12717
|
+
const files = await fs26.readdir(dir);
|
|
12270
12718
|
return files.filter((f) => f.endsWith(".json") && f !== "index.json").map((f) => [...prefix, f.replace(".json", "")]);
|
|
12271
12719
|
} catch (error) {
|
|
12272
12720
|
if (isNotFoundError(error)) {
|
|
@@ -12278,7 +12726,7 @@ var init_storage = __esm({
|
|
|
12278
12726
|
async delete(pathArray) {
|
|
12279
12727
|
const filePath = this.pathToFile(pathArray);
|
|
12280
12728
|
try {
|
|
12281
|
-
await
|
|
12729
|
+
await fs26.unlink(filePath);
|
|
12282
12730
|
eventBus.publish({
|
|
12283
12731
|
type: inferEventType(pathArray, "delete"),
|
|
12284
12732
|
path: pathArray,
|
|
@@ -12298,7 +12746,7 @@ var init_storage = __esm({
|
|
|
12298
12746
|
async exists(pathArray) {
|
|
12299
12747
|
const filePath = this.pathToFile(pathArray);
|
|
12300
12748
|
try {
|
|
12301
|
-
await
|
|
12749
|
+
await fs26.access(filePath);
|
|
12302
12750
|
return true;
|
|
12303
12751
|
} catch (error) {
|
|
12304
12752
|
if (isNotFoundError(error)) {
|
|
@@ -12314,7 +12762,7 @@ var init_storage = __esm({
|
|
|
12314
12762
|
const indexPath = path24.join(this.basePath, `${collection}s`, "index.json");
|
|
12315
12763
|
let index = { ids: [], updatedAt: "" };
|
|
12316
12764
|
try {
|
|
12317
|
-
const content = await
|
|
12765
|
+
const content = await fs26.readFile(indexPath, "utf-8");
|
|
12318
12766
|
index = JSON.parse(content);
|
|
12319
12767
|
} catch (error) {
|
|
12320
12768
|
if (!isNotFoundError(error) && !(error instanceof SyntaxError)) {
|
|
@@ -12327,8 +12775,8 @@ var init_storage = __esm({
|
|
|
12327
12775
|
index.ids = index.ids.filter((i) => i !== id);
|
|
12328
12776
|
}
|
|
12329
12777
|
index.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
12330
|
-
await
|
|
12331
|
-
await
|
|
12778
|
+
await fs26.mkdir(path24.dirname(indexPath), { recursive: true });
|
|
12779
|
+
await fs26.writeFile(indexPath, JSON.stringify(index, null, 2), "utf-8");
|
|
12332
12780
|
}
|
|
12333
12781
|
};
|
|
12334
12782
|
__name(getStorage, "getStorage");
|
|
@@ -12351,7 +12799,7 @@ var init_storage2 = __esm({
|
|
|
12351
12799
|
});
|
|
12352
12800
|
|
|
12353
12801
|
// core/agentic/template-loader.ts
|
|
12354
|
-
import
|
|
12802
|
+
import fs27 from "node:fs/promises";
|
|
12355
12803
|
import path25 from "node:path";
|
|
12356
12804
|
function updateLruOrder(key) {
|
|
12357
12805
|
const index = cacheOrder.indexOf(key);
|
|
@@ -12392,7 +12840,7 @@ async function load(commandName) {
|
|
|
12392
12840
|
}
|
|
12393
12841
|
const templatePath = path25.join(TEMPLATES_DIR, `${commandName}.md`);
|
|
12394
12842
|
try {
|
|
12395
|
-
const rawContent = await
|
|
12843
|
+
const rawContent = await fs27.readFile(templatePath, "utf-8");
|
|
12396
12844
|
const parsed = parseFrontmatter(rawContent);
|
|
12397
12845
|
evictLru();
|
|
12398
12846
|
cache.set(commandName, parsed);
|
|
@@ -12432,7 +12880,7 @@ var init_template_loader = __esm({
|
|
|
12432
12880
|
|
|
12433
12881
|
// core/agentic/orchestrator-executor.ts
|
|
12434
12882
|
import { exec as execCallback5 } from "node:child_process";
|
|
12435
|
-
import
|
|
12883
|
+
import fs28 from "node:fs/promises";
|
|
12436
12884
|
import os9 from "node:os";
|
|
12437
12885
|
import path26 from "node:path";
|
|
12438
12886
|
import { promisify as promisify7 } from "node:util";
|
|
@@ -12703,7 +13151,7 @@ var init_orchestrator_executor = __esm({
|
|
|
12703
13151
|
async loadRepoAnalysis(globalPath) {
|
|
12704
13152
|
try {
|
|
12705
13153
|
const analysisPath = path26.join(globalPath, "analysis", "repo-analysis.json");
|
|
12706
|
-
const content = await
|
|
13154
|
+
const content = await fs28.readFile(analysisPath, "utf-8");
|
|
12707
13155
|
return JSON.parse(content);
|
|
12708
13156
|
} catch (error) {
|
|
12709
13157
|
if (isNotFoundError(error)) return null;
|
|
@@ -12768,7 +13216,7 @@ var init_orchestrator_executor = __esm({
|
|
|
12768
13216
|
async getAvailableAgentNames(globalPath) {
|
|
12769
13217
|
try {
|
|
12770
13218
|
const agentsDir = path26.join(globalPath, "agents");
|
|
12771
|
-
const files = await
|
|
13219
|
+
const files = await fs28.readdir(agentsDir);
|
|
12772
13220
|
return files.filter((f) => f.endsWith(".md")).map((f) => f.replace(".md", ""));
|
|
12773
13221
|
} catch {
|
|
12774
13222
|
return [];
|
|
@@ -12790,7 +13238,7 @@ var init_orchestrator_executor = __esm({
|
|
|
12790
13238
|
for (const fileName of possibleNames) {
|
|
12791
13239
|
const filePath = path26.join(agentsDir, fileName);
|
|
12792
13240
|
try {
|
|
12793
|
-
const content = await
|
|
13241
|
+
const content = await fs28.readFile(filePath, "utf-8");
|
|
12794
13242
|
const { frontmatter, body } = this.parseAgentFile(content);
|
|
12795
13243
|
return {
|
|
12796
13244
|
name: fileName.replace(".md", ""),
|
|
@@ -12845,11 +13293,11 @@ var init_orchestrator_executor = __esm({
|
|
|
12845
13293
|
const flatPath = path26.join(skillsDir, `${skillName}.md`);
|
|
12846
13294
|
const subdirPath = path26.join(skillsDir, skillName, "SKILL.md");
|
|
12847
13295
|
try {
|
|
12848
|
-
const content = await
|
|
13296
|
+
const content = await fs28.readFile(subdirPath, "utf-8");
|
|
12849
13297
|
return { name: skillName, content, filePath: subdirPath };
|
|
12850
13298
|
} catch {
|
|
12851
13299
|
try {
|
|
12852
|
-
const content = await
|
|
13300
|
+
const content = await fs28.readFile(flatPath, "utf-8");
|
|
12853
13301
|
return { name: skillName, content, filePath: flatPath };
|
|
12854
13302
|
} catch {
|
|
12855
13303
|
const agentNames = skillToAgents.get(skillName) || [];
|
|
@@ -13772,7 +14220,7 @@ var init_outcomes2 = __esm({
|
|
|
13772
14220
|
});
|
|
13773
14221
|
|
|
13774
14222
|
// core/agentic/prompt-builder.ts
|
|
13775
|
-
import
|
|
14223
|
+
import fs29 from "node:fs/promises";
|
|
13776
14224
|
import path28 from "node:path";
|
|
13777
14225
|
var PromptBuilder, promptBuilder, prompt_builder_default;
|
|
13778
14226
|
var init_prompt_builder = __esm({
|
|
@@ -13811,7 +14259,7 @@ var init_prompt_builder = __esm({
|
|
|
13811
14259
|
}
|
|
13812
14260
|
try {
|
|
13813
14261
|
if (await fileExists(templatePath)) {
|
|
13814
|
-
const content = await
|
|
14262
|
+
const content = await fs29.readFile(templatePath, "utf-8");
|
|
13815
14263
|
this._templateCache.set(templatePath, { content, loadedAt: now });
|
|
13816
14264
|
return content;
|
|
13817
14265
|
}
|
|
@@ -13882,7 +14330,7 @@ var init_prompt_builder = __esm({
|
|
|
13882
14330
|
const checklists = {};
|
|
13883
14331
|
try {
|
|
13884
14332
|
if (await fileExists(checklistsDir)) {
|
|
13885
|
-
const files = (await
|
|
14333
|
+
const files = (await fs29.readdir(checklistsDir)).filter((f) => f.endsWith(".md"));
|
|
13886
14334
|
for (const file of files) {
|
|
13887
14335
|
const name = file.replace(".md", "");
|
|
13888
14336
|
const templatePath = path28.join(checklistsDir, file);
|
|
@@ -14442,7 +14890,7 @@ Context: ${fileCount} files available. Read what you need.
|
|
|
14442
14890
|
});
|
|
14443
14891
|
|
|
14444
14892
|
// core/agentic/template-executor.ts
|
|
14445
|
-
import
|
|
14893
|
+
import fs30 from "node:fs/promises";
|
|
14446
14894
|
import path29 from "node:path";
|
|
14447
14895
|
var ORCHESTRATED_COMMANDS, SIMPLE_COMMANDS, TemplateExecutor, templateExecutor, template_executor_default;
|
|
14448
14896
|
var init_template_executor = __esm({
|
|
@@ -14521,7 +14969,7 @@ var init_template_executor = __esm({
|
|
|
14521
14969
|
try {
|
|
14522
14970
|
const projectId = await this.getProjectId(projectPath);
|
|
14523
14971
|
const agentsDir = path29.join(path_manager_default.getGlobalProjectPath(projectId), "agents");
|
|
14524
|
-
const files = await
|
|
14972
|
+
const files = await fs30.readdir(agentsDir);
|
|
14525
14973
|
return files.some((f) => f.endsWith(".md"));
|
|
14526
14974
|
} catch (error) {
|
|
14527
14975
|
if (isNotFoundError(error)) return false;
|
|
@@ -14535,7 +14983,7 @@ var init_template_executor = __esm({
|
|
|
14535
14983
|
try {
|
|
14536
14984
|
const projectId = await this.getProjectId(projectPath);
|
|
14537
14985
|
const agentsDir = path29.join(path_manager_default.getGlobalProjectPath(projectId), "agents");
|
|
14538
|
-
const files = await
|
|
14986
|
+
const files = await fs30.readdir(agentsDir);
|
|
14539
14987
|
return files.filter((f) => f.endsWith(".md")).map((f) => f.replace(".md", ""));
|
|
14540
14988
|
} catch {
|
|
14541
14989
|
return [];
|
|
@@ -14644,7 +15092,7 @@ When fragmenting tasks:
|
|
|
14644
15092
|
|
|
14645
15093
|
// core/agentic/tool-registry.ts
|
|
14646
15094
|
import { exec as exec7 } from "node:child_process";
|
|
14647
|
-
import
|
|
15095
|
+
import fs31 from "node:fs/promises";
|
|
14648
15096
|
import { promisify as promisify8 } from "node:util";
|
|
14649
15097
|
var execAsync4, toolRegistry, tool_registry_default;
|
|
14650
15098
|
var init_tool_registry = __esm({
|
|
@@ -14688,14 +15136,14 @@ var init_tool_registry = __esm({
|
|
|
14688
15136
|
};
|
|
14689
15137
|
toolRegistry.register("Read", async (filePath) => {
|
|
14690
15138
|
try {
|
|
14691
|
-
return await
|
|
15139
|
+
return await fs31.readFile(filePath, "utf-8");
|
|
14692
15140
|
} catch (_error) {
|
|
14693
15141
|
return null;
|
|
14694
15142
|
}
|
|
14695
15143
|
});
|
|
14696
15144
|
toolRegistry.register("Write", async (filePath, content) => {
|
|
14697
15145
|
try {
|
|
14698
|
-
await
|
|
15146
|
+
await fs31.writeFile(filePath, content, "utf-8");
|
|
14699
15147
|
return true;
|
|
14700
15148
|
} catch (_error) {
|
|
14701
15149
|
return false;
|
|
@@ -14730,23 +15178,23 @@ var init_tool_registry = __esm({
|
|
|
14730
15178
|
});
|
|
14731
15179
|
|
|
14732
15180
|
// core/agentic/command-executor.ts
|
|
14733
|
-
import
|
|
15181
|
+
import fs32 from "node:fs/promises";
|
|
14734
15182
|
import os10 from "node:os";
|
|
14735
15183
|
import path30 from "node:path";
|
|
14736
15184
|
async function signalStart(commandName) {
|
|
14737
15185
|
try {
|
|
14738
15186
|
const dir = path30.dirname(RUNNING_FILE);
|
|
14739
15187
|
if (!await fileExists(dir)) {
|
|
14740
|
-
await
|
|
15188
|
+
await fs32.mkdir(dir, { recursive: true });
|
|
14741
15189
|
}
|
|
14742
|
-
await
|
|
15190
|
+
await fs32.writeFile(RUNNING_FILE, `/p:${commandName}`);
|
|
14743
15191
|
} catch (_error) {
|
|
14744
15192
|
}
|
|
14745
15193
|
}
|
|
14746
15194
|
async function signalEnd() {
|
|
14747
15195
|
try {
|
|
14748
15196
|
if (await fileExists(RUNNING_FILE)) {
|
|
14749
|
-
await
|
|
15197
|
+
await fs32.unlink(RUNNING_FILE);
|
|
14750
15198
|
}
|
|
14751
15199
|
} catch (_error) {
|
|
14752
15200
|
}
|
|
@@ -15079,7 +15527,7 @@ var init_command_executor = __esm({
|
|
|
15079
15527
|
});
|
|
15080
15528
|
|
|
15081
15529
|
// core/infrastructure/update-checker.ts
|
|
15082
|
-
import
|
|
15530
|
+
import fs33 from "node:fs/promises";
|
|
15083
15531
|
import https from "node:https";
|
|
15084
15532
|
import os11 from "node:os";
|
|
15085
15533
|
import path31 from "node:path";
|
|
@@ -15110,7 +15558,7 @@ var init_update_checker = __esm({
|
|
|
15110
15558
|
async getCurrentVersion() {
|
|
15111
15559
|
try {
|
|
15112
15560
|
const packageJsonPath = path31.join(__dirname, "..", "..", "package.json");
|
|
15113
|
-
const packageJson = JSON.parse(await
|
|
15561
|
+
const packageJson = JSON.parse(await fs33.readFile(packageJsonPath, "utf8"));
|
|
15114
15562
|
return packageJson.version;
|
|
15115
15563
|
} catch (error) {
|
|
15116
15564
|
console.error("Error reading package version:", getErrorMessage2(error));
|
|
@@ -15180,7 +15628,7 @@ var init_update_checker = __esm({
|
|
|
15180
15628
|
async readCache() {
|
|
15181
15629
|
try {
|
|
15182
15630
|
if (await fileExists(this.cacheFile)) {
|
|
15183
|
-
const cache2 = JSON.parse(await
|
|
15631
|
+
const cache2 = JSON.parse(await fs33.readFile(this.cacheFile, "utf8"));
|
|
15184
15632
|
return cache2;
|
|
15185
15633
|
}
|
|
15186
15634
|
} catch (_error) {
|
|
@@ -15193,9 +15641,9 @@ var init_update_checker = __esm({
|
|
|
15193
15641
|
async writeCache(data) {
|
|
15194
15642
|
try {
|
|
15195
15643
|
if (!await fileExists(this.cacheDir)) {
|
|
15196
|
-
await
|
|
15644
|
+
await fs33.mkdir(this.cacheDir, { recursive: true });
|
|
15197
15645
|
}
|
|
15198
|
-
await
|
|
15646
|
+
await fs33.writeFile(this.cacheFile, JSON.stringify(data, null, 2), "utf8");
|
|
15199
15647
|
} catch (_error) {
|
|
15200
15648
|
}
|
|
15201
15649
|
}
|
|
@@ -15353,7 +15801,7 @@ var init_agent_generator = __esm({
|
|
|
15353
15801
|
});
|
|
15354
15802
|
|
|
15355
15803
|
// core/agentic/agent-router.ts
|
|
15356
|
-
import
|
|
15804
|
+
import fs34 from "node:fs/promises";
|
|
15357
15805
|
import path32 from "node:path";
|
|
15358
15806
|
var AgentRouter, agent_router_default;
|
|
15359
15807
|
var init_agent_router = __esm({
|
|
@@ -15383,12 +15831,12 @@ var init_agent_router = __esm({
|
|
|
15383
15831
|
async loadAvailableAgents() {
|
|
15384
15832
|
if (!this.agentsPath) return [];
|
|
15385
15833
|
try {
|
|
15386
|
-
const files = await
|
|
15834
|
+
const files = await fs34.readdir(this.agentsPath);
|
|
15387
15835
|
const agents = [];
|
|
15388
15836
|
for (const file of files) {
|
|
15389
15837
|
if (file.endsWith(".md")) {
|
|
15390
15838
|
const name = file.replace(".md", "");
|
|
15391
|
-
const content = await
|
|
15839
|
+
const content = await fs34.readFile(path32.join(this.agentsPath, file), "utf-8");
|
|
15392
15840
|
agents.push({ name, content });
|
|
15393
15841
|
}
|
|
15394
15842
|
}
|
|
@@ -15414,7 +15862,7 @@ var init_agent_router = __esm({
|
|
|
15414
15862
|
if (!this.agentsPath) return null;
|
|
15415
15863
|
try {
|
|
15416
15864
|
const filePath = path32.join(this.agentsPath, `${name}.md`);
|
|
15417
|
-
const content = await
|
|
15865
|
+
const content = await fs34.readFile(filePath, "utf-8");
|
|
15418
15866
|
return { name, content };
|
|
15419
15867
|
} catch (error) {
|
|
15420
15868
|
if (!isNotFoundError(error)) {
|
|
@@ -15456,7 +15904,7 @@ var init_agent_router = __esm({
|
|
|
15456
15904
|
projectId: this.projectId
|
|
15457
15905
|
})}
|
|
15458
15906
|
`;
|
|
15459
|
-
await
|
|
15907
|
+
await fs34.appendFile(logPath, entry);
|
|
15460
15908
|
} catch (error) {
|
|
15461
15909
|
if (!isNotFoundError(error)) {
|
|
15462
15910
|
console.error(`Agent usage log error: ${getErrorMessage2(error)}`);
|
|
@@ -16935,7 +17383,7 @@ var init_memory_service = __esm({
|
|
|
16935
17383
|
});
|
|
16936
17384
|
|
|
16937
17385
|
// core/services/nested-context-resolver.ts
|
|
16938
|
-
import
|
|
17386
|
+
import fs35 from "node:fs/promises";
|
|
16939
17387
|
import path36 from "node:path";
|
|
16940
17388
|
var NestedContextResolver;
|
|
16941
17389
|
var init_nested_context_resolver = __esm({
|
|
@@ -16989,7 +17437,7 @@ var init_nested_context_resolver = __esm({
|
|
|
16989
17437
|
* Load a single PRJCT.md file into a NestedContext
|
|
16990
17438
|
*/
|
|
16991
17439
|
async loadContext(filePath, parent, pkg = null) {
|
|
16992
|
-
const content = await
|
|
17440
|
+
const content = await fs35.readFile(filePath, "utf-8");
|
|
16993
17441
|
const relativePath = path36.relative(this.rootPath, filePath);
|
|
16994
17442
|
const depth = relativePath.split(path36.sep).length - 1;
|
|
16995
17443
|
return {
|
|
@@ -17045,7 +17493,7 @@ var init_nested_context_resolver = __esm({
|
|
|
17045
17493
|
const scan = /* @__PURE__ */ __name(async (currentDir, depth) => {
|
|
17046
17494
|
if (depth > 5) return;
|
|
17047
17495
|
try {
|
|
17048
|
-
const entries = await
|
|
17496
|
+
const entries = await fs35.readdir(currentDir, { withFileTypes: true });
|
|
17049
17497
|
for (const entry of entries) {
|
|
17050
17498
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "coverage") {
|
|
17051
17499
|
continue;
|
|
@@ -17212,7 +17660,7 @@ ${content}`);
|
|
|
17212
17660
|
* Load a single AGENTS.md file into a NestedAgents structure
|
|
17213
17661
|
*/
|
|
17214
17662
|
async loadAgents(filePath, parent, pkg = null) {
|
|
17215
|
-
const content = await
|
|
17663
|
+
const content = await fs35.readFile(filePath, "utf-8");
|
|
17216
17664
|
const relativePath = path36.relative(this.rootPath, filePath);
|
|
17217
17665
|
const depth = relativePath.split(path36.sep).length - 1;
|
|
17218
17666
|
return {
|
|
@@ -17347,7 +17795,7 @@ ${content}`);
|
|
|
17347
17795
|
const scan = /* @__PURE__ */ __name(async (currentDir, depth) => {
|
|
17348
17796
|
if (depth > 5) return;
|
|
17349
17797
|
try {
|
|
17350
|
-
const entries = await
|
|
17798
|
+
const entries = await fs35.readdir(currentDir, { withFileTypes: true });
|
|
17351
17799
|
for (const entry of entries) {
|
|
17352
17800
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "coverage") {
|
|
17353
17801
|
continue;
|
|
@@ -17511,150 +17959,6 @@ var init_project_index = __esm({
|
|
|
17511
17959
|
}
|
|
17512
17960
|
});
|
|
17513
17961
|
|
|
17514
|
-
// core/workflow/state-machine.ts
|
|
17515
|
-
var WORKFLOW_STATES, WorkflowStateMachine, workflowStateMachine;
|
|
17516
|
-
var init_state_machine = __esm({
|
|
17517
|
-
"core/workflow/state-machine.ts"() {
|
|
17518
|
-
"use strict";
|
|
17519
|
-
WORKFLOW_STATES = {
|
|
17520
|
-
idle: {
|
|
17521
|
-
transitions: ["task", "next"],
|
|
17522
|
-
prompt: "p. task <description> Start working",
|
|
17523
|
-
description: "No active task"
|
|
17524
|
-
},
|
|
17525
|
-
working: {
|
|
17526
|
-
transitions: ["done", "pause"],
|
|
17527
|
-
prompt: "p. done Complete task | p. pause Switch context",
|
|
17528
|
-
description: "Task in progress"
|
|
17529
|
-
},
|
|
17530
|
-
paused: {
|
|
17531
|
-
transitions: ["resume", "task"],
|
|
17532
|
-
prompt: "p. resume Continue | p. task <new> Start different",
|
|
17533
|
-
description: "Task paused"
|
|
17534
|
-
},
|
|
17535
|
-
completed: {
|
|
17536
|
-
transitions: ["ship", "task", "next"],
|
|
17537
|
-
prompt: "p. ship Ship it | p. task <next> Start next",
|
|
17538
|
-
description: "Task completed"
|
|
17539
|
-
},
|
|
17540
|
-
shipped: {
|
|
17541
|
-
transitions: ["task", "next"],
|
|
17542
|
-
prompt: "p. task <description> Start new task",
|
|
17543
|
-
description: "Feature shipped"
|
|
17544
|
-
}
|
|
17545
|
-
};
|
|
17546
|
-
WorkflowStateMachine = class {
|
|
17547
|
-
static {
|
|
17548
|
-
__name(this, "WorkflowStateMachine");
|
|
17549
|
-
}
|
|
17550
|
-
/**
|
|
17551
|
-
* Get current state from storage state
|
|
17552
|
-
*/
|
|
17553
|
-
getCurrentState(storageState) {
|
|
17554
|
-
const task = storageState?.currentTask;
|
|
17555
|
-
if (!task) {
|
|
17556
|
-
return "idle";
|
|
17557
|
-
}
|
|
17558
|
-
const status = task.status?.toLowerCase();
|
|
17559
|
-
switch (status) {
|
|
17560
|
-
case "in_progress":
|
|
17561
|
-
case "working":
|
|
17562
|
-
return "working";
|
|
17563
|
-
case "paused":
|
|
17564
|
-
return "paused";
|
|
17565
|
-
case "completed":
|
|
17566
|
-
case "done":
|
|
17567
|
-
return "completed";
|
|
17568
|
-
case "shipped":
|
|
17569
|
-
return "shipped";
|
|
17570
|
-
default:
|
|
17571
|
-
return task ? "working" : "idle";
|
|
17572
|
-
}
|
|
17573
|
-
}
|
|
17574
|
-
/**
|
|
17575
|
-
* Check if a command is valid for the current state
|
|
17576
|
-
*/
|
|
17577
|
-
canTransition(currentState, command) {
|
|
17578
|
-
const stateConfig = WORKFLOW_STATES[currentState];
|
|
17579
|
-
if (stateConfig.transitions.includes(command)) {
|
|
17580
|
-
return { valid: true };
|
|
17581
|
-
}
|
|
17582
|
-
const validCommands = stateConfig.transitions.map((c) => `p. ${c}`).join(", ");
|
|
17583
|
-
return {
|
|
17584
|
-
valid: false,
|
|
17585
|
-
error: `Cannot run 'p. ${command}' in ${currentState} state`,
|
|
17586
|
-
suggestion: `Valid commands: ${validCommands}`
|
|
17587
|
-
};
|
|
17588
|
-
}
|
|
17589
|
-
/**
|
|
17590
|
-
* Get the next state after a command
|
|
17591
|
-
*/
|
|
17592
|
-
getNextState(currentState, command) {
|
|
17593
|
-
switch (command) {
|
|
17594
|
-
case "task":
|
|
17595
|
-
return "working";
|
|
17596
|
-
case "done":
|
|
17597
|
-
return "completed";
|
|
17598
|
-
case "pause":
|
|
17599
|
-
return "paused";
|
|
17600
|
-
case "resume":
|
|
17601
|
-
return "working";
|
|
17602
|
-
case "ship":
|
|
17603
|
-
return "shipped";
|
|
17604
|
-
case "next":
|
|
17605
|
-
return currentState;
|
|
17606
|
-
// next doesn't change state
|
|
17607
|
-
default:
|
|
17608
|
-
return currentState;
|
|
17609
|
-
}
|
|
17610
|
-
}
|
|
17611
|
-
/**
|
|
17612
|
-
* Get state definition
|
|
17613
|
-
*/
|
|
17614
|
-
getStateInfo(state) {
|
|
17615
|
-
return WORKFLOW_STATES[state];
|
|
17616
|
-
}
|
|
17617
|
-
/**
|
|
17618
|
-
* Get prompt for current state
|
|
17619
|
-
*/
|
|
17620
|
-
getPrompt(state) {
|
|
17621
|
-
return WORKFLOW_STATES[state].prompt;
|
|
17622
|
-
}
|
|
17623
|
-
/**
|
|
17624
|
-
* Get valid commands for current state
|
|
17625
|
-
*/
|
|
17626
|
-
getValidCommands(state) {
|
|
17627
|
-
return WORKFLOW_STATES[state].transitions;
|
|
17628
|
-
}
|
|
17629
|
-
/**
|
|
17630
|
-
* Format next steps for display
|
|
17631
|
-
*/
|
|
17632
|
-
formatNextSteps(state) {
|
|
17633
|
-
const stateConfig = WORKFLOW_STATES[state];
|
|
17634
|
-
return stateConfig.transitions.map((cmd) => {
|
|
17635
|
-
switch (cmd) {
|
|
17636
|
-
case "task":
|
|
17637
|
-
return "p. task <desc> Start new task";
|
|
17638
|
-
case "done":
|
|
17639
|
-
return "p. done Complete current task";
|
|
17640
|
-
case "pause":
|
|
17641
|
-
return "p. pause Pause and switch context";
|
|
17642
|
-
case "resume":
|
|
17643
|
-
return "p. resume Continue paused task";
|
|
17644
|
-
case "ship":
|
|
17645
|
-
return "p. ship Ship the feature";
|
|
17646
|
-
case "next":
|
|
17647
|
-
return "p. next View task queue";
|
|
17648
|
-
default:
|
|
17649
|
-
return `p. ${cmd}`;
|
|
17650
|
-
}
|
|
17651
|
-
});
|
|
17652
|
-
}
|
|
17653
|
-
};
|
|
17654
|
-
workflowStateMachine = new WorkflowStateMachine();
|
|
17655
|
-
}
|
|
17656
|
-
});
|
|
17657
|
-
|
|
17658
17962
|
// core/utils/next-steps.ts
|
|
17659
17963
|
import chalk9 from "chalk";
|
|
17660
17964
|
function showNextSteps(command, options = {}) {
|
|
@@ -17687,6 +17991,7 @@ var init_next_steps = __esm({
|
|
|
17687
17991
|
pause: "Pause and switch context",
|
|
17688
17992
|
resume: "Continue paused task",
|
|
17689
17993
|
ship: "Ship the feature",
|
|
17994
|
+
reopen: "Reopen for rework",
|
|
17690
17995
|
next: "View task queue",
|
|
17691
17996
|
sync: "Analyze project",
|
|
17692
17997
|
bug: "Report a bug",
|
|
@@ -17700,6 +18005,7 @@ var init_next_steps = __esm({
|
|
|
17700
18005
|
pause: "paused",
|
|
17701
18006
|
resume: "working",
|
|
17702
18007
|
ship: "shipped",
|
|
18008
|
+
reopen: "working",
|
|
17703
18009
|
next: "idle",
|
|
17704
18010
|
sync: "idle",
|
|
17705
18011
|
init: "idle",
|
|
@@ -17980,16 +18286,16 @@ var init_onboarding = __esm({
|
|
|
17980
18286
|
* Detect project type from file system
|
|
17981
18287
|
*/
|
|
17982
18288
|
async detectProjectType() {
|
|
17983
|
-
const
|
|
18289
|
+
const fs53 = await import("node:fs/promises");
|
|
17984
18290
|
const path65 = await import("node:path");
|
|
17985
18291
|
try {
|
|
17986
|
-
const files = await
|
|
18292
|
+
const files = await fs53.readdir(this.projectPath);
|
|
17987
18293
|
if (files.includes("turbo.json") || files.includes("lerna.json") || files.includes("nx.json")) {
|
|
17988
18294
|
return "monorepo";
|
|
17989
18295
|
}
|
|
17990
18296
|
if (files.includes("package.json")) {
|
|
17991
18297
|
const pkgPath = path65.join(this.projectPath, "package.json");
|
|
17992
|
-
const pkgContent = await
|
|
18298
|
+
const pkgContent = await fs53.readFile(pkgPath, "utf-8");
|
|
17993
18299
|
const pkg = JSON.parse(pkgContent);
|
|
17994
18300
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
17995
18301
|
if (pkg.bin) return "cli-tool";
|
|
@@ -18025,32 +18331,32 @@ var init_onboarding = __esm({
|
|
|
18025
18331
|
* Detect installed AI agents from config files
|
|
18026
18332
|
*/
|
|
18027
18333
|
async detectInstalledAgents() {
|
|
18028
|
-
const
|
|
18334
|
+
const fs53 = await import("node:fs/promises");
|
|
18029
18335
|
const path65 = await import("node:path");
|
|
18030
18336
|
const os21 = await import("node:os");
|
|
18031
18337
|
const agents = [];
|
|
18032
18338
|
try {
|
|
18033
|
-
await
|
|
18339
|
+
await fs53.access(path65.join(os21.homedir(), ".claude"));
|
|
18034
18340
|
agents.push("claude");
|
|
18035
18341
|
} catch {
|
|
18036
18342
|
}
|
|
18037
18343
|
try {
|
|
18038
|
-
await
|
|
18344
|
+
await fs53.access(path65.join(this.projectPath, ".cursorrules"));
|
|
18039
18345
|
agents.push("cursor");
|
|
18040
18346
|
} catch {
|
|
18041
18347
|
}
|
|
18042
18348
|
try {
|
|
18043
|
-
await
|
|
18349
|
+
await fs53.access(path65.join(this.projectPath, ".windsurfrules"));
|
|
18044
18350
|
agents.push("windsurf");
|
|
18045
18351
|
} catch {
|
|
18046
18352
|
}
|
|
18047
18353
|
try {
|
|
18048
|
-
await
|
|
18354
|
+
await fs53.access(path65.join(this.projectPath, ".github", "copilot-instructions.md"));
|
|
18049
18355
|
agents.push("copilot");
|
|
18050
18356
|
} catch {
|
|
18051
18357
|
}
|
|
18052
18358
|
try {
|
|
18053
|
-
await
|
|
18359
|
+
await fs53.access(path65.join(os21.homedir(), ".gemini"));
|
|
18054
18360
|
agents.push("gemini");
|
|
18055
18361
|
} catch {
|
|
18056
18362
|
}
|
|
@@ -18060,17 +18366,17 @@ var init_onboarding = __esm({
|
|
|
18060
18366
|
* Detect tech stack from project files
|
|
18061
18367
|
*/
|
|
18062
18368
|
async detectStack() {
|
|
18063
|
-
const
|
|
18369
|
+
const fs53 = await import("node:fs/promises");
|
|
18064
18370
|
const path65 = await import("node:path");
|
|
18065
18371
|
const stack = {
|
|
18066
18372
|
language: "Unknown",
|
|
18067
18373
|
technologies: []
|
|
18068
18374
|
};
|
|
18069
18375
|
try {
|
|
18070
|
-
const files = await
|
|
18376
|
+
const files = await fs53.readdir(this.projectPath);
|
|
18071
18377
|
if (files.includes("package.json")) {
|
|
18072
18378
|
const pkgPath = path65.join(this.projectPath, "package.json");
|
|
18073
|
-
const pkgContent = await
|
|
18379
|
+
const pkgContent = await fs53.readFile(pkgPath, "utf-8");
|
|
18074
18380
|
const pkg = JSON.parse(pkgContent);
|
|
18075
18381
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
18076
18382
|
stack.language = deps.typescript ? "TypeScript" : "JavaScript";
|
|
@@ -18177,14 +18483,14 @@ var init_wizard = __esm({
|
|
|
18177
18483
|
|
|
18178
18484
|
// core/context/generator.ts
|
|
18179
18485
|
import { exec as exec10 } from "node:child_process";
|
|
18180
|
-
import
|
|
18486
|
+
import fs36 from "node:fs/promises";
|
|
18181
18487
|
import path37 from "node:path";
|
|
18182
18488
|
import { promisify as promisify11 } from "node:util";
|
|
18183
18489
|
async function generateContext(projectId, repoPath) {
|
|
18184
18490
|
const _globalPath = path_manager_default.getGlobalProjectPath(projectId);
|
|
18185
18491
|
const contextPath = path_manager_default.getContextPath(projectId);
|
|
18186
18492
|
const storage = getStorage(projectId);
|
|
18187
|
-
await
|
|
18493
|
+
await fs36.mkdir(contextPath, { recursive: true });
|
|
18188
18494
|
const project = await storage.read(["project"]) || {};
|
|
18189
18495
|
const taskPaths = await storage.list(["task"]);
|
|
18190
18496
|
const featurePaths = await storage.list(["feature"]);
|
|
@@ -18267,7 +18573,7 @@ async function getPackageData(repoPath) {
|
|
|
18267
18573
|
};
|
|
18268
18574
|
try {
|
|
18269
18575
|
const pkgPath = path37.join(repoPath, "package.json");
|
|
18270
|
-
const pkg = JSON.parse(await
|
|
18576
|
+
const pkg = JSON.parse(await fs36.readFile(pkgPath, "utf-8"));
|
|
18271
18577
|
data.dependencies = pkg.dependencies || {};
|
|
18272
18578
|
data.devDependencies = pkg.devDependencies || {};
|
|
18273
18579
|
data.scripts = pkg.scripts || {};
|
|
@@ -18351,7 +18657,7 @@ ${agents.length > 0 ? agents.map((a) => `- **${a.name}**: ${a.role || "Specialis
|
|
|
18351
18657
|
\u2514\u2500\u2500 pending.json
|
|
18352
18658
|
\`\`\`
|
|
18353
18659
|
`;
|
|
18354
|
-
await
|
|
18660
|
+
await fs36.writeFile(path37.join(contextPath, "CLAUDE.md"), content, "utf-8");
|
|
18355
18661
|
}
|
|
18356
18662
|
async function generateNowMd(contextPath, tasks) {
|
|
18357
18663
|
const currentTask = tasks.find((t) => t.status === "in_progress");
|
|
@@ -18366,7 +18672,7 @@ async function generateNowMd(contextPath, tasks) {
|
|
|
18366
18672
|
|
|
18367
18673
|
_No active task. Use /p:now to start._
|
|
18368
18674
|
`;
|
|
18369
|
-
await
|
|
18675
|
+
await fs36.writeFile(path37.join(contextPath, "now.md"), content, "utf-8");
|
|
18370
18676
|
}
|
|
18371
18677
|
async function generateQueueMd(contextPath, tasks) {
|
|
18372
18678
|
const pendingTasks = tasks.filter((t) => t.status === "pending");
|
|
@@ -18374,7 +18680,7 @@ async function generateQueueMd(contextPath, tasks) {
|
|
|
18374
18680
|
|
|
18375
18681
|
${pendingTasks.length > 0 ? pendingTasks.map((t, i) => `${i + 1}. ${t.description}${t.priority ? ` [${t.priority}]` : ""}`).join("\n") : "_Empty queue. Use /p:next to add tasks._"}
|
|
18376
18682
|
`;
|
|
18377
|
-
await
|
|
18683
|
+
await fs36.writeFile(path37.join(contextPath, "queue.md"), content, "utf-8");
|
|
18378
18684
|
}
|
|
18379
18685
|
async function generateSummaryMd(contextPath, project, gitData, pkgData) {
|
|
18380
18686
|
const content = `# PROJECT SUMMARY
|
|
@@ -18394,7 +18700,7 @@ async function generateSummaryMd(contextPath, project, gitData, pkgData) {
|
|
|
18394
18700
|
- Production: ${Object.keys(pkgData.dependencies).length}
|
|
18395
18701
|
- Dev: ${Object.keys(pkgData.devDependencies).length}
|
|
18396
18702
|
`;
|
|
18397
|
-
await
|
|
18703
|
+
await fs36.writeFile(path37.join(contextPath, "summary.md"), content, "utf-8");
|
|
18398
18704
|
}
|
|
18399
18705
|
var execAsync7;
|
|
18400
18706
|
var init_generator = __esm({
|
|
@@ -18415,7 +18721,7 @@ var init_generator = __esm({
|
|
|
18415
18721
|
|
|
18416
18722
|
// core/domain/analyzer.ts
|
|
18417
18723
|
import { exec as execCallback6 } from "node:child_process";
|
|
18418
|
-
import
|
|
18724
|
+
import fs37 from "node:fs/promises";
|
|
18419
18725
|
import path38 from "node:path";
|
|
18420
18726
|
import { promisify as promisify12 } from "node:util";
|
|
18421
18727
|
var exec11, CodebaseAnalyzer, analyzer, analyzer_default2;
|
|
@@ -18441,7 +18747,7 @@ var init_analyzer2 = __esm({
|
|
|
18441
18747
|
async readPackageJson() {
|
|
18442
18748
|
try {
|
|
18443
18749
|
const packagePath = path38.join(this.projectPath, "package.json");
|
|
18444
|
-
const content = await
|
|
18750
|
+
const content = await fs37.readFile(packagePath, "utf-8");
|
|
18445
18751
|
return JSON.parse(content);
|
|
18446
18752
|
} catch (error) {
|
|
18447
18753
|
if (isNotFoundError(error) || error instanceof SyntaxError) {
|
|
@@ -18456,7 +18762,7 @@ var init_analyzer2 = __esm({
|
|
|
18456
18762
|
async readCargoToml() {
|
|
18457
18763
|
try {
|
|
18458
18764
|
const cargoPath = path38.join(this.projectPath, "Cargo.toml");
|
|
18459
|
-
return await
|
|
18765
|
+
return await fs37.readFile(cargoPath, "utf-8");
|
|
18460
18766
|
} catch (error) {
|
|
18461
18767
|
if (isNotFoundError(error)) {
|
|
18462
18768
|
return null;
|
|
@@ -18470,7 +18776,7 @@ var init_analyzer2 = __esm({
|
|
|
18470
18776
|
async readRequirements() {
|
|
18471
18777
|
try {
|
|
18472
18778
|
const reqPath = path38.join(this.projectPath, "requirements.txt");
|
|
18473
|
-
return await
|
|
18779
|
+
return await fs37.readFile(reqPath, "utf-8");
|
|
18474
18780
|
} catch (error) {
|
|
18475
18781
|
if (isNotFoundError(error)) {
|
|
18476
18782
|
return null;
|
|
@@ -18484,7 +18790,7 @@ var init_analyzer2 = __esm({
|
|
|
18484
18790
|
async readGoMod() {
|
|
18485
18791
|
try {
|
|
18486
18792
|
const goModPath = path38.join(this.projectPath, "go.mod");
|
|
18487
|
-
return await
|
|
18793
|
+
return await fs37.readFile(goModPath, "utf-8");
|
|
18488
18794
|
} catch (error) {
|
|
18489
18795
|
if (isNotFoundError(error)) {
|
|
18490
18796
|
return null;
|
|
@@ -18498,7 +18804,7 @@ var init_analyzer2 = __esm({
|
|
|
18498
18804
|
async readGemfile() {
|
|
18499
18805
|
try {
|
|
18500
18806
|
const gemfilePath = path38.join(this.projectPath, "Gemfile");
|
|
18501
|
-
return await
|
|
18807
|
+
return await fs37.readFile(gemfilePath, "utf-8");
|
|
18502
18808
|
} catch (error) {
|
|
18503
18809
|
if (isNotFoundError(error)) {
|
|
18504
18810
|
return null;
|
|
@@ -18512,7 +18818,7 @@ var init_analyzer2 = __esm({
|
|
|
18512
18818
|
async readMixExs() {
|
|
18513
18819
|
try {
|
|
18514
18820
|
const mixPath = path38.join(this.projectPath, "mix.exs");
|
|
18515
|
-
return await
|
|
18821
|
+
return await fs37.readFile(mixPath, "utf-8");
|
|
18516
18822
|
} catch (error) {
|
|
18517
18823
|
if (isNotFoundError(error)) {
|
|
18518
18824
|
return null;
|
|
@@ -18526,7 +18832,7 @@ var init_analyzer2 = __esm({
|
|
|
18526
18832
|
async readPomXml() {
|
|
18527
18833
|
try {
|
|
18528
18834
|
const pomPath = path38.join(this.projectPath, "pom.xml");
|
|
18529
|
-
return await
|
|
18835
|
+
return await fs37.readFile(pomPath, "utf-8");
|
|
18530
18836
|
} catch (error) {
|
|
18531
18837
|
if (isNotFoundError(error)) {
|
|
18532
18838
|
return null;
|
|
@@ -18540,7 +18846,7 @@ var init_analyzer2 = __esm({
|
|
|
18540
18846
|
async readComposerJson() {
|
|
18541
18847
|
try {
|
|
18542
18848
|
const composerPath = path38.join(this.projectPath, "composer.json");
|
|
18543
|
-
const content = await
|
|
18849
|
+
const content = await fs37.readFile(composerPath, "utf-8");
|
|
18544
18850
|
return JSON.parse(content);
|
|
18545
18851
|
} catch (error) {
|
|
18546
18852
|
if (isNotFoundError(error) || error instanceof SyntaxError) {
|
|
@@ -18555,7 +18861,7 @@ var init_analyzer2 = __esm({
|
|
|
18555
18861
|
async readPyprojectToml() {
|
|
18556
18862
|
try {
|
|
18557
18863
|
const pyprojectPath = path38.join(this.projectPath, "pyproject.toml");
|
|
18558
|
-
return await
|
|
18864
|
+
return await fs37.readFile(pyprojectPath, "utf-8");
|
|
18559
18865
|
} catch (error) {
|
|
18560
18866
|
if (isNotFoundError(error)) {
|
|
18561
18867
|
return null;
|
|
@@ -18591,7 +18897,7 @@ var init_analyzer2 = __esm({
|
|
|
18591
18897
|
*/
|
|
18592
18898
|
async listConfigFiles() {
|
|
18593
18899
|
try {
|
|
18594
|
-
const entries = await
|
|
18900
|
+
const entries = await fs37.readdir(this.projectPath);
|
|
18595
18901
|
const configPatterns = [
|
|
18596
18902
|
/^package\.json$/,
|
|
18597
18903
|
/^Cargo\.toml$/,
|
|
@@ -18621,7 +18927,7 @@ var init_analyzer2 = __esm({
|
|
|
18621
18927
|
*/
|
|
18622
18928
|
async listDirectories() {
|
|
18623
18929
|
try {
|
|
18624
|
-
const entries = await
|
|
18930
|
+
const entries = await fs37.readdir(this.projectPath, { withFileTypes: true });
|
|
18625
18931
|
return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => !name.startsWith(".") && name !== "node_modules");
|
|
18626
18932
|
} catch (error) {
|
|
18627
18933
|
if (isNotFoundError(error)) {
|
|
@@ -18692,7 +18998,7 @@ var init_analyzer2 = __esm({
|
|
|
18692
18998
|
*/
|
|
18693
18999
|
async fileExists(filename) {
|
|
18694
19000
|
try {
|
|
18695
|
-
await
|
|
19001
|
+
await fs37.access(path38.join(this.projectPath, filename));
|
|
18696
19002
|
return true;
|
|
18697
19003
|
} catch (error) {
|
|
18698
19004
|
if (isNotFoundError(error)) {
|
|
@@ -18707,7 +19013,7 @@ var init_analyzer2 = __esm({
|
|
|
18707
19013
|
async readFile(relativePath) {
|
|
18708
19014
|
try {
|
|
18709
19015
|
const fullPath = path38.join(this.projectPath, relativePath);
|
|
18710
|
-
return await
|
|
19016
|
+
return await fs37.readFile(fullPath, "utf-8");
|
|
18711
19017
|
} catch (error) {
|
|
18712
19018
|
if (isNotFoundError(error)) {
|
|
18713
19019
|
return null;
|
|
@@ -18955,7 +19261,7 @@ var analysis_exports = {};
|
|
|
18955
19261
|
__export(analysis_exports, {
|
|
18956
19262
|
AnalysisCommands: () => AnalysisCommands
|
|
18957
19263
|
});
|
|
18958
|
-
import
|
|
19264
|
+
import fs38 from "node:fs/promises";
|
|
18959
19265
|
import path39 from "node:path";
|
|
18960
19266
|
import prompts2 from "prompts";
|
|
18961
19267
|
var AnalysisCommands;
|
|
@@ -19187,7 +19493,7 @@ var init_analysis2 = __esm({
|
|
|
19187
19493
|
const claudeMdPath = path39.join(globalPath, "context", "CLAUDE.md");
|
|
19188
19494
|
let existingContent = null;
|
|
19189
19495
|
try {
|
|
19190
|
-
existingContent = await
|
|
19496
|
+
existingContent = await fs38.readFile(claudeMdPath, "utf-8");
|
|
19191
19497
|
} catch {
|
|
19192
19498
|
}
|
|
19193
19499
|
const isNonInteractive = !process.stdin.isTTY || options.json;
|
|
@@ -19206,7 +19512,7 @@ var init_analysis2 = __esm({
|
|
|
19206
19512
|
}
|
|
19207
19513
|
let newContent;
|
|
19208
19514
|
try {
|
|
19209
|
-
newContent = await
|
|
19515
|
+
newContent = await fs38.readFile(claudeMdPath, "utf-8");
|
|
19210
19516
|
} catch {
|
|
19211
19517
|
newContent = "";
|
|
19212
19518
|
}
|
|
@@ -19230,7 +19536,7 @@ var init_analysis2 = __esm({
|
|
|
19230
19536
|
}
|
|
19231
19537
|
const restoreOriginal = /* @__PURE__ */ __name(async () => {
|
|
19232
19538
|
if (existingContent != null) {
|
|
19233
|
-
await
|
|
19539
|
+
await fs38.writeFile(claudeMdPath, existingContent, "utf-8");
|
|
19234
19540
|
}
|
|
19235
19541
|
}, "restoreOriginal");
|
|
19236
19542
|
if (isNonInteractive) {
|
|
@@ -19449,7 +19755,7 @@ ${formatFullDiff(diff)}`);
|
|
|
19449
19755
|
let projectName = "Unknown";
|
|
19450
19756
|
try {
|
|
19451
19757
|
const projectJson = JSON.parse(
|
|
19452
|
-
await
|
|
19758
|
+
await fs38.readFile(path39.join(globalPath, "project.json"), "utf-8")
|
|
19453
19759
|
);
|
|
19454
19760
|
projectName = projectJson.name || "Unknown";
|
|
19455
19761
|
} catch {
|
|
@@ -20204,8 +20510,8 @@ Generated: ${(/* @__PURE__ */ new Date()).toLocaleString()}
|
|
|
20204
20510
|
const globalPath2 = path_manager_default.getGlobalProjectPath(projectId);
|
|
20205
20511
|
const specsPath2 = path40.join(globalPath2, "planning", "specs");
|
|
20206
20512
|
try {
|
|
20207
|
-
const
|
|
20208
|
-
const files = await
|
|
20513
|
+
const fs53 = await import("node:fs/promises");
|
|
20514
|
+
const files = await fs53.readdir(specsPath2);
|
|
20209
20515
|
const specs = files.filter((f) => f.endsWith(".md") && f !== ".gitkeep");
|
|
20210
20516
|
if (specs.length === 0) {
|
|
20211
20517
|
output_default.warn("no specs yet");
|
|
@@ -20419,7 +20725,7 @@ var init_project_service = __esm({
|
|
|
20419
20725
|
|
|
20420
20726
|
// core/services/staleness-checker.ts
|
|
20421
20727
|
import { exec as exec12 } from "node:child_process";
|
|
20422
|
-
import
|
|
20728
|
+
import fs39 from "node:fs/promises";
|
|
20423
20729
|
import path41 from "node:path";
|
|
20424
20730
|
import { promisify as promisify13 } from "node:util";
|
|
20425
20731
|
var execAsync8, DEFAULT_CONFIG, StalenessChecker, createStalenessChecker;
|
|
@@ -20473,7 +20779,7 @@ var init_staleness_checker = __esm({
|
|
|
20473
20779
|
const projectJsonPath = path41.join(path_manager_default.getGlobalProjectPath(projectId), "project.json");
|
|
20474
20780
|
let projectJson = {};
|
|
20475
20781
|
try {
|
|
20476
|
-
projectJson = JSON.parse(await
|
|
20782
|
+
projectJson = JSON.parse(await fs39.readFile(projectJsonPath, "utf-8"));
|
|
20477
20783
|
} catch {
|
|
20478
20784
|
status.isStale = true;
|
|
20479
20785
|
status.reason = "No sync history found. Run `prjct sync` to initialize.";
|
|
@@ -21040,7 +21346,7 @@ var init_registry = __esm({
|
|
|
21040
21346
|
});
|
|
21041
21347
|
|
|
21042
21348
|
// core/ai-tools/generator.ts
|
|
21043
|
-
import
|
|
21349
|
+
import fs40 from "node:fs/promises";
|
|
21044
21350
|
import path43 from "node:path";
|
|
21045
21351
|
async function generateAIToolContexts(context2, globalPath, repoPath, toolIds = DEFAULT_AI_TOOLS) {
|
|
21046
21352
|
const results = [];
|
|
@@ -21080,9 +21386,9 @@ async function generateForTool(context2, config, globalPath, repoPath) {
|
|
|
21080
21386
|
} else {
|
|
21081
21387
|
outputPath = path43.join(globalPath, "context", config.outputFile);
|
|
21082
21388
|
}
|
|
21083
|
-
await
|
|
21389
|
+
await fs40.mkdir(path43.dirname(outputPath), { recursive: true });
|
|
21084
21390
|
try {
|
|
21085
|
-
const existingContent = await
|
|
21391
|
+
const existingContent = await fs40.readFile(outputPath, "utf-8");
|
|
21086
21392
|
const validation = validatePreserveBlocks(existingContent);
|
|
21087
21393
|
if (!validation.valid) {
|
|
21088
21394
|
console.warn(`\u26A0\uFE0F ${config.outputFile} has invalid preserve blocks:`);
|
|
@@ -21093,7 +21399,7 @@ async function generateForTool(context2, config, globalPath, repoPath) {
|
|
|
21093
21399
|
content = mergePreservedSections(content, existingContent);
|
|
21094
21400
|
} catch {
|
|
21095
21401
|
}
|
|
21096
|
-
await
|
|
21402
|
+
await fs40.writeFile(outputPath, content, "utf-8");
|
|
21097
21403
|
return {
|
|
21098
21404
|
toolId: config.id,
|
|
21099
21405
|
outputFile: config.outputFile,
|
|
@@ -21133,7 +21439,7 @@ var init_ai_tools = __esm({
|
|
|
21133
21439
|
});
|
|
21134
21440
|
|
|
21135
21441
|
// core/services/context-generator.ts
|
|
21136
|
-
import
|
|
21442
|
+
import fs41 from "node:fs/promises";
|
|
21137
21443
|
import path44 from "node:path";
|
|
21138
21444
|
var ContextFileGenerator;
|
|
21139
21445
|
var init_context_generator = __esm({
|
|
@@ -21159,7 +21465,7 @@ var init_context_generator = __esm({
|
|
|
21159
21465
|
async writeWithPreservation(filePath, content) {
|
|
21160
21466
|
let finalContent = content;
|
|
21161
21467
|
try {
|
|
21162
|
-
const existingContent = await
|
|
21468
|
+
const existingContent = await fs41.readFile(filePath, "utf-8");
|
|
21163
21469
|
const validation = validatePreserveBlocks(existingContent);
|
|
21164
21470
|
if (!validation.valid) {
|
|
21165
21471
|
const filename = path44.basename(filePath);
|
|
@@ -21171,7 +21477,7 @@ var init_context_generator = __esm({
|
|
|
21171
21477
|
finalContent = mergePreservedSections(content, existingContent);
|
|
21172
21478
|
} catch {
|
|
21173
21479
|
}
|
|
21174
|
-
await
|
|
21480
|
+
await fs41.writeFile(filePath, finalContent, "utf-8");
|
|
21175
21481
|
}
|
|
21176
21482
|
/**
|
|
21177
21483
|
* Generate all context files in parallel
|
|
@@ -21287,7 +21593,7 @@ Load from \`~/.prjct-cli/projects/${this.config.projectId}/agents/\`:
|
|
|
21287
21593
|
let currentTask = null;
|
|
21288
21594
|
try {
|
|
21289
21595
|
const statePath = path44.join(this.config.globalPath, "storage", "state.json");
|
|
21290
|
-
const state = JSON.parse(await
|
|
21596
|
+
const state = JSON.parse(await fs41.readFile(statePath, "utf-8"));
|
|
21291
21597
|
currentTask = state.currentTask;
|
|
21292
21598
|
} catch {
|
|
21293
21599
|
}
|
|
@@ -21312,7 +21618,7 @@ Use \`p. task "description"\` to start working.
|
|
|
21312
21618
|
let queue = { tasks: [] };
|
|
21313
21619
|
try {
|
|
21314
21620
|
const queuePath = path44.join(this.config.globalPath, "storage", "queue.json");
|
|
21315
|
-
queue = JSON.parse(await
|
|
21621
|
+
queue = JSON.parse(await fs41.readFile(queuePath, "utf-8"));
|
|
21316
21622
|
} catch {
|
|
21317
21623
|
}
|
|
21318
21624
|
const content = `# NEXT
|
|
@@ -21328,7 +21634,7 @@ ${queue.tasks.length > 0 ? queue.tasks.map((t, i) => `${i + 1}. ${t.description}
|
|
|
21328
21634
|
let ideas = { ideas: [] };
|
|
21329
21635
|
try {
|
|
21330
21636
|
const ideasPath = path44.join(this.config.globalPath, "storage", "ideas.json");
|
|
21331
|
-
ideas = JSON.parse(await
|
|
21637
|
+
ideas = JSON.parse(await fs41.readFile(ideasPath, "utf-8"));
|
|
21332
21638
|
} catch {
|
|
21333
21639
|
}
|
|
21334
21640
|
const content = `# IDEAS
|
|
@@ -21346,7 +21652,7 @@ ${ideas.ideas.length > 0 ? ideas.ideas.map((i) => `- ${i.text}${i.priority ? ` [
|
|
|
21346
21652
|
};
|
|
21347
21653
|
try {
|
|
21348
21654
|
const shippedPath = path44.join(this.config.globalPath, "storage", "shipped.json");
|
|
21349
|
-
shipped = JSON.parse(await
|
|
21655
|
+
shipped = JSON.parse(await fs41.readFile(shippedPath, "utf-8"));
|
|
21350
21656
|
} catch {
|
|
21351
21657
|
}
|
|
21352
21658
|
const content = `# SHIPPED \u{1F680}
|
|
@@ -21400,7 +21706,7 @@ ${shipped.shipped.length > 0 ? shipped.shipped.slice(-10).map((s) => `- **${s.na
|
|
|
21400
21706
|
let pkgName = pkg.name;
|
|
21401
21707
|
try {
|
|
21402
21708
|
const pkgJsonPath = path44.join(pkg.path, "package.json");
|
|
21403
|
-
const pkgJson = JSON.parse(await
|
|
21709
|
+
const pkgJson = JSON.parse(await fs41.readFile(pkgJsonPath, "utf-8"));
|
|
21404
21710
|
pkgVersion = pkgJson.version || stats.version;
|
|
21405
21711
|
pkgName = pkgJson.name || pkg.name;
|
|
21406
21712
|
} catch {
|
|
@@ -21465,7 +21771,7 @@ Load from \`~/.prjct-cli/projects/${this.config.projectId}/agents/\`:
|
|
|
21465
21771
|
});
|
|
21466
21772
|
|
|
21467
21773
|
// core/services/local-state-generator.ts
|
|
21468
|
-
import
|
|
21774
|
+
import fs42 from "node:fs/promises";
|
|
21469
21775
|
import path45 from "node:path";
|
|
21470
21776
|
var LOCAL_STATE_FILENAME, LocalStateGenerator, localStateGenerator;
|
|
21471
21777
|
var init_local_state_generator = __esm({
|
|
@@ -21483,7 +21789,7 @@ var init_local_state_generator = __esm({
|
|
|
21483
21789
|
async generate(projectPath, state) {
|
|
21484
21790
|
const filePath = path45.join(projectPath, LOCAL_STATE_FILENAME);
|
|
21485
21791
|
const content = this.toMarkdown(state);
|
|
21486
|
-
await
|
|
21792
|
+
await fs42.writeFile(filePath, content, "utf-8");
|
|
21487
21793
|
}
|
|
21488
21794
|
/**
|
|
21489
21795
|
* Remove local state file
|
|
@@ -21491,7 +21797,7 @@ var init_local_state_generator = __esm({
|
|
|
21491
21797
|
async remove(projectPath) {
|
|
21492
21798
|
const filePath = path45.join(projectPath, LOCAL_STATE_FILENAME);
|
|
21493
21799
|
try {
|
|
21494
|
-
await
|
|
21800
|
+
await fs42.unlink(filePath);
|
|
21495
21801
|
} catch (error) {
|
|
21496
21802
|
if (!isNotFoundError(error)) throw error;
|
|
21497
21803
|
}
|
|
@@ -21502,7 +21808,7 @@ var init_local_state_generator = __esm({
|
|
|
21502
21808
|
async exists(projectPath) {
|
|
21503
21809
|
const filePath = path45.join(projectPath, LOCAL_STATE_FILENAME);
|
|
21504
21810
|
try {
|
|
21505
|
-
await
|
|
21811
|
+
await fs42.access(filePath);
|
|
21506
21812
|
return true;
|
|
21507
21813
|
} catch {
|
|
21508
21814
|
return false;
|
|
@@ -21581,7 +21887,7 @@ var init_local_state_generator = __esm({
|
|
|
21581
21887
|
});
|
|
21582
21888
|
|
|
21583
21889
|
// core/services/skill-lock.ts
|
|
21584
|
-
import
|
|
21890
|
+
import fs43 from "node:fs/promises";
|
|
21585
21891
|
import os13 from "node:os";
|
|
21586
21892
|
import path46 from "node:path";
|
|
21587
21893
|
function getLockFilePath() {
|
|
@@ -21596,7 +21902,7 @@ function createEmptyLockFile() {
|
|
|
21596
21902
|
}
|
|
21597
21903
|
async function read() {
|
|
21598
21904
|
try {
|
|
21599
|
-
const content = await
|
|
21905
|
+
const content = await fs43.readFile(getLockFilePath(), "utf-8");
|
|
21600
21906
|
return JSON.parse(content);
|
|
21601
21907
|
} catch {
|
|
21602
21908
|
return createEmptyLockFile();
|
|
@@ -21604,9 +21910,9 @@ async function read() {
|
|
|
21604
21910
|
}
|
|
21605
21911
|
async function write(lockFile) {
|
|
21606
21912
|
const lockPath = getLockFilePath();
|
|
21607
|
-
await
|
|
21913
|
+
await fs43.mkdir(path46.dirname(lockPath), { recursive: true });
|
|
21608
21914
|
lockFile.generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21609
|
-
await
|
|
21915
|
+
await fs43.writeFile(lockPath, JSON.stringify(lockFile, null, 2), "utf-8");
|
|
21610
21916
|
}
|
|
21611
21917
|
async function addEntry(entry) {
|
|
21612
21918
|
const lockFile = await read();
|
|
@@ -21659,7 +21965,7 @@ var init_skill_lock = __esm({
|
|
|
21659
21965
|
|
|
21660
21966
|
// core/services/skill-installer.ts
|
|
21661
21967
|
import { exec as execCallback7 } from "node:child_process";
|
|
21662
|
-
import
|
|
21968
|
+
import fs44 from "node:fs/promises";
|
|
21663
21969
|
import os14 from "node:os";
|
|
21664
21970
|
import path47 from "node:path";
|
|
21665
21971
|
import { promisify as promisify15 } from "node:util";
|
|
@@ -21705,7 +22011,7 @@ async function discoverSkills(dir) {
|
|
|
21705
22011
|
const skills = [];
|
|
21706
22012
|
try {
|
|
21707
22013
|
const rootSkill = path47.join(dir, "SKILL.md");
|
|
21708
|
-
await
|
|
22014
|
+
await fs44.access(rootSkill);
|
|
21709
22015
|
const dirName = path47.basename(dir);
|
|
21710
22016
|
skills.push({ name: dirName, filePath: rootSkill });
|
|
21711
22017
|
} catch {
|
|
@@ -21761,10 +22067,10 @@ async function installSkillFile(sourcePath, name, source, sha) {
|
|
|
21761
22067
|
const installDir = getInstallDir();
|
|
21762
22068
|
const targetDir = path47.join(installDir, name);
|
|
21763
22069
|
const targetPath = path47.join(targetDir, "SKILL.md");
|
|
21764
|
-
const content = await
|
|
22070
|
+
const content = await fs44.readFile(sourcePath, "utf-8");
|
|
21765
22071
|
const enrichedContent = injectSourceMetadata(content, source, sha);
|
|
21766
|
-
await
|
|
21767
|
-
await
|
|
22072
|
+
await fs44.mkdir(targetDir, { recursive: true });
|
|
22073
|
+
await fs44.writeFile(targetPath, enrichedContent, "utf-8");
|
|
21768
22074
|
return {
|
|
21769
22075
|
name,
|
|
21770
22076
|
filePath: targetPath,
|
|
@@ -21825,7 +22131,7 @@ async function installFromGitHub(source) {
|
|
|
21825
22131
|
}
|
|
21826
22132
|
} finally {
|
|
21827
22133
|
try {
|
|
21828
|
-
await
|
|
22134
|
+
await fs44.rm(tmpDir, { recursive: true, force: true });
|
|
21829
22135
|
} catch {
|
|
21830
22136
|
}
|
|
21831
22137
|
}
|
|
@@ -21835,12 +22141,12 @@ async function installFromLocal(source) {
|
|
|
21835
22141
|
const result = { installed: [], skipped: [], errors: [] };
|
|
21836
22142
|
const localPath = source.localPath;
|
|
21837
22143
|
try {
|
|
21838
|
-
await
|
|
22144
|
+
await fs44.access(localPath);
|
|
21839
22145
|
} catch {
|
|
21840
22146
|
result.errors.push(`Local path not found: ${localPath}`);
|
|
21841
22147
|
return result;
|
|
21842
22148
|
}
|
|
21843
|
-
const stat = await
|
|
22149
|
+
const stat = await fs44.stat(localPath);
|
|
21844
22150
|
if (stat.isFile()) {
|
|
21845
22151
|
const name = path47.basename(path47.dirname(localPath));
|
|
21846
22152
|
try {
|
|
@@ -21884,12 +22190,12 @@ async function remove(name) {
|
|
|
21884
22190
|
const installDir = getInstallDir();
|
|
21885
22191
|
const subdirPath = path47.join(installDir, name);
|
|
21886
22192
|
try {
|
|
21887
|
-
await
|
|
22193
|
+
await fs44.rm(subdirPath, { recursive: true, force: true });
|
|
21888
22194
|
} catch {
|
|
21889
22195
|
}
|
|
21890
22196
|
const flatPath = path47.join(installDir, `${name}.md`);
|
|
21891
22197
|
try {
|
|
21892
|
-
await
|
|
22198
|
+
await fs44.rm(flatPath, { force: true });
|
|
21893
22199
|
} catch {
|
|
21894
22200
|
}
|
|
21895
22201
|
return skillLock.removeEntry(name);
|
|
@@ -21937,7 +22243,7 @@ var init_skill_installer = __esm({
|
|
|
21937
22243
|
});
|
|
21938
22244
|
|
|
21939
22245
|
// core/services/stack-detector.ts
|
|
21940
|
-
import
|
|
22246
|
+
import fs45 from "node:fs/promises";
|
|
21941
22247
|
import path48 from "node:path";
|
|
21942
22248
|
var StackDetector;
|
|
21943
22249
|
var init_stack_detector = __esm({
|
|
@@ -22098,7 +22404,7 @@ var init_stack_detector = __esm({
|
|
|
22098
22404
|
async readPackageJson() {
|
|
22099
22405
|
try {
|
|
22100
22406
|
const pkgPath = path48.join(this.projectPath, "package.json");
|
|
22101
|
-
const content = await
|
|
22407
|
+
const content = await fs45.readFile(pkgPath, "utf-8");
|
|
22102
22408
|
return JSON.parse(content);
|
|
22103
22409
|
} catch {
|
|
22104
22410
|
return null;
|
|
@@ -22109,7 +22415,7 @@ var init_stack_detector = __esm({
|
|
|
22109
22415
|
*/
|
|
22110
22416
|
async fileExists(filename) {
|
|
22111
22417
|
try {
|
|
22112
|
-
await
|
|
22418
|
+
await fs45.access(path48.join(this.projectPath, filename));
|
|
22113
22419
|
return true;
|
|
22114
22420
|
} catch {
|
|
22115
22421
|
return false;
|
|
@@ -22121,7 +22427,7 @@ var init_stack_detector = __esm({
|
|
|
22121
22427
|
|
|
22122
22428
|
// core/services/sync-verifier.ts
|
|
22123
22429
|
import { exec as exec15 } from "node:child_process";
|
|
22124
|
-
import
|
|
22430
|
+
import fs46 from "node:fs/promises";
|
|
22125
22431
|
import path49 from "node:path";
|
|
22126
22432
|
import { promisify as promisify16 } from "node:util";
|
|
22127
22433
|
var execAsync10, BUILTIN_CHECKS, SyncVerifier, syncVerifier;
|
|
@@ -22141,7 +22447,7 @@ var init_sync_verifier = __esm({
|
|
|
22141
22447
|
for (const file of expected) {
|
|
22142
22448
|
const filePath = path49.join(globalPath, file);
|
|
22143
22449
|
try {
|
|
22144
|
-
await
|
|
22450
|
+
await fs46.access(filePath);
|
|
22145
22451
|
} catch {
|
|
22146
22452
|
missing.push(file);
|
|
22147
22453
|
}
|
|
@@ -22164,7 +22470,7 @@ var init_sync_verifier = __esm({
|
|
|
22164
22470
|
for (const file of jsonFiles) {
|
|
22165
22471
|
const filePath = path49.join(globalPath, file);
|
|
22166
22472
|
try {
|
|
22167
|
-
const content = await
|
|
22473
|
+
const content = await fs46.readFile(filePath, "utf-8");
|
|
22168
22474
|
JSON.parse(content);
|
|
22169
22475
|
} catch (error) {
|
|
22170
22476
|
if (!isNotFoundError(error)) {
|
|
@@ -22193,10 +22499,10 @@ var init_sync_verifier = __esm({
|
|
|
22193
22499
|
];
|
|
22194
22500
|
const violations = [];
|
|
22195
22501
|
try {
|
|
22196
|
-
const files = await
|
|
22502
|
+
const files = await fs46.readdir(contextDir);
|
|
22197
22503
|
for (const file of files) {
|
|
22198
22504
|
if (!file.endsWith(".md")) continue;
|
|
22199
|
-
const content = await
|
|
22505
|
+
const content = await fs46.readFile(path49.join(contextDir, file), "utf-8");
|
|
22200
22506
|
for (const pattern of patterns) {
|
|
22201
22507
|
if (pattern.test(content)) {
|
|
22202
22508
|
violations.push(`${file}: potential sensitive data detected`);
|
|
@@ -22317,7 +22623,7 @@ var init_sync_verifier = __esm({
|
|
|
22317
22623
|
|
|
22318
22624
|
// core/services/sync-service.ts
|
|
22319
22625
|
import { exec as exec16 } from "node:child_process";
|
|
22320
|
-
import
|
|
22626
|
+
import fs47 from "node:fs/promises";
|
|
22321
22627
|
import os15 from "node:os";
|
|
22322
22628
|
import path50 from "node:path";
|
|
22323
22629
|
import { promisify as promisify17 } from "node:util";
|
|
@@ -22495,7 +22801,7 @@ var init_sync_service = __esm({
|
|
|
22495
22801
|
async ensureDirectories() {
|
|
22496
22802
|
const dirs = ["storage", "context", "agents", "memory", "analysis", "config", "sync"];
|
|
22497
22803
|
await Promise.all(
|
|
22498
|
-
dirs.map((dir) =>
|
|
22804
|
+
dirs.map((dir) => fs47.mkdir(path50.join(this.globalPath, dir), { recursive: true }))
|
|
22499
22805
|
);
|
|
22500
22806
|
}
|
|
22501
22807
|
// ==========================================================================
|
|
@@ -22584,7 +22890,7 @@ var init_sync_service = __esm({
|
|
|
22584
22890
|
}
|
|
22585
22891
|
try {
|
|
22586
22892
|
const pkgPath = path50.join(this.projectPath, "package.json");
|
|
22587
|
-
const pkg = JSON.parse(await
|
|
22893
|
+
const pkg = JSON.parse(await fs47.readFile(pkgPath, "utf-8"));
|
|
22588
22894
|
stats.version = pkg.version || "0.0.0";
|
|
22589
22895
|
stats.name = pkg.name || stats.name;
|
|
22590
22896
|
stats.ecosystem = "JavaScript";
|
|
@@ -22731,10 +23037,10 @@ var init_sync_service = __esm({
|
|
|
22731
23037
|
const agents = [];
|
|
22732
23038
|
const agentsPath = path50.join(this.globalPath, "agents");
|
|
22733
23039
|
try {
|
|
22734
|
-
const files = await
|
|
23040
|
+
const files = await fs47.readdir(agentsPath);
|
|
22735
23041
|
for (const file of files) {
|
|
22736
23042
|
if (file.endsWith(".md")) {
|
|
22737
|
-
await
|
|
23043
|
+
await fs47.unlink(path50.join(agentsPath, file));
|
|
22738
23044
|
}
|
|
22739
23045
|
}
|
|
22740
23046
|
} catch (error) {
|
|
@@ -22792,7 +23098,7 @@ var init_sync_service = __esm({
|
|
|
22792
23098
|
`${partialName}.md`
|
|
22793
23099
|
);
|
|
22794
23100
|
try {
|
|
22795
|
-
const partialContent = await
|
|
23101
|
+
const partialContent = await fs47.readFile(partialPath, "utf-8");
|
|
22796
23102
|
resolved = resolved.replace(match[0], partialContent.trim());
|
|
22797
23103
|
} catch {
|
|
22798
23104
|
resolved = resolved.replace(match[0], `<!-- partial "${partialName}" not found -->`);
|
|
@@ -22812,7 +23118,7 @@ var init_sync_service = __esm({
|
|
|
22812
23118
|
"workflow",
|
|
22813
23119
|
`${name}.md`
|
|
22814
23120
|
);
|
|
22815
|
-
content = await
|
|
23121
|
+
content = await fs47.readFile(templatePath, "utf-8");
|
|
22816
23122
|
content = await this.resolveTemplateIncludes(content);
|
|
22817
23123
|
} catch (error) {
|
|
22818
23124
|
logger_default.debug("Workflow agent template not found, generating minimal", {
|
|
@@ -22821,7 +23127,7 @@ var init_sync_service = __esm({
|
|
|
22821
23127
|
});
|
|
22822
23128
|
content = this.generateMinimalWorkflowAgent(name);
|
|
22823
23129
|
}
|
|
22824
|
-
await
|
|
23130
|
+
await fs47.writeFile(path50.join(agentsPath, `${name}.md`), content, "utf-8");
|
|
22825
23131
|
}
|
|
22826
23132
|
async generateDomainAgent(name, agentsPath, stats, stack) {
|
|
22827
23133
|
let content = "";
|
|
@@ -22835,7 +23141,7 @@ var init_sync_service = __esm({
|
|
|
22835
23141
|
"domain",
|
|
22836
23142
|
`${name}.md`
|
|
22837
23143
|
);
|
|
22838
|
-
content = await
|
|
23144
|
+
content = await fs47.readFile(templatePath, "utf-8");
|
|
22839
23145
|
content = await this.resolveTemplateIncludes(content);
|
|
22840
23146
|
content = content.replace("{projectName}", stats.name);
|
|
22841
23147
|
content = content.replace("{frameworks}", stack.frameworks.join(", ") || "None detected");
|
|
@@ -22847,7 +23153,7 @@ var init_sync_service = __esm({
|
|
|
22847
23153
|
});
|
|
22848
23154
|
content = this.generateMinimalDomainAgent(name, stats, stack);
|
|
22849
23155
|
}
|
|
22850
|
-
await
|
|
23156
|
+
await fs47.writeFile(path50.join(agentsPath, `${name}.md`), content, "utf-8");
|
|
22851
23157
|
}
|
|
22852
23158
|
generateMinimalWorkflowAgent(name) {
|
|
22853
23159
|
const descriptions = {
|
|
@@ -22915,7 +23221,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
22915
23221
|
})),
|
|
22916
23222
|
agentSkillMap: Object.fromEntries(skills.map((s) => [s.agent, s.skill]))
|
|
22917
23223
|
};
|
|
22918
|
-
|
|
23224
|
+
fs47.writeFile(
|
|
22919
23225
|
path50.join(this.globalPath, "config", "skills.json"),
|
|
22920
23226
|
JSON.stringify(skillsConfig, null, 2),
|
|
22921
23227
|
"utf-8"
|
|
@@ -22942,7 +23248,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
22942
23248
|
"config",
|
|
22943
23249
|
"skill-mappings.json"
|
|
22944
23250
|
);
|
|
22945
|
-
const mappingsContent = await
|
|
23251
|
+
const mappingsContent = await fs47.readFile(mappingsPath, "utf-8");
|
|
22946
23252
|
const mappings = JSON.parse(mappingsContent);
|
|
22947
23253
|
const agentToSkillMap = mappings.agentToSkillMap || {};
|
|
22948
23254
|
const packagesToInstall = [];
|
|
@@ -22962,11 +23268,11 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
22962
23268
|
const flatPath = path50.join(skillsDir, `${skillName}.md`);
|
|
22963
23269
|
let alreadyInstalled = false;
|
|
22964
23270
|
try {
|
|
22965
|
-
await
|
|
23271
|
+
await fs47.access(subdirPath);
|
|
22966
23272
|
alreadyInstalled = true;
|
|
22967
23273
|
} catch {
|
|
22968
23274
|
try {
|
|
22969
|
-
await
|
|
23275
|
+
await fs47.access(flatPath);
|
|
22970
23276
|
alreadyInstalled = true;
|
|
22971
23277
|
} catch {
|
|
22972
23278
|
}
|
|
@@ -23021,7 +23327,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
23021
23327
|
const projectJsonPath = path50.join(this.globalPath, "project.json");
|
|
23022
23328
|
let existing = {};
|
|
23023
23329
|
try {
|
|
23024
|
-
existing = JSON.parse(await
|
|
23330
|
+
existing = JSON.parse(await fs47.readFile(projectJsonPath, "utf-8"));
|
|
23025
23331
|
} catch (error) {
|
|
23026
23332
|
logger_default.debug("No existing project.json", {
|
|
23027
23333
|
path: projectJsonPath,
|
|
@@ -23047,7 +23353,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
23047
23353
|
lastSyncCommit: git.recentCommits[0]?.hash || null,
|
|
23048
23354
|
lastSyncBranch: git.branch
|
|
23049
23355
|
};
|
|
23050
|
-
await
|
|
23356
|
+
await fs47.writeFile(projectJsonPath, JSON.stringify(updated, null, 2), "utf-8");
|
|
23051
23357
|
}
|
|
23052
23358
|
// ==========================================================================
|
|
23053
23359
|
// STATE.JSON UPDATE
|
|
@@ -23056,7 +23362,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
23056
23362
|
const statePath = path50.join(this.globalPath, "storage", "state.json");
|
|
23057
23363
|
let state = {};
|
|
23058
23364
|
try {
|
|
23059
|
-
state = JSON.parse(await
|
|
23365
|
+
state = JSON.parse(await fs47.readFile(statePath, "utf-8"));
|
|
23060
23366
|
} catch (error) {
|
|
23061
23367
|
logger_default.debug("No existing state.json", { path: statePath, error: getErrorMessage(error) });
|
|
23062
23368
|
}
|
|
@@ -23084,7 +23390,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
23084
23390
|
lastAction: "Synced project",
|
|
23085
23391
|
nextAction: 'Run `p. task "description"` to start working'
|
|
23086
23392
|
};
|
|
23087
|
-
await
|
|
23393
|
+
await fs47.writeFile(statePath, JSON.stringify(state, null, 2), "utf-8");
|
|
23088
23394
|
try {
|
|
23089
23395
|
await localStateGenerator.generate(
|
|
23090
23396
|
this.projectPath,
|
|
@@ -23107,7 +23413,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
23107
23413
|
fileCount: stats.fileCount,
|
|
23108
23414
|
commitCount: git.commits
|
|
23109
23415
|
};
|
|
23110
|
-
await
|
|
23416
|
+
await fs47.appendFile(memoryPath, `${JSON.stringify(event)}
|
|
23111
23417
|
`, "utf-8");
|
|
23112
23418
|
}
|
|
23113
23419
|
// ==========================================================================
|
|
@@ -23128,7 +23434,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
23128
23434
|
for (const file of contextFiles) {
|
|
23129
23435
|
try {
|
|
23130
23436
|
const filePath = path50.join(this.globalPath, file);
|
|
23131
|
-
const content = await
|
|
23437
|
+
const content = await fs47.readFile(filePath, "utf-8");
|
|
23132
23438
|
filteredChars += content.length;
|
|
23133
23439
|
} catch (error) {
|
|
23134
23440
|
logger_default.debug("Context file not found for metrics", { file, error: getErrorMessage(error) });
|
|
@@ -23137,7 +23443,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
23137
23443
|
for (const agent of agents) {
|
|
23138
23444
|
try {
|
|
23139
23445
|
const agentPath = path50.join(this.globalPath, "agents", `${agent.name}.md`);
|
|
23140
|
-
const content = await
|
|
23446
|
+
const content = await fs47.readFile(agentPath, "utf-8");
|
|
23141
23447
|
filteredChars += content.length;
|
|
23142
23448
|
} catch (error) {
|
|
23143
23449
|
logger_default.debug("Agent file not found for metrics", {
|
|
@@ -23173,7 +23479,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
23173
23479
|
// ==========================================================================
|
|
23174
23480
|
async fileExists(filename) {
|
|
23175
23481
|
try {
|
|
23176
|
-
await
|
|
23482
|
+
await fs47.access(path50.join(this.projectPath, filename));
|
|
23177
23483
|
return true;
|
|
23178
23484
|
} catch (error) {
|
|
23179
23485
|
logger_default.debug("File not found", { filename, error: getErrorMessage(error) });
|
|
@@ -23183,7 +23489,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
23183
23489
|
async getCliVersion() {
|
|
23184
23490
|
try {
|
|
23185
23491
|
const pkgPath = path50.join(__dirname, "..", "..", "package.json");
|
|
23186
|
-
const pkg = JSON.parse(await
|
|
23492
|
+
const pkg = JSON.parse(await fs47.readFile(pkgPath, "utf-8"));
|
|
23187
23493
|
return pkg.version || "0.0.0";
|
|
23188
23494
|
} catch (error) {
|
|
23189
23495
|
logger_default.debug("Failed to read CLI version", { error: getErrorMessage(error) });
|
|
@@ -23344,7 +23650,7 @@ __export(uninstall_exports, {
|
|
|
23344
23650
|
uninstall: () => uninstall
|
|
23345
23651
|
});
|
|
23346
23652
|
import { execSync as execSync3 } from "node:child_process";
|
|
23347
|
-
import
|
|
23653
|
+
import fs48 from "node:fs/promises";
|
|
23348
23654
|
import os16 from "node:os";
|
|
23349
23655
|
import path51 from "node:path";
|
|
23350
23656
|
import readline2 from "node:readline";
|
|
@@ -23352,14 +23658,14 @@ import chalk12 from "chalk";
|
|
|
23352
23658
|
async function getDirectorySize(dirPath) {
|
|
23353
23659
|
let totalSize = 0;
|
|
23354
23660
|
try {
|
|
23355
|
-
const entries = await
|
|
23661
|
+
const entries = await fs48.readdir(dirPath, { withFileTypes: true });
|
|
23356
23662
|
for (const entry of entries) {
|
|
23357
23663
|
const entryPath = path51.join(dirPath, entry.name);
|
|
23358
23664
|
if (entry.isDirectory()) {
|
|
23359
23665
|
totalSize += await getDirectorySize(entryPath);
|
|
23360
23666
|
} else {
|
|
23361
23667
|
try {
|
|
23362
|
-
const stats = await
|
|
23668
|
+
const stats = await fs48.stat(entryPath);
|
|
23363
23669
|
totalSize += stats.size;
|
|
23364
23670
|
} catch {
|
|
23365
23671
|
}
|
|
@@ -23378,7 +23684,7 @@ function formatSize(bytes) {
|
|
|
23378
23684
|
}
|
|
23379
23685
|
async function countDirectoryItems(dirPath) {
|
|
23380
23686
|
try {
|
|
23381
|
-
const entries = await
|
|
23687
|
+
const entries = await fs48.readdir(dirPath, { withFileTypes: true });
|
|
23382
23688
|
return entries.filter((e) => e.isDirectory()).length;
|
|
23383
23689
|
} catch {
|
|
23384
23690
|
return 0;
|
|
@@ -23426,7 +23732,7 @@ async function gatherUninstallItems() {
|
|
|
23426
23732
|
let hasPrjctSection = false;
|
|
23427
23733
|
if (claudeMdExists) {
|
|
23428
23734
|
try {
|
|
23429
|
-
const content = await
|
|
23735
|
+
const content = await fs48.readFile(claudeMdPath, "utf-8");
|
|
23430
23736
|
hasPrjctSection = content.includes(PRJCT_START_MARKER) && content.includes(PRJCT_END_MARKER);
|
|
23431
23737
|
} catch {
|
|
23432
23738
|
}
|
|
@@ -23476,7 +23782,7 @@ async function gatherUninstallItems() {
|
|
|
23476
23782
|
let hasGeminiPrjctSection = false;
|
|
23477
23783
|
if (geminiMdExists) {
|
|
23478
23784
|
try {
|
|
23479
|
-
const content = await
|
|
23785
|
+
const content = await fs48.readFile(geminiMdPath, "utf-8");
|
|
23480
23786
|
hasGeminiPrjctSection = content.includes(PRJCT_START_MARKER) && content.includes(PRJCT_END_MARKER);
|
|
23481
23787
|
} catch {
|
|
23482
23788
|
}
|
|
@@ -23493,7 +23799,7 @@ async function gatherUninstallItems() {
|
|
|
23493
23799
|
}
|
|
23494
23800
|
async function removePrjctSection(filePath) {
|
|
23495
23801
|
try {
|
|
23496
|
-
const content = await
|
|
23802
|
+
const content = await fs48.readFile(filePath, "utf-8");
|
|
23497
23803
|
if (!content.includes(PRJCT_START_MARKER) || !content.includes(PRJCT_END_MARKER)) {
|
|
23498
23804
|
return false;
|
|
23499
23805
|
}
|
|
@@ -23502,9 +23808,9 @@ async function removePrjctSection(filePath) {
|
|
|
23502
23808
|
let newContent = content.substring(0, startIndex) + content.substring(endIndex);
|
|
23503
23809
|
newContent = newContent.replace(/\n{3,}/g, "\n\n").trim();
|
|
23504
23810
|
if (!newContent || newContent.trim().length === 0) {
|
|
23505
|
-
await
|
|
23811
|
+
await fs48.unlink(filePath);
|
|
23506
23812
|
} else {
|
|
23507
|
-
await
|
|
23813
|
+
await fs48.writeFile(filePath, `${newContent}
|
|
23508
23814
|
`, "utf-8");
|
|
23509
23815
|
}
|
|
23510
23816
|
return true;
|
|
@@ -23512,12 +23818,12 @@ async function removePrjctSection(filePath) {
|
|
|
23512
23818
|
return false;
|
|
23513
23819
|
}
|
|
23514
23820
|
}
|
|
23515
|
-
async function
|
|
23821
|
+
async function createBackup2() {
|
|
23516
23822
|
const homeDir = os16.homedir();
|
|
23517
23823
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").substring(0, 19);
|
|
23518
23824
|
const backupDir = path51.join(homeDir, `.prjct-backup-${timestamp}`);
|
|
23519
23825
|
try {
|
|
23520
|
-
await
|
|
23826
|
+
await fs48.mkdir(backupDir, { recursive: true });
|
|
23521
23827
|
const prjctCliPath = path_manager_default.getGlobalBasePath();
|
|
23522
23828
|
if (await fileExists(prjctCliPath)) {
|
|
23523
23829
|
await copyDirectory(prjctCliPath, path51.join(backupDir, ".prjct-cli"));
|
|
@@ -23528,15 +23834,15 @@ async function createBackup() {
|
|
|
23528
23834
|
}
|
|
23529
23835
|
}
|
|
23530
23836
|
async function copyDirectory(src, dest) {
|
|
23531
|
-
await
|
|
23532
|
-
const entries = await
|
|
23837
|
+
await fs48.mkdir(dest, { recursive: true });
|
|
23838
|
+
const entries = await fs48.readdir(src, { withFileTypes: true });
|
|
23533
23839
|
for (const entry of entries) {
|
|
23534
23840
|
const srcPath = path51.join(src, entry.name);
|
|
23535
23841
|
const destPath = path51.join(dest, entry.name);
|
|
23536
23842
|
if (entry.isDirectory()) {
|
|
23537
23843
|
await copyDirectory(srcPath, destPath);
|
|
23538
23844
|
} else {
|
|
23539
|
-
await
|
|
23845
|
+
await fs48.copyFile(srcPath, destPath);
|
|
23540
23846
|
}
|
|
23541
23847
|
}
|
|
23542
23848
|
}
|
|
@@ -23552,10 +23858,10 @@ async function performUninstall(items, installation, options) {
|
|
|
23552
23858
|
deleted.push(item.path);
|
|
23553
23859
|
}
|
|
23554
23860
|
} else if (item.type === "directory") {
|
|
23555
|
-
await
|
|
23861
|
+
await fs48.rm(item.path, { recursive: true, force: true });
|
|
23556
23862
|
deleted.push(item.path);
|
|
23557
23863
|
} else if (item.type === "file") {
|
|
23558
|
-
await
|
|
23864
|
+
await fs48.unlink(item.path);
|
|
23559
23865
|
deleted.push(item.path);
|
|
23560
23866
|
}
|
|
23561
23867
|
} catch (error) {
|
|
@@ -23649,7 +23955,7 @@ async function uninstall(options = {}, _projectPath = process.cwd()) {
|
|
|
23649
23955
|
}
|
|
23650
23956
|
if (options.backup) {
|
|
23651
23957
|
console.log(chalk12.blue("Creating backup..."));
|
|
23652
|
-
const backupPath = await
|
|
23958
|
+
const backupPath = await createBackup2();
|
|
23653
23959
|
if (backupPath) {
|
|
23654
23960
|
console.log(chalk12.green(`Backup created: ${path_manager_default.getDisplayPath(backupPath)}`));
|
|
23655
23961
|
console.log("");
|
|
@@ -23710,7 +24016,7 @@ var init_uninstall = __esm({
|
|
|
23710
24016
|
__name(detectInstallation, "detectInstallation");
|
|
23711
24017
|
__name(gatherUninstallItems, "gatherUninstallItems");
|
|
23712
24018
|
__name(removePrjctSection, "removePrjctSection");
|
|
23713
|
-
__name(
|
|
24019
|
+
__name(createBackup2, "createBackup");
|
|
23714
24020
|
__name(copyDirectory, "copyDirectory");
|
|
23715
24021
|
__name(performUninstall, "performUninstall");
|
|
23716
24022
|
__name(promptConfirmation, "promptConfirmation");
|
|
@@ -24621,7 +24927,7 @@ __export(setup_exports, {
|
|
|
24621
24927
|
run: () => run
|
|
24622
24928
|
});
|
|
24623
24929
|
import { execSync as execSync4 } from "node:child_process";
|
|
24624
|
-
import
|
|
24930
|
+
import fs49 from "node:fs/promises";
|
|
24625
24931
|
import os17 from "node:os";
|
|
24626
24932
|
import path53 from "node:path";
|
|
24627
24933
|
import chalk15 from "chalk";
|
|
@@ -24765,9 +25071,9 @@ async function installGeminiRouter() {
|
|
|
24765
25071
|
const geminiCommandsDir = path53.join(os17.homedir(), ".gemini", "commands");
|
|
24766
25072
|
const routerSource = path53.join(PACKAGE_ROOT, "templates", "commands", "p.toml");
|
|
24767
25073
|
const routerDest = path53.join(geminiCommandsDir, "p.toml");
|
|
24768
|
-
await
|
|
25074
|
+
await fs49.mkdir(geminiCommandsDir, { recursive: true });
|
|
24769
25075
|
if (await fileExists(routerSource)) {
|
|
24770
|
-
await
|
|
25076
|
+
await fs49.copyFile(routerSource, routerDest);
|
|
24771
25077
|
return true;
|
|
24772
25078
|
}
|
|
24773
25079
|
return false;
|
|
@@ -24781,12 +25087,12 @@ async function installGeminiGlobalConfig() {
|
|
|
24781
25087
|
const geminiDir = path53.join(os17.homedir(), ".gemini");
|
|
24782
25088
|
const globalConfigPath = path53.join(geminiDir, "GEMINI.md");
|
|
24783
25089
|
const templatePath = path53.join(PACKAGE_ROOT, "templates", "global", "GEMINI.md");
|
|
24784
|
-
await
|
|
24785
|
-
const templateContent = await
|
|
25090
|
+
await fs49.mkdir(geminiDir, { recursive: true });
|
|
25091
|
+
const templateContent = await fs49.readFile(templatePath, "utf-8");
|
|
24786
25092
|
let existingContent = "";
|
|
24787
25093
|
let configExists = false;
|
|
24788
25094
|
try {
|
|
24789
|
-
existingContent = await
|
|
25095
|
+
existingContent = await fs49.readFile(globalConfigPath, "utf-8");
|
|
24790
25096
|
configExists = true;
|
|
24791
25097
|
} catch (error) {
|
|
24792
25098
|
if (isNotFoundError(error)) {
|
|
@@ -24796,7 +25102,7 @@ async function installGeminiGlobalConfig() {
|
|
|
24796
25102
|
}
|
|
24797
25103
|
}
|
|
24798
25104
|
if (!configExists) {
|
|
24799
|
-
await
|
|
25105
|
+
await fs49.writeFile(globalConfigPath, templateContent, "utf-8");
|
|
24800
25106
|
return { success: true, action: "created" };
|
|
24801
25107
|
}
|
|
24802
25108
|
const startMarker = "<!-- prjct:start - DO NOT REMOVE THIS MARKER -->";
|
|
@@ -24806,7 +25112,7 @@ async function installGeminiGlobalConfig() {
|
|
|
24806
25112
|
const updatedContent2 = `${existingContent}
|
|
24807
25113
|
|
|
24808
25114
|
${templateContent}`;
|
|
24809
|
-
await
|
|
25115
|
+
await fs49.writeFile(globalConfigPath, updatedContent2, "utf-8");
|
|
24810
25116
|
return { success: true, action: "appended" };
|
|
24811
25117
|
}
|
|
24812
25118
|
const beforeMarker = existingContent.substring(0, existingContent.indexOf(startMarker));
|
|
@@ -24818,7 +25124,7 @@ ${templateContent}`;
|
|
|
24818
25124
|
templateContent.indexOf(endMarker) + endMarker.length
|
|
24819
25125
|
);
|
|
24820
25126
|
const updatedContent = beforeMarker + prjctSection + afterMarker;
|
|
24821
|
-
await
|
|
25127
|
+
await fs49.writeFile(globalConfigPath, updatedContent, "utf-8");
|
|
24822
25128
|
return { success: true, action: "updated" };
|
|
24823
25129
|
} catch (error) {
|
|
24824
25130
|
logger_default.warn(`Gemini config warning: ${getErrorMessage2(error)}`);
|
|
@@ -24831,14 +25137,14 @@ async function installAntigravitySkill() {
|
|
|
24831
25137
|
const prjctSkillDir = path53.join(antigravitySkillsDir, "prjct");
|
|
24832
25138
|
const skillMdPath = path53.join(prjctSkillDir, "SKILL.md");
|
|
24833
25139
|
const templatePath = path53.join(PACKAGE_ROOT, "templates", "antigravity", "SKILL.md");
|
|
24834
|
-
await
|
|
25140
|
+
await fs49.mkdir(prjctSkillDir, { recursive: true });
|
|
24835
25141
|
const skillExists = await fileExists(skillMdPath);
|
|
24836
25142
|
if (!await fileExists(templatePath)) {
|
|
24837
25143
|
logger_default.warn("Antigravity SKILL.md template not found");
|
|
24838
25144
|
return { success: false, action: null };
|
|
24839
25145
|
}
|
|
24840
|
-
const templateContent = await
|
|
24841
|
-
await
|
|
25146
|
+
const templateContent = await fs49.readFile(templatePath, "utf-8");
|
|
25147
|
+
await fs49.writeFile(skillMdPath, templateContent, "utf-8");
|
|
24842
25148
|
return { success: true, action: skillExists ? "updated" : "created" };
|
|
24843
25149
|
} catch (error) {
|
|
24844
25150
|
logger_default.warn(`Antigravity skill warning: ${getErrorMessage2(error)}`);
|
|
@@ -24863,18 +25169,18 @@ async function installCursorProject(projectRoot) {
|
|
|
24863
25169
|
const routerMdcDest = path53.join(rulesDir, "prjct.mdc");
|
|
24864
25170
|
const routerMdcSource = path53.join(PACKAGE_ROOT, "templates", "cursor", "router.mdc");
|
|
24865
25171
|
const cursorCommandsSource = path53.join(PACKAGE_ROOT, "templates", "cursor", "commands");
|
|
24866
|
-
await
|
|
24867
|
-
await
|
|
25172
|
+
await fs49.mkdir(rulesDir, { recursive: true });
|
|
25173
|
+
await fs49.mkdir(commandsDir, { recursive: true });
|
|
24868
25174
|
if (await fileExists(routerMdcSource)) {
|
|
24869
|
-
await
|
|
25175
|
+
await fs49.copyFile(routerMdcSource, routerMdcDest);
|
|
24870
25176
|
result.rulesCreated = true;
|
|
24871
25177
|
}
|
|
24872
25178
|
if (await fileExists(cursorCommandsSource)) {
|
|
24873
|
-
const commandFiles = (await
|
|
25179
|
+
const commandFiles = (await fs49.readdir(cursorCommandsSource)).filter((f) => f.endsWith(".md"));
|
|
24874
25180
|
for (const file of commandFiles) {
|
|
24875
25181
|
const src = path53.join(cursorCommandsSource, file);
|
|
24876
25182
|
const dest = path53.join(commandsDir, file);
|
|
24877
|
-
await
|
|
25183
|
+
await fs49.copyFile(src, dest);
|
|
24878
25184
|
}
|
|
24879
25185
|
result.commandsCreated = commandFiles.length > 0;
|
|
24880
25186
|
}
|
|
@@ -24903,7 +25209,7 @@ async function addCursorToGitignore(projectRoot) {
|
|
|
24903
25209
|
let content = "";
|
|
24904
25210
|
let configExists = false;
|
|
24905
25211
|
try {
|
|
24906
|
-
content = await
|
|
25212
|
+
content = await fs49.readFile(gitignorePath, "utf-8");
|
|
24907
25213
|
configExists = true;
|
|
24908
25214
|
} catch (error) {
|
|
24909
25215
|
if (!isNotFoundError(error)) {
|
|
@@ -24918,7 +25224,7 @@ async function addCursorToGitignore(projectRoot) {
|
|
|
24918
25224
|
${entriesToAdd.join("\n")}
|
|
24919
25225
|
` : `${entriesToAdd.join("\n")}
|
|
24920
25226
|
`;
|
|
24921
|
-
await
|
|
25227
|
+
await fs49.writeFile(gitignorePath, newContent, "utf-8");
|
|
24922
25228
|
return true;
|
|
24923
25229
|
} catch (error) {
|
|
24924
25230
|
logger_default.warn(`Gitignore update warning: ${getErrorMessage2(error)}`);
|
|
@@ -24947,20 +25253,20 @@ async function installWindsurfProject(projectRoot) {
|
|
|
24947
25253
|
const routerDest = path53.join(rulesDir, "prjct.md");
|
|
24948
25254
|
const routerSource = path53.join(PACKAGE_ROOT, "templates", "windsurf", "router.md");
|
|
24949
25255
|
const windsurfWorkflowsSource = path53.join(PACKAGE_ROOT, "templates", "windsurf", "workflows");
|
|
24950
|
-
await
|
|
24951
|
-
await
|
|
25256
|
+
await fs49.mkdir(rulesDir, { recursive: true });
|
|
25257
|
+
await fs49.mkdir(workflowsDir, { recursive: true });
|
|
24952
25258
|
if (await fileExists(routerSource)) {
|
|
24953
|
-
await
|
|
25259
|
+
await fs49.copyFile(routerSource, routerDest);
|
|
24954
25260
|
result.rulesCreated = true;
|
|
24955
25261
|
}
|
|
24956
25262
|
if (await fileExists(windsurfWorkflowsSource)) {
|
|
24957
|
-
const workflowFiles = (await
|
|
25263
|
+
const workflowFiles = (await fs49.readdir(windsurfWorkflowsSource)).filter(
|
|
24958
25264
|
(f) => f.endsWith(".md")
|
|
24959
25265
|
);
|
|
24960
25266
|
for (const file of workflowFiles) {
|
|
24961
25267
|
const src = path53.join(windsurfWorkflowsSource, file);
|
|
24962
25268
|
const dest = path53.join(workflowsDir, file);
|
|
24963
|
-
await
|
|
25269
|
+
await fs49.copyFile(src, dest);
|
|
24964
25270
|
}
|
|
24965
25271
|
result.workflowsCreated = workflowFiles.length > 0;
|
|
24966
25272
|
}
|
|
@@ -24989,7 +25295,7 @@ async function addWindsurfToGitignore(projectRoot) {
|
|
|
24989
25295
|
let content = "";
|
|
24990
25296
|
let configExists = false;
|
|
24991
25297
|
try {
|
|
24992
|
-
content = await
|
|
25298
|
+
content = await fs49.readFile(gitignorePath, "utf-8");
|
|
24993
25299
|
configExists = true;
|
|
24994
25300
|
} catch (error) {
|
|
24995
25301
|
if (!isNotFoundError(error)) {
|
|
@@ -25004,7 +25310,7 @@ async function addWindsurfToGitignore(projectRoot) {
|
|
|
25004
25310
|
${entriesToAdd.join("\n")}
|
|
25005
25311
|
` : `${entriesToAdd.join("\n")}
|
|
25006
25312
|
`;
|
|
25007
|
-
await
|
|
25313
|
+
await fs49.writeFile(gitignorePath, newContent, "utf-8");
|
|
25008
25314
|
return true;
|
|
25009
25315
|
} catch (error) {
|
|
25010
25316
|
logger_default.warn(`Gitignore update warning: ${getErrorMessage2(error)}`);
|
|
@@ -25025,7 +25331,7 @@ async function migrateProjectsCliVersion() {
|
|
|
25025
25331
|
if (!await fileExists(projectsDir)) {
|
|
25026
25332
|
return;
|
|
25027
25333
|
}
|
|
25028
|
-
const projectDirs = (await
|
|
25334
|
+
const projectDirs = (await fs49.readdir(projectsDir, { withFileTypes: true })).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
25029
25335
|
let migrated = 0;
|
|
25030
25336
|
for (const projectId of projectDirs) {
|
|
25031
25337
|
const projectJsonPath = path53.join(projectsDir, projectId, "project.json");
|
|
@@ -25033,11 +25339,11 @@ async function migrateProjectsCliVersion() {
|
|
|
25033
25339
|
continue;
|
|
25034
25340
|
}
|
|
25035
25341
|
try {
|
|
25036
|
-
const content = await
|
|
25342
|
+
const content = await fs49.readFile(projectJsonPath, "utf8");
|
|
25037
25343
|
const project = JSON.parse(content);
|
|
25038
25344
|
if (project.cliVersion !== VERSION) {
|
|
25039
25345
|
project.cliVersion = VERSION;
|
|
25040
|
-
await
|
|
25346
|
+
await fs49.writeFile(projectJsonPath, JSON.stringify(project, null, 2));
|
|
25041
25347
|
migrated++;
|
|
25042
25348
|
}
|
|
25043
25349
|
} catch (error) {
|
|
@@ -25059,7 +25365,7 @@ async function ensureStatusLineSettings(settingsPath, statusLinePath) {
|
|
|
25059
25365
|
let settings = {};
|
|
25060
25366
|
if (await fileExists(settingsPath)) {
|
|
25061
25367
|
try {
|
|
25062
|
-
settings = JSON.parse(await
|
|
25368
|
+
settings = JSON.parse(await fs49.readFile(settingsPath, "utf8"));
|
|
25063
25369
|
} catch (error) {
|
|
25064
25370
|
if (!(error instanceof SyntaxError)) {
|
|
25065
25371
|
throw error;
|
|
@@ -25067,7 +25373,7 @@ async function ensureStatusLineSettings(settingsPath, statusLinePath) {
|
|
|
25067
25373
|
}
|
|
25068
25374
|
}
|
|
25069
25375
|
settings.statusLine = { type: "command", command: statusLinePath };
|
|
25070
|
-
await
|
|
25376
|
+
await fs49.writeFile(settingsPath, JSON.stringify(settings, null, 2));
|
|
25071
25377
|
}
|
|
25072
25378
|
async function installStatusLine() {
|
|
25073
25379
|
try {
|
|
@@ -25087,22 +25393,22 @@ async function installStatusLine() {
|
|
|
25087
25393
|
const sourceComponentsDir = path53.join(assetsDir, "components");
|
|
25088
25394
|
const sourceConfigPath = path53.join(assetsDir, "default-config.json");
|
|
25089
25395
|
if (!await fileExists(claudeDir)) {
|
|
25090
|
-
await
|
|
25396
|
+
await fs49.mkdir(claudeDir, { recursive: true });
|
|
25091
25397
|
}
|
|
25092
25398
|
if (!await fileExists(prjctStatusLineDir)) {
|
|
25093
|
-
await
|
|
25399
|
+
await fs49.mkdir(prjctStatusLineDir, { recursive: true });
|
|
25094
25400
|
}
|
|
25095
25401
|
if (!await fileExists(prjctThemesDir)) {
|
|
25096
|
-
await
|
|
25402
|
+
await fs49.mkdir(prjctThemesDir, { recursive: true });
|
|
25097
25403
|
}
|
|
25098
25404
|
if (!await fileExists(prjctLibDir)) {
|
|
25099
|
-
await
|
|
25405
|
+
await fs49.mkdir(prjctLibDir, { recursive: true });
|
|
25100
25406
|
}
|
|
25101
25407
|
if (!await fileExists(prjctComponentsDir)) {
|
|
25102
|
-
await
|
|
25408
|
+
await fs49.mkdir(prjctComponentsDir, { recursive: true });
|
|
25103
25409
|
}
|
|
25104
25410
|
if (await fileExists(prjctStatusLinePath)) {
|
|
25105
|
-
const existingContent = await
|
|
25411
|
+
const existingContent = await fs49.readFile(prjctStatusLinePath, "utf8");
|
|
25106
25412
|
if (existingContent.includes("CLI_VERSION=")) {
|
|
25107
25413
|
const versionMatch = existingContent.match(/CLI_VERSION="([^"]*)"/);
|
|
25108
25414
|
if (versionMatch && versionMatch[1] !== VERSION) {
|
|
@@ -25110,7 +25416,7 @@ async function installStatusLine() {
|
|
|
25110
25416
|
/CLI_VERSION="[^"]*"/,
|
|
25111
25417
|
`CLI_VERSION="${VERSION}"`
|
|
25112
25418
|
);
|
|
25113
|
-
await
|
|
25419
|
+
await fs49.writeFile(prjctStatusLinePath, updatedContent, { mode: 493 });
|
|
25114
25420
|
}
|
|
25115
25421
|
await installStatusLineModules(sourceLibDir, prjctLibDir);
|
|
25116
25422
|
await installStatusLineModules(sourceComponentsDir, prjctComponentsDir);
|
|
@@ -25120,21 +25426,21 @@ async function installStatusLine() {
|
|
|
25120
25426
|
}
|
|
25121
25427
|
}
|
|
25122
25428
|
if (await fileExists(sourceScript)) {
|
|
25123
|
-
let scriptContent = await
|
|
25429
|
+
let scriptContent = await fs49.readFile(sourceScript, "utf8");
|
|
25124
25430
|
scriptContent = scriptContent.replace(/CLI_VERSION="[^"]*"/, `CLI_VERSION="${VERSION}"`);
|
|
25125
|
-
await
|
|
25431
|
+
await fs49.writeFile(prjctStatusLinePath, scriptContent, { mode: 493 });
|
|
25126
25432
|
await installStatusLineModules(sourceLibDir, prjctLibDir);
|
|
25127
25433
|
await installStatusLineModules(sourceComponentsDir, prjctComponentsDir);
|
|
25128
25434
|
if (await fileExists(sourceThemeDir)) {
|
|
25129
|
-
const themes = await
|
|
25435
|
+
const themes = await fs49.readdir(sourceThemeDir);
|
|
25130
25436
|
for (const theme of themes) {
|
|
25131
25437
|
const src = path53.join(sourceThemeDir, theme);
|
|
25132
25438
|
const dest = path53.join(prjctThemesDir, theme);
|
|
25133
|
-
await
|
|
25439
|
+
await fs49.copyFile(src, dest);
|
|
25134
25440
|
}
|
|
25135
25441
|
}
|
|
25136
25442
|
if (!await fileExists(prjctConfigPath) && await fileExists(sourceConfigPath)) {
|
|
25137
|
-
await
|
|
25443
|
+
await fs49.copyFile(sourceConfigPath, prjctConfigPath);
|
|
25138
25444
|
}
|
|
25139
25445
|
} else {
|
|
25140
25446
|
const scriptContent = `#!/bin/bash
|
|
@@ -25169,7 +25475,7 @@ if [ -f "$CONFIG" ]; then
|
|
|
25169
25475
|
fi
|
|
25170
25476
|
echo "prjct"
|
|
25171
25477
|
`;
|
|
25172
|
-
await
|
|
25478
|
+
await fs49.writeFile(prjctStatusLinePath, scriptContent, { mode: 493 });
|
|
25173
25479
|
}
|
|
25174
25480
|
await ensureStatusLineSymlink(claudeStatusLinePath, prjctStatusLinePath);
|
|
25175
25481
|
await ensureStatusLineSettings(settingsPath, claudeStatusLinePath);
|
|
@@ -25184,7 +25490,7 @@ async function installContext7MCP() {
|
|
|
25184
25490
|
const claudeDir = path53.join(os17.homedir(), ".claude");
|
|
25185
25491
|
const mcpConfigPath = path53.join(claudeDir, "mcp.json");
|
|
25186
25492
|
if (!await fileExists(claudeDir)) {
|
|
25187
|
-
await
|
|
25493
|
+
await fs49.mkdir(claudeDir, { recursive: true });
|
|
25188
25494
|
}
|
|
25189
25495
|
const context7Config = {
|
|
25190
25496
|
mcpServers: {
|
|
@@ -25195,16 +25501,16 @@ async function installContext7MCP() {
|
|
|
25195
25501
|
}
|
|
25196
25502
|
};
|
|
25197
25503
|
if (await fileExists(mcpConfigPath)) {
|
|
25198
|
-
const existingContent = await
|
|
25504
|
+
const existingContent = await fs49.readFile(mcpConfigPath, "utf-8");
|
|
25199
25505
|
const existingConfig = JSON.parse(existingContent);
|
|
25200
25506
|
if (existingConfig.mcpServers?.context7) {
|
|
25201
25507
|
return;
|
|
25202
25508
|
}
|
|
25203
25509
|
existingConfig.mcpServers = existingConfig.mcpServers || {};
|
|
25204
25510
|
existingConfig.mcpServers.context7 = context7Config.mcpServers.context7;
|
|
25205
|
-
await
|
|
25511
|
+
await fs49.writeFile(mcpConfigPath, JSON.stringify(existingConfig, null, 2), "utf-8");
|
|
25206
25512
|
} else {
|
|
25207
|
-
await
|
|
25513
|
+
await fs49.writeFile(mcpConfigPath, JSON.stringify(context7Config, null, 2), "utf-8");
|
|
25208
25514
|
}
|
|
25209
25515
|
} catch (error) {
|
|
25210
25516
|
logger_default.warn(`Context7 MCP setup warning: ${getErrorMessage2(error)}`);
|
|
@@ -25214,34 +25520,34 @@ async function installStatusLineModules(sourceDir, destDir) {
|
|
|
25214
25520
|
if (!await fileExists(sourceDir)) {
|
|
25215
25521
|
return;
|
|
25216
25522
|
}
|
|
25217
|
-
const files = await
|
|
25523
|
+
const files = await fs49.readdir(sourceDir);
|
|
25218
25524
|
for (const file of files) {
|
|
25219
25525
|
if (file.endsWith(".sh")) {
|
|
25220
25526
|
const src = path53.join(sourceDir, file);
|
|
25221
25527
|
const dest = path53.join(destDir, file);
|
|
25222
|
-
await
|
|
25223
|
-
await
|
|
25528
|
+
await fs49.copyFile(src, dest);
|
|
25529
|
+
await fs49.chmod(dest, 493);
|
|
25224
25530
|
}
|
|
25225
25531
|
}
|
|
25226
25532
|
}
|
|
25227
25533
|
async function ensureStatusLineSymlink(linkPath, targetPath) {
|
|
25228
25534
|
try {
|
|
25229
25535
|
if (await fileExists(linkPath)) {
|
|
25230
|
-
const stats = await
|
|
25536
|
+
const stats = await fs49.lstat(linkPath);
|
|
25231
25537
|
if (stats.isSymbolicLink()) {
|
|
25232
|
-
const existingTarget = await
|
|
25538
|
+
const existingTarget = await fs49.readlink(linkPath);
|
|
25233
25539
|
if (existingTarget === targetPath) {
|
|
25234
25540
|
return;
|
|
25235
25541
|
}
|
|
25236
25542
|
}
|
|
25237
|
-
await
|
|
25543
|
+
await fs49.unlink(linkPath);
|
|
25238
25544
|
}
|
|
25239
|
-
await
|
|
25545
|
+
await fs49.symlink(targetPath, linkPath);
|
|
25240
25546
|
} catch (_error) {
|
|
25241
25547
|
try {
|
|
25242
25548
|
if (await fileExists(targetPath)) {
|
|
25243
|
-
await
|
|
25244
|
-
await
|
|
25549
|
+
await fs49.copyFile(targetPath, linkPath);
|
|
25550
|
+
await fs49.chmod(linkPath, 493);
|
|
25245
25551
|
}
|
|
25246
25552
|
} catch (copyError) {
|
|
25247
25553
|
if (!isNotFoundError(copyError)) {
|
|
@@ -25935,7 +26241,7 @@ ${"\u2550".repeat(50)}
|
|
|
25935
26241
|
});
|
|
25936
26242
|
|
|
25937
26243
|
// core/commands/context.ts
|
|
25938
|
-
import
|
|
26244
|
+
import fs50 from "node:fs/promises";
|
|
25939
26245
|
import path55 from "node:path";
|
|
25940
26246
|
var ContextCommands, contextCommands;
|
|
25941
26247
|
var init_context = __esm({
|
|
@@ -26063,7 +26369,7 @@ var init_context = __esm({
|
|
|
26063
26369
|
async loadRepoAnalysis(globalPath) {
|
|
26064
26370
|
try {
|
|
26065
26371
|
const analysisPath = path55.join(globalPath, "analysis", "repo-analysis.json");
|
|
26066
|
-
const content = await
|
|
26372
|
+
const content = await fs50.readFile(analysisPath, "utf-8");
|
|
26067
26373
|
const data = JSON.parse(content);
|
|
26068
26374
|
return {
|
|
26069
26375
|
ecosystem: data.ecosystem || "unknown",
|
|
@@ -26560,7 +26866,7 @@ var init_maintenance = __esm({
|
|
|
26560
26866
|
});
|
|
26561
26867
|
|
|
26562
26868
|
// core/commands/setup.ts
|
|
26563
|
-
import
|
|
26869
|
+
import fs51 from "node:fs/promises";
|
|
26564
26870
|
import path59 from "node:path";
|
|
26565
26871
|
import chalk16 from "chalk";
|
|
26566
26872
|
var SetupCommands;
|
|
@@ -26748,11 +27054,11 @@ fi
|
|
|
26748
27054
|
# Default: show prjct branding
|
|
26749
27055
|
echo "\u26A1 prjct"
|
|
26750
27056
|
`;
|
|
26751
|
-
await
|
|
27057
|
+
await fs51.writeFile(statusLinePath, scriptContent, { mode: 493 });
|
|
26752
27058
|
let settings = {};
|
|
26753
27059
|
if (await fileExists(settingsPath)) {
|
|
26754
27060
|
try {
|
|
26755
|
-
settings = JSON.parse(await
|
|
27061
|
+
settings = JSON.parse(await fs51.readFile(settingsPath, "utf8"));
|
|
26756
27062
|
} catch (_error) {
|
|
26757
27063
|
}
|
|
26758
27064
|
}
|
|
@@ -26760,7 +27066,7 @@ echo "\u26A1 prjct"
|
|
|
26760
27066
|
type: "command",
|
|
26761
27067
|
command: statusLinePath
|
|
26762
27068
|
};
|
|
26763
|
-
await
|
|
27069
|
+
await fs51.writeFile(settingsPath, JSON.stringify(settings, null, 2));
|
|
26764
27070
|
return { success: true };
|
|
26765
27071
|
} catch (error) {
|
|
26766
27072
|
return { success: false, error: getErrorMessage2(error) };
|
|
@@ -28118,7 +28424,7 @@ var init_linear = __esm({
|
|
|
28118
28424
|
});
|
|
28119
28425
|
|
|
28120
28426
|
// core/utils/project-credentials.ts
|
|
28121
|
-
import
|
|
28427
|
+
import fs52 from "node:fs/promises";
|
|
28122
28428
|
import os18 from "node:os";
|
|
28123
28429
|
import path62 from "node:path";
|
|
28124
28430
|
function getCredentialsPath(projectId) {
|
|
@@ -28130,7 +28436,7 @@ async function getProjectCredentials(projectId) {
|
|
|
28130
28436
|
return {};
|
|
28131
28437
|
}
|
|
28132
28438
|
try {
|
|
28133
|
-
return JSON.parse(await
|
|
28439
|
+
return JSON.parse(await fs52.readFile(credPath, "utf-8"));
|
|
28134
28440
|
} catch (error) {
|
|
28135
28441
|
console.error("[project-credentials] Failed to read credentials:", getErrorMessage2(error));
|
|
28136
28442
|
return {};
|
|
@@ -28710,7 +29016,7 @@ var require_package = __commonJS({
|
|
|
28710
29016
|
"package.json"(exports, module) {
|
|
28711
29017
|
module.exports = {
|
|
28712
29018
|
name: "prjct-cli",
|
|
28713
|
-
version: "1.7.
|
|
29019
|
+
version: "1.7.2",
|
|
28714
29020
|
description: "Context layer for AI agents. Project context for Claude Code, Gemini CLI, and more.",
|
|
28715
29021
|
main: "core/index.ts",
|
|
28716
29022
|
bin: {
|
|
@@ -29185,7 +29491,7 @@ __name(isBun, "isBun");
|
|
|
29185
29491
|
init_path_manager();
|
|
29186
29492
|
init_fs();
|
|
29187
29493
|
init_logger();
|
|
29188
|
-
import
|
|
29494
|
+
import fs9 from "node:fs/promises";
|
|
29189
29495
|
import path8 from "node:path";
|
|
29190
29496
|
import { Hono } from "hono";
|
|
29191
29497
|
import * as jsonc2 from "jsonc-parser";
|
|
@@ -29198,7 +29504,7 @@ var STORAGE_PATHS = {
|
|
|
29198
29504
|
};
|
|
29199
29505
|
async function readJsonFile(filePath) {
|
|
29200
29506
|
try {
|
|
29201
|
-
const content = await
|
|
29507
|
+
const content = await fs9.readFile(filePath, "utf-8");
|
|
29202
29508
|
const errors = [];
|
|
29203
29509
|
const result = jsonc2.parse(content, errors);
|
|
29204
29510
|
return errors.length > 0 ? null : result;
|
|
@@ -29212,8 +29518,8 @@ async function readJsonFile(filePath) {
|
|
|
29212
29518
|
__name(readJsonFile, "readJsonFile");
|
|
29213
29519
|
async function writeJsonFile(filePath, data) {
|
|
29214
29520
|
try {
|
|
29215
|
-
await
|
|
29216
|
-
await
|
|
29521
|
+
await fs9.mkdir(path8.dirname(filePath), { recursive: true });
|
|
29522
|
+
await fs9.writeFile(filePath, `${JSON.stringify(data, null, 2)}
|
|
29217
29523
|
`, "utf-8");
|
|
29218
29524
|
return true;
|
|
29219
29525
|
} catch (error) {
|
|
@@ -29303,7 +29609,7 @@ function createRoutes(projectId, _projectPath) {
|
|
|
29303
29609
|
}
|
|
29304
29610
|
try {
|
|
29305
29611
|
const filePath = path8.join(dataPath, "context", `${name}.md`);
|
|
29306
|
-
const content = await
|
|
29612
|
+
const content = await fs9.readFile(filePath, "utf-8");
|
|
29307
29613
|
return c.text(content, 200, { "Content-Type": "text/markdown" });
|
|
29308
29614
|
} catch (error) {
|
|
29309
29615
|
if (!isNotFoundError(error)) {
|
|
@@ -29319,7 +29625,7 @@ __name(createRoutes, "createRoutes");
|
|
|
29319
29625
|
// core/server/routes-extended.ts
|
|
29320
29626
|
init_path_manager();
|
|
29321
29627
|
init_fs();
|
|
29322
|
-
import
|
|
29628
|
+
import fs10 from "node:fs/promises";
|
|
29323
29629
|
import path9 from "node:path";
|
|
29324
29630
|
import { Hono as Hono2 } from "hono";
|
|
29325
29631
|
import * as jsonc3 from "jsonc-parser";
|
|
@@ -29327,7 +29633,7 @@ var GLOBAL_BASE = path_manager_default.getGlobalBasePath();
|
|
|
29327
29633
|
var PROJECTS_DIR = path9.join(GLOBAL_BASE, "projects");
|
|
29328
29634
|
async function readJsonFile2(filePath) {
|
|
29329
29635
|
try {
|
|
29330
|
-
const content = await
|
|
29636
|
+
const content = await fs10.readFile(filePath, "utf-8");
|
|
29331
29637
|
const errors = [];
|
|
29332
29638
|
const result = jsonc3.parse(content, errors);
|
|
29333
29639
|
return errors.length > 0 ? null : result;
|
|
@@ -29341,8 +29647,8 @@ async function readJsonFile2(filePath) {
|
|
|
29341
29647
|
__name(readJsonFile2, "readJsonFile");
|
|
29342
29648
|
async function writeJsonFile2(filePath, data) {
|
|
29343
29649
|
try {
|
|
29344
|
-
await
|
|
29345
|
-
await
|
|
29650
|
+
await fs10.mkdir(path9.dirname(filePath), { recursive: true });
|
|
29651
|
+
await fs10.writeFile(filePath, `${JSON.stringify(data, null, 2)}
|
|
29346
29652
|
`, "utf-8");
|
|
29347
29653
|
return true;
|
|
29348
29654
|
} catch (error) {
|
|
@@ -29379,8 +29685,8 @@ function createExtendedRoutes() {
|
|
|
29379
29685
|
const api = new Hono2();
|
|
29380
29686
|
api.get("/projects", async (c) => {
|
|
29381
29687
|
try {
|
|
29382
|
-
await
|
|
29383
|
-
const entries = await
|
|
29688
|
+
await fs10.mkdir(PROJECTS_DIR, { recursive: true });
|
|
29689
|
+
const entries = await fs10.readdir(PROJECTS_DIR, { withFileTypes: true });
|
|
29384
29690
|
const projectIds = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
29385
29691
|
const projects = await Promise.all(
|
|
29386
29692
|
projectIds.map(async (id) => {
|
|
@@ -29639,8 +29945,8 @@ function createExtendedRoutes() {
|
|
|
29639
29945
|
});
|
|
29640
29946
|
api.get("/stats/global", async (c) => {
|
|
29641
29947
|
try {
|
|
29642
|
-
await
|
|
29643
|
-
const entries = await
|
|
29948
|
+
await fs10.mkdir(PROJECTS_DIR, { recursive: true });
|
|
29949
|
+
const entries = await fs10.readdir(PROJECTS_DIR, { withFileTypes: true });
|
|
29644
29950
|
const projectIds = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
29645
29951
|
let totalTasks = 0;
|
|
29646
29952
|
let totalIdeas = 0;
|
|
@@ -29674,8 +29980,8 @@ function createExtendedRoutes() {
|
|
|
29674
29980
|
api.get("/status-bar/compact", async (c) => {
|
|
29675
29981
|
try {
|
|
29676
29982
|
const cwd = c.req.query("cwd");
|
|
29677
|
-
await
|
|
29678
|
-
const entries = await
|
|
29983
|
+
await fs10.mkdir(PROJECTS_DIR, { recursive: true });
|
|
29984
|
+
const entries = await fs10.readdir(PROJECTS_DIR, { withFileTypes: true });
|
|
29679
29985
|
const projectIds = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
29680
29986
|
let targetProjectId = null;
|
|
29681
29987
|
if (cwd) {
|