prjct-cli 0.58.0 → 0.60.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +61 -0
- package/assets/statusline/components/git.sh +32 -2
- package/assets/statusline/lib/theme.sh +8 -8
- package/assets/statusline/themes/default.json +2 -2
- package/core/__tests__/agentic/command-executor.test.ts +659 -0
- package/core/__tests__/services/hierarchical-agent-resolver.test.ts +359 -0
- package/core/__tests__/services/nested-context-resolver.test.ts +443 -0
- package/core/__tests__/services/staleness-checker.test.ts +204 -0
- package/core/__tests__/storage/storage-manager.test.ts +379 -0
- package/core/commands/analysis.ts +59 -1
- package/core/commands/analytics.ts +9 -0
- package/core/commands/command-data.ts +16 -0
- package/core/commands/commands.ts +7 -0
- package/core/commands/register.ts +1 -0
- package/core/domain/agent-loader.ts +197 -3
- package/core/index.ts +4 -0
- package/core/schemas/project.ts +3 -0
- package/core/services/hierarchical-agent-resolver.ts +234 -0
- package/core/services/index.ts +3 -0
- package/core/services/nested-context-resolver.ts +467 -3
- package/core/services/staleness-checker.ts +262 -0
- package/core/services/sync-service.ts +3 -0
- package/dist/bin/prjct.mjs +957 -364
- package/package.json +1 -1
- package/templates/commands/done.md +61 -13
- package/templates/commands/merge.md +11 -18
- package/templates/commands/ship.md +75 -42
- package/templates/commands/task.md +53 -19
- package/templates/global/CLAUDE.md +27 -0
- package/templates/global/STORAGE-SPEC.md +138 -3
package/dist/bin/prjct.mjs
CHANGED
|
@@ -16,10 +16,10 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
16
16
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
17
17
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
18
18
|
});
|
|
19
|
-
var __glob = (map) => (
|
|
20
|
-
var fn = map[
|
|
19
|
+
var __glob = (map) => (path58) => {
|
|
20
|
+
var fn = map[path58];
|
|
21
21
|
if (fn) return fn();
|
|
22
|
-
throw new Error("Module not found in bundle: " +
|
|
22
|
+
throw new Error("Module not found in bundle: " + path58);
|
|
23
23
|
};
|
|
24
24
|
var __esm = (fn, res) => function __init() {
|
|
25
25
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
@@ -4019,8 +4019,8 @@ function tryResolve(basePath, projectPath) {
|
|
|
4019
4019
|
for (const ext of extensions) {
|
|
4020
4020
|
const fullPath = basePath + ext;
|
|
4021
4021
|
try {
|
|
4022
|
-
const
|
|
4023
|
-
if (
|
|
4022
|
+
const fs49 = __require("node:fs");
|
|
4023
|
+
if (fs49.existsSync(fullPath) && fs49.statSync(fullPath).isFile()) {
|
|
4024
4024
|
return path12.relative(projectPath, fullPath);
|
|
4025
4025
|
}
|
|
4026
4026
|
} catch {
|
|
@@ -5203,11 +5203,11 @@ async function runSignaturesTool(args2, projectPath) {
|
|
|
5203
5203
|
}
|
|
5204
5204
|
};
|
|
5205
5205
|
}
|
|
5206
|
-
const
|
|
5207
|
-
const
|
|
5208
|
-
const fullPath =
|
|
5206
|
+
const fs49 = await import("node:fs/promises");
|
|
5207
|
+
const path58 = await import("node:path");
|
|
5208
|
+
const fullPath = path58.isAbsolute(filePath) ? filePath : path58.join(projectPath, filePath);
|
|
5209
5209
|
try {
|
|
5210
|
-
const stat = await
|
|
5210
|
+
const stat = await fs49.stat(fullPath);
|
|
5211
5211
|
if (stat.isDirectory()) {
|
|
5212
5212
|
const results = await extractDirectorySignatures(filePath, projectPath, {
|
|
5213
5213
|
recursive: args2.includes("--recursive") || args2.includes("-r")
|
|
@@ -5274,11 +5274,11 @@ async function runSummaryTool(args2, projectPath) {
|
|
|
5274
5274
|
}
|
|
5275
5275
|
};
|
|
5276
5276
|
}
|
|
5277
|
-
const
|
|
5278
|
-
const
|
|
5279
|
-
const fullPath =
|
|
5277
|
+
const fs49 = await import("node:fs/promises");
|
|
5278
|
+
const path58 = await import("node:path");
|
|
5279
|
+
const fullPath = path58.isAbsolute(targetPath) ? targetPath : path58.join(projectPath, targetPath);
|
|
5280
5280
|
try {
|
|
5281
|
-
const stat = await
|
|
5281
|
+
const stat = await fs49.stat(fullPath);
|
|
5282
5282
|
if (stat.isDirectory()) {
|
|
5283
5283
|
const results = await summarizeDirectory(targetPath, projectPath, {
|
|
5284
5284
|
recursive: args2.includes("--recursive") || args2.includes("-r")
|
|
@@ -8251,8 +8251,13 @@ var init_project = __esm({
|
|
|
8251
8251
|
commitCount: z7.number(),
|
|
8252
8252
|
createdAt: z7.string(),
|
|
8253
8253
|
// ISO8601
|
|
8254
|
-
lastSync: z7.string()
|
|
8254
|
+
lastSync: z7.string(),
|
|
8255
8255
|
// ISO8601
|
|
8256
|
+
// Staleness tracking (PRJ-120)
|
|
8257
|
+
lastSyncCommit: z7.string().optional(),
|
|
8258
|
+
// Git commit hash at last sync
|
|
8259
|
+
lastSyncBranch: z7.string().optional()
|
|
8260
|
+
// Git branch at last sync
|
|
8256
8261
|
});
|
|
8257
8262
|
DEFAULT_PROJECT = {
|
|
8258
8263
|
techStack: [],
|
|
@@ -15953,6 +15958,321 @@ ${content}`);
|
|
|
15953
15958
|
}
|
|
15954
15959
|
return results;
|
|
15955
15960
|
}
|
|
15961
|
+
// ==========================================================================
|
|
15962
|
+
// AGENTS.md DISCOVERY AND RESOLUTION
|
|
15963
|
+
// ==========================================================================
|
|
15964
|
+
/**
|
|
15965
|
+
* Discover all AGENTS.md files in the project/monorepo
|
|
15966
|
+
*/
|
|
15967
|
+
async discoverAgentFiles() {
|
|
15968
|
+
const agentFiles = [];
|
|
15969
|
+
const rootAgentsPath = path33.join(this.rootPath, "AGENTS.md");
|
|
15970
|
+
if (await fileExists(rootAgentsPath)) {
|
|
15971
|
+
const rootAgents = await this.loadAgents(rootAgentsPath, null);
|
|
15972
|
+
agentFiles.push(rootAgents);
|
|
15973
|
+
}
|
|
15974
|
+
if (this.monoInfo?.isMonorepo) {
|
|
15975
|
+
for (const pkg of this.monoInfo.packages) {
|
|
15976
|
+
const pkgAgentsPath = path33.join(pkg.path, "AGENTS.md");
|
|
15977
|
+
if (await fileExists(pkgAgentsPath)) {
|
|
15978
|
+
const parentAgents = agentFiles.find((a) => a.depth === 0) || null;
|
|
15979
|
+
const pkgAgents = await this.loadAgents(pkgAgentsPath, parentAgents, pkg);
|
|
15980
|
+
agentFiles.push(pkgAgents);
|
|
15981
|
+
if (parentAgents) {
|
|
15982
|
+
parentAgents.children.push(pkgAgents);
|
|
15983
|
+
}
|
|
15984
|
+
}
|
|
15985
|
+
}
|
|
15986
|
+
}
|
|
15987
|
+
const additionalAgents = await this.scanForNestedAgents(this.rootPath, agentFiles);
|
|
15988
|
+
agentFiles.push(...additionalAgents);
|
|
15989
|
+
return agentFiles;
|
|
15990
|
+
}
|
|
15991
|
+
/**
|
|
15992
|
+
* Load a single AGENTS.md file into a NestedAgents structure
|
|
15993
|
+
*/
|
|
15994
|
+
async loadAgents(filePath, parent, pkg = null) {
|
|
15995
|
+
const content = await fs32.readFile(filePath, "utf-8");
|
|
15996
|
+
const relativePath = path33.relative(this.rootPath, filePath);
|
|
15997
|
+
const depth = relativePath.split(path33.sep).length - 1;
|
|
15998
|
+
return {
|
|
15999
|
+
path: filePath,
|
|
16000
|
+
relativePath,
|
|
16001
|
+
depth,
|
|
16002
|
+
parent,
|
|
16003
|
+
children: [],
|
|
16004
|
+
content,
|
|
16005
|
+
agents: this.parseAgents(content),
|
|
16006
|
+
package: pkg
|
|
16007
|
+
};
|
|
16008
|
+
}
|
|
16009
|
+
/**
|
|
16010
|
+
* Parse AGENTS.md content into agent definitions
|
|
16011
|
+
*
|
|
16012
|
+
* Expected format:
|
|
16013
|
+
* ## AgentName @override?
|
|
16014
|
+
*
|
|
16015
|
+
* Description text here.
|
|
16016
|
+
*
|
|
16017
|
+
* ### Triggers
|
|
16018
|
+
* - trigger phrase 1
|
|
16019
|
+
* - trigger phrase 2
|
|
16020
|
+
*
|
|
16021
|
+
* ### Rules
|
|
16022
|
+
* - rule 1
|
|
16023
|
+
* - rule 2
|
|
16024
|
+
*
|
|
16025
|
+
* ### Patterns
|
|
16026
|
+
* ```typescript
|
|
16027
|
+
* // code pattern
|
|
16028
|
+
* ```
|
|
16029
|
+
*/
|
|
16030
|
+
parseAgents(content) {
|
|
16031
|
+
const agents = [];
|
|
16032
|
+
const lines = content.split("\n");
|
|
16033
|
+
let currentAgent = null;
|
|
16034
|
+
let currentSubsection = null;
|
|
16035
|
+
let currentContent = [];
|
|
16036
|
+
const saveCurrentContent = /* @__PURE__ */ __name(() => {
|
|
16037
|
+
if (!currentAgent) return;
|
|
16038
|
+
if (currentSubsection) {
|
|
16039
|
+
const contentStr = currentContent.join("\n").trim();
|
|
16040
|
+
switch (currentSubsection.toLowerCase()) {
|
|
16041
|
+
case "triggers":
|
|
16042
|
+
currentAgent.triggers = this.parseListItems(contentStr);
|
|
16043
|
+
break;
|
|
16044
|
+
case "rules":
|
|
16045
|
+
currentAgent.rules = this.parseListItems(contentStr);
|
|
16046
|
+
break;
|
|
16047
|
+
case "patterns":
|
|
16048
|
+
currentAgent.patterns = this.parseCodeBlocks(contentStr);
|
|
16049
|
+
break;
|
|
16050
|
+
case "examples":
|
|
16051
|
+
currentAgent.examples = this.parseListItems(contentStr);
|
|
16052
|
+
break;
|
|
16053
|
+
case "domain":
|
|
16054
|
+
currentAgent.domain = contentStr;
|
|
16055
|
+
break;
|
|
16056
|
+
}
|
|
16057
|
+
} else {
|
|
16058
|
+
const desc = currentContent.join("\n").trim();
|
|
16059
|
+
if (desc && !currentAgent.description) {
|
|
16060
|
+
currentAgent.description = desc;
|
|
16061
|
+
}
|
|
16062
|
+
}
|
|
16063
|
+
currentContent = [];
|
|
16064
|
+
}, "saveCurrentContent");
|
|
16065
|
+
for (const line of lines) {
|
|
16066
|
+
const agentMatch = line.match(/^##\s+([^#].+)$/);
|
|
16067
|
+
if (agentMatch) {
|
|
16068
|
+
if (currentAgent) {
|
|
16069
|
+
saveCurrentContent();
|
|
16070
|
+
agents.push(currentAgent);
|
|
16071
|
+
}
|
|
16072
|
+
const agentName = agentMatch[1];
|
|
16073
|
+
const override = agentName.includes("@override") || agentName.includes("(override)");
|
|
16074
|
+
currentAgent = {
|
|
16075
|
+
name: agentName.replace(/@override|\(override\)/gi, "").trim(),
|
|
16076
|
+
description: "",
|
|
16077
|
+
override
|
|
16078
|
+
};
|
|
16079
|
+
currentSubsection = null;
|
|
16080
|
+
currentContent = [];
|
|
16081
|
+
continue;
|
|
16082
|
+
}
|
|
16083
|
+
const subsectionMatch = line.match(/^###\s+(.+)$/);
|
|
16084
|
+
if (subsectionMatch && currentAgent) {
|
|
16085
|
+
saveCurrentContent();
|
|
16086
|
+
currentSubsection = subsectionMatch[1].trim();
|
|
16087
|
+
currentContent = [];
|
|
16088
|
+
continue;
|
|
16089
|
+
}
|
|
16090
|
+
if (currentAgent) {
|
|
16091
|
+
currentContent.push(line);
|
|
16092
|
+
}
|
|
16093
|
+
}
|
|
16094
|
+
if (currentAgent) {
|
|
16095
|
+
saveCurrentContent();
|
|
16096
|
+
agents.push(currentAgent);
|
|
16097
|
+
}
|
|
16098
|
+
return agents;
|
|
16099
|
+
}
|
|
16100
|
+
/**
|
|
16101
|
+
* Parse list items from content (lines starting with - or *)
|
|
16102
|
+
*/
|
|
16103
|
+
parseListItems(content) {
|
|
16104
|
+
return content.split("\n").filter((line) => line.match(/^\s*[-*]\s+/)).map((line) => line.replace(/^\s*[-*]\s+/, "").trim()).filter((item) => item.length > 0);
|
|
16105
|
+
}
|
|
16106
|
+
/**
|
|
16107
|
+
* Parse code blocks from content
|
|
16108
|
+
*/
|
|
16109
|
+
parseCodeBlocks(content) {
|
|
16110
|
+
const blocks = [];
|
|
16111
|
+
const codeBlockRegex = /```[\w]*\n([\s\S]*?)```/g;
|
|
16112
|
+
let match;
|
|
16113
|
+
while ((match = codeBlockRegex.exec(content)) !== null) {
|
|
16114
|
+
blocks.push(match[1].trim());
|
|
16115
|
+
}
|
|
16116
|
+
if (blocks.length === 0 && content.trim()) {
|
|
16117
|
+
blocks.push(content.trim());
|
|
16118
|
+
}
|
|
16119
|
+
return blocks;
|
|
16120
|
+
}
|
|
16121
|
+
/**
|
|
16122
|
+
* Scan for additional nested AGENTS.md files not in packages
|
|
16123
|
+
*/
|
|
16124
|
+
async scanForNestedAgents(dir, existing) {
|
|
16125
|
+
const found = [];
|
|
16126
|
+
const existingPaths = new Set(existing.map((a) => a.path));
|
|
16127
|
+
const scan = /* @__PURE__ */ __name(async (currentDir, depth) => {
|
|
16128
|
+
if (depth > 5) return;
|
|
16129
|
+
try {
|
|
16130
|
+
const entries = await fs32.readdir(currentDir, { withFileTypes: true });
|
|
16131
|
+
for (const entry of entries) {
|
|
16132
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "coverage") {
|
|
16133
|
+
continue;
|
|
16134
|
+
}
|
|
16135
|
+
if (entry.isDirectory()) {
|
|
16136
|
+
const subDir = path33.join(currentDir, entry.name);
|
|
16137
|
+
const agentsPath = path33.join(subDir, "AGENTS.md");
|
|
16138
|
+
if (await fileExists(agentsPath) && !existingPaths.has(agentsPath)) {
|
|
16139
|
+
const parent = this.findParentAgents(agentsPath, existing.concat(found));
|
|
16140
|
+
const agents = await this.loadAgents(agentsPath, parent);
|
|
16141
|
+
found.push(agents);
|
|
16142
|
+
existingPaths.add(agentsPath);
|
|
16143
|
+
if (parent) {
|
|
16144
|
+
parent.children.push(agents);
|
|
16145
|
+
}
|
|
16146
|
+
}
|
|
16147
|
+
await scan(subDir, depth + 1);
|
|
16148
|
+
}
|
|
16149
|
+
}
|
|
16150
|
+
} catch {
|
|
16151
|
+
}
|
|
16152
|
+
}, "scan");
|
|
16153
|
+
await scan(dir, 0);
|
|
16154
|
+
return found;
|
|
16155
|
+
}
|
|
16156
|
+
/**
|
|
16157
|
+
* Find the parent agents file for a given path
|
|
16158
|
+
*/
|
|
16159
|
+
findParentAgents(filePath, agentFiles) {
|
|
16160
|
+
const fileDir = path33.dirname(filePath);
|
|
16161
|
+
const sorted = [...agentFiles].sort((a, b) => b.depth - a.depth);
|
|
16162
|
+
for (const agents of sorted) {
|
|
16163
|
+
const agentsDir = path33.dirname(agents.path);
|
|
16164
|
+
if (fileDir.startsWith(agentsDir) && fileDir !== agentsDir) {
|
|
16165
|
+
return agents;
|
|
16166
|
+
}
|
|
16167
|
+
}
|
|
16168
|
+
return null;
|
|
16169
|
+
}
|
|
16170
|
+
/**
|
|
16171
|
+
* Resolve agents for a specific path by merging parent agent definitions
|
|
16172
|
+
* Deeper files take precedence (can override parent agents)
|
|
16173
|
+
*/
|
|
16174
|
+
async resolveAgentsForPath(targetPath) {
|
|
16175
|
+
const agentFiles = await this.discoverAgentFiles();
|
|
16176
|
+
const targetDir = path33.resolve(targetPath);
|
|
16177
|
+
let bestMatch = null;
|
|
16178
|
+
for (const agents of agentFiles) {
|
|
16179
|
+
const agentsDir = path33.dirname(agents.path);
|
|
16180
|
+
if (targetDir.startsWith(agentsDir)) {
|
|
16181
|
+
if (!bestMatch || agents.depth > bestMatch.depth) {
|
|
16182
|
+
bestMatch = agents;
|
|
16183
|
+
}
|
|
16184
|
+
}
|
|
16185
|
+
}
|
|
16186
|
+
if (!bestMatch) {
|
|
16187
|
+
return {
|
|
16188
|
+
agents: [],
|
|
16189
|
+
sources: [],
|
|
16190
|
+
overrides: []
|
|
16191
|
+
};
|
|
16192
|
+
}
|
|
16193
|
+
const chain = [];
|
|
16194
|
+
let current = bestMatch;
|
|
16195
|
+
while (current) {
|
|
16196
|
+
chain.unshift(current);
|
|
16197
|
+
current = current.parent;
|
|
16198
|
+
}
|
|
16199
|
+
return this.mergeAgentsChain(chain);
|
|
16200
|
+
}
|
|
16201
|
+
/**
|
|
16202
|
+
* Merge a chain of agent files following inheritance rules
|
|
16203
|
+
*/
|
|
16204
|
+
mergeAgentsChain(chain) {
|
|
16205
|
+
const mergedAgents = /* @__PURE__ */ new Map();
|
|
16206
|
+
const sources = [];
|
|
16207
|
+
const overrides = [];
|
|
16208
|
+
for (const agentFile of chain) {
|
|
16209
|
+
sources.push(agentFile.relativePath);
|
|
16210
|
+
for (const agent of agentFile.agents) {
|
|
16211
|
+
const existing = mergedAgents.get(agent.name);
|
|
16212
|
+
if (agent.override || !existing) {
|
|
16213
|
+
mergedAgents.set(agent.name, { ...agent });
|
|
16214
|
+
if (agent.override && existing) {
|
|
16215
|
+
overrides.push(`${agentFile.relativePath}:${agent.name}`);
|
|
16216
|
+
}
|
|
16217
|
+
} else {
|
|
16218
|
+
const merged = { ...existing };
|
|
16219
|
+
if (agent.triggers) {
|
|
16220
|
+
merged.triggers = [...existing.triggers || [], ...agent.triggers];
|
|
16221
|
+
}
|
|
16222
|
+
if (agent.rules) {
|
|
16223
|
+
merged.rules = [...existing.rules || [], ...agent.rules];
|
|
16224
|
+
}
|
|
16225
|
+
if (agent.patterns) {
|
|
16226
|
+
merged.patterns = [...existing.patterns || [], ...agent.patterns];
|
|
16227
|
+
}
|
|
16228
|
+
if (agent.examples) {
|
|
16229
|
+
merged.examples = [...existing.examples || [], ...agent.examples];
|
|
16230
|
+
}
|
|
16231
|
+
if (agent.description) {
|
|
16232
|
+
merged.description = `${existing.description}
|
|
16233
|
+
|
|
16234
|
+
${agent.description}`;
|
|
16235
|
+
}
|
|
16236
|
+
if (agent.domain) {
|
|
16237
|
+
merged.domain = agent.domain;
|
|
16238
|
+
}
|
|
16239
|
+
mergedAgents.set(agent.name, merged);
|
|
16240
|
+
}
|
|
16241
|
+
}
|
|
16242
|
+
}
|
|
16243
|
+
return {
|
|
16244
|
+
agents: Array.from(mergedAgents.values()),
|
|
16245
|
+
sources,
|
|
16246
|
+
overrides
|
|
16247
|
+
};
|
|
16248
|
+
}
|
|
16249
|
+
/**
|
|
16250
|
+
* Get agents for a specific monorepo package
|
|
16251
|
+
*/
|
|
16252
|
+
async getPackageAgents(packageName) {
|
|
16253
|
+
if (!this.monoInfo?.isMonorepo) {
|
|
16254
|
+
return null;
|
|
16255
|
+
}
|
|
16256
|
+
const pkg = this.monoInfo.packages.find((p) => p.name === packageName);
|
|
16257
|
+
if (!pkg) {
|
|
16258
|
+
return null;
|
|
16259
|
+
}
|
|
16260
|
+
return this.resolveAgentsForPath(pkg.path);
|
|
16261
|
+
}
|
|
16262
|
+
/**
|
|
16263
|
+
* Get all package agents in the monorepo
|
|
16264
|
+
*/
|
|
16265
|
+
async getAllPackageAgents() {
|
|
16266
|
+
const results = /* @__PURE__ */ new Map();
|
|
16267
|
+
if (!this.monoInfo?.isMonorepo) {
|
|
16268
|
+
return results;
|
|
16269
|
+
}
|
|
16270
|
+
for (const pkg of this.monoInfo.packages) {
|
|
16271
|
+
const agents = await this.resolveAgentsForPath(pkg.path);
|
|
16272
|
+
results.set(pkg.name, agents);
|
|
16273
|
+
}
|
|
16274
|
+
return results;
|
|
16275
|
+
}
|
|
15956
16276
|
};
|
|
15957
16277
|
}
|
|
15958
16278
|
});
|
|
@@ -16440,16 +16760,16 @@ var init_onboarding = __esm({
|
|
|
16440
16760
|
* Detect project type from file system
|
|
16441
16761
|
*/
|
|
16442
16762
|
async detectProjectType() {
|
|
16443
|
-
const
|
|
16444
|
-
const
|
|
16763
|
+
const fs49 = await import("node:fs/promises");
|
|
16764
|
+
const path58 = await import("node:path");
|
|
16445
16765
|
try {
|
|
16446
|
-
const files = await
|
|
16766
|
+
const files = await fs49.readdir(this.projectPath);
|
|
16447
16767
|
if (files.includes("turbo.json") || files.includes("lerna.json") || files.includes("nx.json")) {
|
|
16448
16768
|
return "monorepo";
|
|
16449
16769
|
}
|
|
16450
16770
|
if (files.includes("package.json")) {
|
|
16451
|
-
const pkgPath =
|
|
16452
|
-
const pkgContent = await
|
|
16771
|
+
const pkgPath = path58.join(this.projectPath, "package.json");
|
|
16772
|
+
const pkgContent = await fs49.readFile(pkgPath, "utf-8");
|
|
16453
16773
|
const pkg = JSON.parse(pkgContent);
|
|
16454
16774
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
16455
16775
|
if (pkg.bin) return "cli-tool";
|
|
@@ -16485,32 +16805,32 @@ var init_onboarding = __esm({
|
|
|
16485
16805
|
* Detect installed AI agents from config files
|
|
16486
16806
|
*/
|
|
16487
16807
|
async detectInstalledAgents() {
|
|
16488
|
-
const
|
|
16489
|
-
const
|
|
16808
|
+
const fs49 = await import("node:fs/promises");
|
|
16809
|
+
const path58 = await import("node:path");
|
|
16490
16810
|
const os17 = await import("node:os");
|
|
16491
16811
|
const agents = [];
|
|
16492
16812
|
try {
|
|
16493
|
-
await
|
|
16813
|
+
await fs49.access(path58.join(os17.homedir(), ".claude"));
|
|
16494
16814
|
agents.push("claude");
|
|
16495
16815
|
} catch {
|
|
16496
16816
|
}
|
|
16497
16817
|
try {
|
|
16498
|
-
await
|
|
16818
|
+
await fs49.access(path58.join(this.projectPath, ".cursorrules"));
|
|
16499
16819
|
agents.push("cursor");
|
|
16500
16820
|
} catch {
|
|
16501
16821
|
}
|
|
16502
16822
|
try {
|
|
16503
|
-
await
|
|
16823
|
+
await fs49.access(path58.join(this.projectPath, ".windsurfrules"));
|
|
16504
16824
|
agents.push("windsurf");
|
|
16505
16825
|
} catch {
|
|
16506
16826
|
}
|
|
16507
16827
|
try {
|
|
16508
|
-
await
|
|
16828
|
+
await fs49.access(path58.join(this.projectPath, ".github", "copilot-instructions.md"));
|
|
16509
16829
|
agents.push("copilot");
|
|
16510
16830
|
} catch {
|
|
16511
16831
|
}
|
|
16512
16832
|
try {
|
|
16513
|
-
await
|
|
16833
|
+
await fs49.access(path58.join(os17.homedir(), ".gemini"));
|
|
16514
16834
|
agents.push("gemini");
|
|
16515
16835
|
} catch {
|
|
16516
16836
|
}
|
|
@@ -16520,17 +16840,17 @@ var init_onboarding = __esm({
|
|
|
16520
16840
|
* Detect tech stack from project files
|
|
16521
16841
|
*/
|
|
16522
16842
|
async detectStack() {
|
|
16523
|
-
const
|
|
16524
|
-
const
|
|
16843
|
+
const fs49 = await import("node:fs/promises");
|
|
16844
|
+
const path58 = await import("node:path");
|
|
16525
16845
|
const stack = {
|
|
16526
16846
|
language: "Unknown",
|
|
16527
16847
|
technologies: []
|
|
16528
16848
|
};
|
|
16529
16849
|
try {
|
|
16530
|
-
const files = await
|
|
16850
|
+
const files = await fs49.readdir(this.projectPath);
|
|
16531
16851
|
if (files.includes("package.json")) {
|
|
16532
|
-
const pkgPath =
|
|
16533
|
-
const pkgContent = await
|
|
16852
|
+
const pkgPath = path58.join(this.projectPath, "package.json");
|
|
16853
|
+
const pkgContent = await fs49.readFile(pkgPath, "utf-8");
|
|
16534
16854
|
const pkg = JSON.parse(pkgContent);
|
|
16535
16855
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
16536
16856
|
stack.language = deps.typescript ? "TypeScript" : "JavaScript";
|
|
@@ -17992,6 +18312,52 @@ ${formatFullDiff(diff)}`);
|
|
|
17992
18312
|
return { success: false, error: error.message };
|
|
17993
18313
|
}
|
|
17994
18314
|
}
|
|
18315
|
+
/**
|
|
18316
|
+
* /p:status - Check if CLAUDE.md context is stale
|
|
18317
|
+
*
|
|
18318
|
+
* Uses git commit history to detect when significant changes
|
|
18319
|
+
* have occurred since the last sync.
|
|
18320
|
+
*
|
|
18321
|
+
* @see PRJ-120
|
|
18322
|
+
*/
|
|
18323
|
+
async status(projectPath = process.cwd(), options = {}) {
|
|
18324
|
+
try {
|
|
18325
|
+
const initResult = await this.ensureProjectInit(projectPath);
|
|
18326
|
+
if (!initResult.success) return initResult;
|
|
18327
|
+
const projectId = await config_manager_default.getProjectId(projectPath);
|
|
18328
|
+
if (!projectId) {
|
|
18329
|
+
if (options.json) {
|
|
18330
|
+
console.log(JSON.stringify({ success: false, error: "No project ID found" }));
|
|
18331
|
+
} else {
|
|
18332
|
+
output_default.fail("No project ID found");
|
|
18333
|
+
}
|
|
18334
|
+
return { success: false, error: "No project ID found" };
|
|
18335
|
+
}
|
|
18336
|
+
const checker = createStalenessChecker(projectPath);
|
|
18337
|
+
const status = await checker.check(projectId);
|
|
18338
|
+
if (options.json) {
|
|
18339
|
+
console.log(
|
|
18340
|
+
JSON.stringify({
|
|
18341
|
+
success: true,
|
|
18342
|
+
...status
|
|
18343
|
+
})
|
|
18344
|
+
);
|
|
18345
|
+
return { success: true, data: status };
|
|
18346
|
+
}
|
|
18347
|
+
console.log("");
|
|
18348
|
+
console.log(checker.formatStatus(status));
|
|
18349
|
+
console.log("");
|
|
18350
|
+
return { success: true, data: status };
|
|
18351
|
+
} catch (error) {
|
|
18352
|
+
const errMsg = error.message;
|
|
18353
|
+
if (options.json) {
|
|
18354
|
+
console.log(JSON.stringify({ success: false, error: errMsg }));
|
|
18355
|
+
} else {
|
|
18356
|
+
output_default.fail(errMsg);
|
|
18357
|
+
}
|
|
18358
|
+
return { success: false, error: errMsg };
|
|
18359
|
+
}
|
|
18360
|
+
}
|
|
17995
18361
|
/**
|
|
17996
18362
|
* Get session activity stats from today's events
|
|
17997
18363
|
* @see PRJ-89
|
|
@@ -18599,8 +18965,8 @@ Generated: ${(/* @__PURE__ */ new Date()).toLocaleString()}
|
|
|
18599
18965
|
const globalPath2 = path_manager_default.getGlobalProjectPath(projectId);
|
|
18600
18966
|
const specsPath2 = path37.join(globalPath2, "planning", "specs");
|
|
18601
18967
|
try {
|
|
18602
|
-
const
|
|
18603
|
-
const files = await
|
|
18968
|
+
const fs49 = await import("node:fs/promises");
|
|
18969
|
+
const files = await fs49.readdir(specsPath2);
|
|
18604
18970
|
const specs = files.filter((f) => f.endsWith(".md") && f !== ".gitkeep");
|
|
18605
18971
|
if (specs.length === 0) {
|
|
18606
18972
|
output_default.warn("no specs yet");
|
|
@@ -18812,6 +19178,198 @@ var init_project_service = __esm({
|
|
|
18812
19178
|
}
|
|
18813
19179
|
});
|
|
18814
19180
|
|
|
19181
|
+
// core/services/staleness-checker.ts
|
|
19182
|
+
import { exec as exec10 } from "node:child_process";
|
|
19183
|
+
import fs36 from "node:fs/promises";
|
|
19184
|
+
import path38 from "node:path";
|
|
19185
|
+
import { promisify as promisify10 } from "node:util";
|
|
19186
|
+
var execAsync5, DEFAULT_CONFIG, StalenessChecker, createStalenessChecker;
|
|
19187
|
+
var init_staleness_checker = __esm({
|
|
19188
|
+
"core/services/staleness-checker.ts"() {
|
|
19189
|
+
"use strict";
|
|
19190
|
+
init_path_manager();
|
|
19191
|
+
execAsync5 = promisify10(exec10);
|
|
19192
|
+
DEFAULT_CONFIG = {
|
|
19193
|
+
commitThreshold: 10,
|
|
19194
|
+
dayThreshold: 3,
|
|
19195
|
+
significantFiles: [
|
|
19196
|
+
"package.json",
|
|
19197
|
+
"tsconfig.json",
|
|
19198
|
+
"Cargo.toml",
|
|
19199
|
+
"go.mod",
|
|
19200
|
+
"requirements.txt",
|
|
19201
|
+
"pyproject.toml",
|
|
19202
|
+
".env.example",
|
|
19203
|
+
"docker-compose.yml",
|
|
19204
|
+
"Dockerfile"
|
|
19205
|
+
]
|
|
19206
|
+
};
|
|
19207
|
+
StalenessChecker = class {
|
|
19208
|
+
static {
|
|
19209
|
+
__name(this, "StalenessChecker");
|
|
19210
|
+
}
|
|
19211
|
+
projectPath;
|
|
19212
|
+
config;
|
|
19213
|
+
constructor(projectPath, config = {}) {
|
|
19214
|
+
this.projectPath = projectPath;
|
|
19215
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
19216
|
+
}
|
|
19217
|
+
/**
|
|
19218
|
+
* Check if the project context is stale
|
|
19219
|
+
*/
|
|
19220
|
+
async check(projectId) {
|
|
19221
|
+
const status = {
|
|
19222
|
+
isStale: false,
|
|
19223
|
+
reason: null,
|
|
19224
|
+
lastSyncCommit: null,
|
|
19225
|
+
currentCommit: null,
|
|
19226
|
+
commitsSinceSync: 0,
|
|
19227
|
+
daysSinceSync: 0,
|
|
19228
|
+
changedFiles: [],
|
|
19229
|
+
significantChanges: []
|
|
19230
|
+
};
|
|
19231
|
+
try {
|
|
19232
|
+
const projectJsonPath = path38.join(path_manager_default.getGlobalProjectPath(projectId), "project.json");
|
|
19233
|
+
let projectJson = {};
|
|
19234
|
+
try {
|
|
19235
|
+
projectJson = JSON.parse(await fs36.readFile(projectJsonPath, "utf-8"));
|
|
19236
|
+
} catch {
|
|
19237
|
+
status.isStale = true;
|
|
19238
|
+
status.reason = "No sync history found. Run `prjct sync` to initialize.";
|
|
19239
|
+
return status;
|
|
19240
|
+
}
|
|
19241
|
+
status.lastSyncCommit = projectJson.lastSyncCommit || null;
|
|
19242
|
+
const lastSync = projectJson.lastSync;
|
|
19243
|
+
try {
|
|
19244
|
+
const { stdout } = await execAsync5("git rev-parse --short HEAD", {
|
|
19245
|
+
cwd: this.projectPath
|
|
19246
|
+
});
|
|
19247
|
+
status.currentCommit = stdout.trim();
|
|
19248
|
+
} catch {
|
|
19249
|
+
status.reason = "Not a git repository";
|
|
19250
|
+
return status;
|
|
19251
|
+
}
|
|
19252
|
+
if (!status.lastSyncCommit) {
|
|
19253
|
+
status.isStale = true;
|
|
19254
|
+
status.reason = "No sync commit recorded. Run `prjct sync` to track.";
|
|
19255
|
+
return status;
|
|
19256
|
+
}
|
|
19257
|
+
if (status.lastSyncCommit === status.currentCommit) {
|
|
19258
|
+
status.reason = "Context is up to date";
|
|
19259
|
+
return status;
|
|
19260
|
+
}
|
|
19261
|
+
try {
|
|
19262
|
+
const { stdout } = await execAsync5(`git rev-list --count ${status.lastSyncCommit}..HEAD`, {
|
|
19263
|
+
cwd: this.projectPath
|
|
19264
|
+
});
|
|
19265
|
+
status.commitsSinceSync = parseInt(stdout.trim(), 10) || 0;
|
|
19266
|
+
} catch {
|
|
19267
|
+
status.isStale = true;
|
|
19268
|
+
status.reason = "Sync commit no longer exists (history changed). Run `prjct sync`.";
|
|
19269
|
+
return status;
|
|
19270
|
+
}
|
|
19271
|
+
if (lastSync) {
|
|
19272
|
+
const syncDate = new Date(lastSync);
|
|
19273
|
+
const now = /* @__PURE__ */ new Date();
|
|
19274
|
+
status.daysSinceSync = Math.floor(
|
|
19275
|
+
(now.getTime() - syncDate.getTime()) / (1e3 * 60 * 60 * 24)
|
|
19276
|
+
);
|
|
19277
|
+
}
|
|
19278
|
+
try {
|
|
19279
|
+
const { stdout } = await execAsync5(`git diff --name-only ${status.lastSyncCommit}..HEAD`, {
|
|
19280
|
+
cwd: this.projectPath
|
|
19281
|
+
});
|
|
19282
|
+
status.changedFiles = stdout.trim().split("\n").filter(Boolean);
|
|
19283
|
+
} catch {
|
|
19284
|
+
status.changedFiles = [];
|
|
19285
|
+
}
|
|
19286
|
+
status.significantChanges = status.changedFiles.filter(
|
|
19287
|
+
(file) => this.config.significantFiles.some((sig) => file.endsWith(sig) || file.includes(sig))
|
|
19288
|
+
);
|
|
19289
|
+
if (status.commitsSinceSync >= this.config.commitThreshold) {
|
|
19290
|
+
status.isStale = true;
|
|
19291
|
+
status.reason = `${status.commitsSinceSync} commits since last sync (threshold: ${this.config.commitThreshold})`;
|
|
19292
|
+
} else if (status.daysSinceSync >= this.config.dayThreshold) {
|
|
19293
|
+
status.isStale = true;
|
|
19294
|
+
status.reason = `${status.daysSinceSync} days since last sync (threshold: ${this.config.dayThreshold})`;
|
|
19295
|
+
} else if (status.significantChanges.length > 0) {
|
|
19296
|
+
status.isStale = true;
|
|
19297
|
+
status.reason = `Significant files changed: ${status.significantChanges.join(", ")}`;
|
|
19298
|
+
} else if (status.commitsSinceSync > 0) {
|
|
19299
|
+
status.reason = `${status.commitsSinceSync} commits since sync (threshold: ${this.config.commitThreshold})`;
|
|
19300
|
+
} else {
|
|
19301
|
+
status.reason = "Context is up to date";
|
|
19302
|
+
}
|
|
19303
|
+
return status;
|
|
19304
|
+
} catch (error) {
|
|
19305
|
+
status.reason = `Error checking staleness: ${error.message}`;
|
|
19306
|
+
return status;
|
|
19307
|
+
}
|
|
19308
|
+
}
|
|
19309
|
+
/**
|
|
19310
|
+
* Format staleness status for display
|
|
19311
|
+
*/
|
|
19312
|
+
formatStatus(status) {
|
|
19313
|
+
const lines = [];
|
|
19314
|
+
if (status.isStale) {
|
|
19315
|
+
lines.push("CLAUDE.md status: \u26A0\uFE0F STALE");
|
|
19316
|
+
} else {
|
|
19317
|
+
lines.push("CLAUDE.md status: \u2713 Fresh");
|
|
19318
|
+
}
|
|
19319
|
+
lines.push("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
19320
|
+
if (status.lastSyncCommit) {
|
|
19321
|
+
lines.push(`Last sync: ${status.lastSyncCommit}`);
|
|
19322
|
+
}
|
|
19323
|
+
if (status.currentCommit) {
|
|
19324
|
+
lines.push(`Current: ${status.currentCommit}`);
|
|
19325
|
+
}
|
|
19326
|
+
if (status.commitsSinceSync > 0) {
|
|
19327
|
+
lines.push(`Commits since: ${status.commitsSinceSync}`);
|
|
19328
|
+
}
|
|
19329
|
+
if (status.daysSinceSync > 0) {
|
|
19330
|
+
lines.push(`Days since: ${status.daysSinceSync}`);
|
|
19331
|
+
}
|
|
19332
|
+
if (status.changedFiles.length > 0) {
|
|
19333
|
+
lines.push(`Files changed: ${status.changedFiles.length}`);
|
|
19334
|
+
}
|
|
19335
|
+
if (status.significantChanges.length > 0) {
|
|
19336
|
+
lines.push(``);
|
|
19337
|
+
lines.push(`Significant changes:`);
|
|
19338
|
+
for (const file of status.significantChanges.slice(0, 5)) {
|
|
19339
|
+
lines.push(` \u2022 ${file}`);
|
|
19340
|
+
}
|
|
19341
|
+
if (status.significantChanges.length > 5) {
|
|
19342
|
+
lines.push(` ... and ${status.significantChanges.length - 5} more`);
|
|
19343
|
+
}
|
|
19344
|
+
}
|
|
19345
|
+
if (status.reason) {
|
|
19346
|
+
lines.push(``);
|
|
19347
|
+
lines.push(status.reason);
|
|
19348
|
+
}
|
|
19349
|
+
if (status.isStale) {
|
|
19350
|
+
lines.push(``);
|
|
19351
|
+
lines.push(`Run \`prjct sync\` to update context`);
|
|
19352
|
+
}
|
|
19353
|
+
return lines.join("\n");
|
|
19354
|
+
}
|
|
19355
|
+
/**
|
|
19356
|
+
* Get a short warning message if stale (for other commands)
|
|
19357
|
+
*/
|
|
19358
|
+
getWarning(status) {
|
|
19359
|
+
if (!status.isStale) return null;
|
|
19360
|
+
if (status.commitsSinceSync > 0) {
|
|
19361
|
+
return `\u26A0\uFE0F Context stale (${status.commitsSinceSync} commits behind). Run \`prjct sync\``;
|
|
19362
|
+
}
|
|
19363
|
+
if (status.daysSinceSync > 0) {
|
|
19364
|
+
return `\u26A0\uFE0F Context stale (${status.daysSinceSync} days old). Run \`prjct sync\``;
|
|
19365
|
+
}
|
|
19366
|
+
return `\u26A0\uFE0F Context may be stale. Run \`prjct sync\``;
|
|
19367
|
+
}
|
|
19368
|
+
};
|
|
19369
|
+
createStalenessChecker = /* @__PURE__ */ __name((projectPath, config) => new StalenessChecker(projectPath, config), "createStalenessChecker");
|
|
19370
|
+
}
|
|
19371
|
+
});
|
|
19372
|
+
|
|
18815
19373
|
// core/ai-tools/formatters.ts
|
|
18816
19374
|
function formatForClaude(ctx, _config) {
|
|
18817
19375
|
return `# ${ctx.name} - Project Rules
|
|
@@ -19031,9 +19589,9 @@ var init_formatters = __esm({
|
|
|
19031
19589
|
|
|
19032
19590
|
// core/ai-tools/registry.ts
|
|
19033
19591
|
import { execSync as execSync4 } from "node:child_process";
|
|
19034
|
-
import
|
|
19592
|
+
import fs37 from "node:fs";
|
|
19035
19593
|
import os11 from "node:os";
|
|
19036
|
-
import
|
|
19594
|
+
import path39 from "node:path";
|
|
19037
19595
|
function getAIToolConfig(id) {
|
|
19038
19596
|
return AI_TOOLS[id] || null;
|
|
19039
19597
|
}
|
|
@@ -19050,16 +19608,16 @@ function detectInstalledTools(repoPath = process.cwd()) {
|
|
|
19050
19608
|
if (commandExists("claude")) {
|
|
19051
19609
|
detected.push("claude");
|
|
19052
19610
|
}
|
|
19053
|
-
if (commandExists("cursor") ||
|
|
19611
|
+
if (commandExists("cursor") || fs37.existsSync(path39.join(repoPath, ".cursor"))) {
|
|
19054
19612
|
detected.push("cursor");
|
|
19055
19613
|
}
|
|
19056
|
-
if (
|
|
19614
|
+
if (fs37.existsSync(path39.join(repoPath, ".github"))) {
|
|
19057
19615
|
detected.push("copilot");
|
|
19058
19616
|
}
|
|
19059
|
-
if (commandExists("windsurf") ||
|
|
19617
|
+
if (commandExists("windsurf") || fs37.existsSync(path39.join(repoPath, ".windsurf"))) {
|
|
19060
19618
|
detected.push("windsurf");
|
|
19061
19619
|
}
|
|
19062
|
-
if (
|
|
19620
|
+
if (fs37.existsSync(path39.join(repoPath, ".continue")) || fs37.existsSync(path39.join(os11.homedir(), ".continue"))) {
|
|
19063
19621
|
detected.push("continue");
|
|
19064
19622
|
}
|
|
19065
19623
|
return detected;
|
|
@@ -19135,8 +19693,8 @@ var init_registry = __esm({
|
|
|
19135
19693
|
});
|
|
19136
19694
|
|
|
19137
19695
|
// core/ai-tools/generator.ts
|
|
19138
|
-
import
|
|
19139
|
-
import
|
|
19696
|
+
import fs38 from "node:fs/promises";
|
|
19697
|
+
import path40 from "node:path";
|
|
19140
19698
|
async function generateAIToolContexts(context2, globalPath, repoPath, toolIds = DEFAULT_AI_TOOLS) {
|
|
19141
19699
|
const results = [];
|
|
19142
19700
|
for (const toolId of toolIds) {
|
|
@@ -19171,13 +19729,13 @@ async function generateForTool(context2, config, globalPath, repoPath) {
|
|
|
19171
19729
|
let content = formatter(context2, config);
|
|
19172
19730
|
let outputPath;
|
|
19173
19731
|
if (config.outputPath === "repo") {
|
|
19174
|
-
outputPath =
|
|
19732
|
+
outputPath = path40.join(repoPath, config.outputFile);
|
|
19175
19733
|
} else {
|
|
19176
|
-
outputPath =
|
|
19734
|
+
outputPath = path40.join(globalPath, "context", config.outputFile);
|
|
19177
19735
|
}
|
|
19178
|
-
await
|
|
19736
|
+
await fs38.mkdir(path40.dirname(outputPath), { recursive: true });
|
|
19179
19737
|
try {
|
|
19180
|
-
const existingContent = await
|
|
19738
|
+
const existingContent = await fs38.readFile(outputPath, "utf-8");
|
|
19181
19739
|
const validation = validatePreserveBlocks(existingContent);
|
|
19182
19740
|
if (!validation.valid) {
|
|
19183
19741
|
console.warn(`\u26A0\uFE0F ${config.outputFile} has invalid preserve blocks:`);
|
|
@@ -19188,7 +19746,7 @@ async function generateForTool(context2, config, globalPath, repoPath) {
|
|
|
19188
19746
|
content = mergePreservedSections(content, existingContent);
|
|
19189
19747
|
} catch {
|
|
19190
19748
|
}
|
|
19191
|
-
await
|
|
19749
|
+
await fs38.writeFile(outputPath, content, "utf-8");
|
|
19192
19750
|
return {
|
|
19193
19751
|
toolId: config.id,
|
|
19194
19752
|
outputFile: config.outputFile,
|
|
@@ -19227,8 +19785,8 @@ var init_ai_tools = __esm({
|
|
|
19227
19785
|
});
|
|
19228
19786
|
|
|
19229
19787
|
// core/services/context-generator.ts
|
|
19230
|
-
import
|
|
19231
|
-
import
|
|
19788
|
+
import fs39 from "node:fs/promises";
|
|
19789
|
+
import path41 from "node:path";
|
|
19232
19790
|
var ContextFileGenerator;
|
|
19233
19791
|
var init_context_generator = __esm({
|
|
19234
19792
|
"core/services/context-generator.ts"() {
|
|
@@ -19252,10 +19810,10 @@ var init_context_generator = __esm({
|
|
|
19252
19810
|
async writeWithPreservation(filePath, content) {
|
|
19253
19811
|
let finalContent = content;
|
|
19254
19812
|
try {
|
|
19255
|
-
const existingContent = await
|
|
19813
|
+
const existingContent = await fs39.readFile(filePath, "utf-8");
|
|
19256
19814
|
const validation = validatePreserveBlocks(existingContent);
|
|
19257
19815
|
if (!validation.valid) {
|
|
19258
|
-
const filename =
|
|
19816
|
+
const filename = path41.basename(filePath);
|
|
19259
19817
|
console.warn(`\u26A0\uFE0F ${filename} has invalid preserve blocks:`);
|
|
19260
19818
|
for (const error of validation.errors) {
|
|
19261
19819
|
console.warn(` ${error}`);
|
|
@@ -19264,13 +19822,13 @@ var init_context_generator = __esm({
|
|
|
19264
19822
|
finalContent = mergePreservedSections(content, existingContent);
|
|
19265
19823
|
} catch {
|
|
19266
19824
|
}
|
|
19267
|
-
await
|
|
19825
|
+
await fs39.writeFile(filePath, finalContent, "utf-8");
|
|
19268
19826
|
}
|
|
19269
19827
|
/**
|
|
19270
19828
|
* Generate all context files in parallel
|
|
19271
19829
|
*/
|
|
19272
19830
|
async generate(git, stats, commands, agents) {
|
|
19273
|
-
const contextPath =
|
|
19831
|
+
const contextPath = path41.join(this.config.globalPath, "context");
|
|
19274
19832
|
await Promise.all([
|
|
19275
19833
|
this.generateClaudeMd(contextPath, git, stats, commands, agents),
|
|
19276
19834
|
this.generateNowMd(contextPath),
|
|
@@ -19364,7 +19922,7 @@ Load from \`~/.prjct-cli/projects/${this.config.projectId}/agents/\`:
|
|
|
19364
19922
|
**Workflow**: ${workflowAgents.join(", ")}
|
|
19365
19923
|
**Domain**: ${domainAgents.join(", ") || "none"}
|
|
19366
19924
|
`;
|
|
19367
|
-
const claudePath =
|
|
19925
|
+
const claudePath = path41.join(contextPath, "CLAUDE.md");
|
|
19368
19926
|
await this.writeWithPreservation(claudePath, content);
|
|
19369
19927
|
}
|
|
19370
19928
|
/**
|
|
@@ -19373,8 +19931,8 @@ Load from \`~/.prjct-cli/projects/${this.config.projectId}/agents/\`:
|
|
|
19373
19931
|
async generateNowMd(contextPath) {
|
|
19374
19932
|
let currentTask = null;
|
|
19375
19933
|
try {
|
|
19376
|
-
const statePath =
|
|
19377
|
-
const state = JSON.parse(await
|
|
19934
|
+
const statePath = path41.join(this.config.globalPath, "storage", "state.json");
|
|
19935
|
+
const state = JSON.parse(await fs39.readFile(statePath, "utf-8"));
|
|
19378
19936
|
currentTask = state.currentTask;
|
|
19379
19937
|
} catch {
|
|
19380
19938
|
}
|
|
@@ -19390,7 +19948,7 @@ _No active task_
|
|
|
19390
19948
|
|
|
19391
19949
|
Use \`p. task "description"\` to start working.
|
|
19392
19950
|
`;
|
|
19393
|
-
await this.writeWithPreservation(
|
|
19951
|
+
await this.writeWithPreservation(path41.join(contextPath, "now.md"), content);
|
|
19394
19952
|
}
|
|
19395
19953
|
/**
|
|
19396
19954
|
* Generate next.md - task queue
|
|
@@ -19398,15 +19956,15 @@ Use \`p. task "description"\` to start working.
|
|
|
19398
19956
|
async generateNextMd(contextPath) {
|
|
19399
19957
|
let queue = { tasks: [] };
|
|
19400
19958
|
try {
|
|
19401
|
-
const queuePath =
|
|
19402
|
-
queue = JSON.parse(await
|
|
19959
|
+
const queuePath = path41.join(this.config.globalPath, "storage", "queue.json");
|
|
19960
|
+
queue = JSON.parse(await fs39.readFile(queuePath, "utf-8"));
|
|
19403
19961
|
} catch {
|
|
19404
19962
|
}
|
|
19405
19963
|
const content = `# NEXT
|
|
19406
19964
|
|
|
19407
19965
|
${queue.tasks.length > 0 ? queue.tasks.map((t, i) => `${i + 1}. ${t.description}${t.priority ? ` [${t.priority}]` : ""}`).join("\n") : "_Empty queue_"}
|
|
19408
19966
|
`;
|
|
19409
|
-
await this.writeWithPreservation(
|
|
19967
|
+
await this.writeWithPreservation(path41.join(contextPath, "next.md"), content);
|
|
19410
19968
|
}
|
|
19411
19969
|
/**
|
|
19412
19970
|
* Generate ideas.md - captured ideas
|
|
@@ -19414,15 +19972,15 @@ ${queue.tasks.length > 0 ? queue.tasks.map((t, i) => `${i + 1}. ${t.description}
|
|
|
19414
19972
|
async generateIdeasMd(contextPath) {
|
|
19415
19973
|
let ideas = { ideas: [] };
|
|
19416
19974
|
try {
|
|
19417
|
-
const ideasPath =
|
|
19418
|
-
ideas = JSON.parse(await
|
|
19975
|
+
const ideasPath = path41.join(this.config.globalPath, "storage", "ideas.json");
|
|
19976
|
+
ideas = JSON.parse(await fs39.readFile(ideasPath, "utf-8"));
|
|
19419
19977
|
} catch {
|
|
19420
19978
|
}
|
|
19421
19979
|
const content = `# IDEAS
|
|
19422
19980
|
|
|
19423
19981
|
${ideas.ideas.length > 0 ? ideas.ideas.map((i) => `- ${i.text}${i.priority ? ` [${i.priority}]` : ""}`).join("\n") : "_No ideas captured yet_"}
|
|
19424
19982
|
`;
|
|
19425
|
-
await this.writeWithPreservation(
|
|
19983
|
+
await this.writeWithPreservation(path41.join(contextPath, "ideas.md"), content);
|
|
19426
19984
|
}
|
|
19427
19985
|
/**
|
|
19428
19986
|
* Generate shipped.md - completed features
|
|
@@ -19432,8 +19990,8 @@ ${ideas.ideas.length > 0 ? ideas.ideas.map((i) => `- ${i.text}${i.priority ? ` [
|
|
|
19432
19990
|
shipped: []
|
|
19433
19991
|
};
|
|
19434
19992
|
try {
|
|
19435
|
-
const shippedPath =
|
|
19436
|
-
shipped = JSON.parse(await
|
|
19993
|
+
const shippedPath = path41.join(this.config.globalPath, "storage", "shipped.json");
|
|
19994
|
+
shipped = JSON.parse(await fs39.readFile(shippedPath, "utf-8"));
|
|
19437
19995
|
} catch {
|
|
19438
19996
|
}
|
|
19439
19997
|
const content = `# SHIPPED \u{1F680}
|
|
@@ -19442,7 +20000,7 @@ ${shipped.shipped.length > 0 ? shipped.shipped.slice(-10).map((s) => `- **${s.na
|
|
|
19442
20000
|
|
|
19443
20001
|
**Total shipped:** ${shipped.shipped.length}
|
|
19444
20002
|
`;
|
|
19445
|
-
await this.writeWithPreservation(
|
|
20003
|
+
await this.writeWithPreservation(path41.join(contextPath, "shipped.md"), content);
|
|
19446
20004
|
}
|
|
19447
20005
|
// ==========================================================================
|
|
19448
20006
|
// MONOREPO SUPPORT
|
|
@@ -19471,9 +20029,9 @@ ${shipped.shipped.length > 0 ? shipped.shipped.slice(-10).map((s) => `- **${s.na
|
|
|
19471
20029
|
commands,
|
|
19472
20030
|
agents
|
|
19473
20031
|
);
|
|
19474
|
-
const claudePath =
|
|
20032
|
+
const claudePath = path41.join(pkg.path, "CLAUDE.md");
|
|
19475
20033
|
await this.writeWithPreservation(claudePath, content);
|
|
19476
|
-
generatedFiles.push(
|
|
20034
|
+
generatedFiles.push(path41.relative(this.config.projectPath, claudePath));
|
|
19477
20035
|
}
|
|
19478
20036
|
return generatedFiles;
|
|
19479
20037
|
}
|
|
@@ -19486,8 +20044,8 @@ ${shipped.shipped.length > 0 ? shipped.shipped.slice(-10).map((s) => `- **${s.na
|
|
|
19486
20044
|
let pkgVersion = stats.version;
|
|
19487
20045
|
let pkgName = pkg.name;
|
|
19488
20046
|
try {
|
|
19489
|
-
const pkgJsonPath =
|
|
19490
|
-
const pkgJson = JSON.parse(await
|
|
20047
|
+
const pkgJsonPath = path41.join(pkg.path, "package.json");
|
|
20048
|
+
const pkgJson = JSON.parse(await fs39.readFile(pkgJsonPath, "utf-8"));
|
|
19491
20049
|
pkgVersion = pkgJson.version || stats.version;
|
|
19492
20050
|
pkgName = pkgJson.name || pkg.name;
|
|
19493
20051
|
} catch {
|
|
@@ -19552,8 +20110,8 @@ Load from \`~/.prjct-cli/projects/${this.config.projectId}/agents/\`:
|
|
|
19552
20110
|
});
|
|
19553
20111
|
|
|
19554
20112
|
// core/services/stack-detector.ts
|
|
19555
|
-
import
|
|
19556
|
-
import
|
|
20113
|
+
import fs40 from "node:fs/promises";
|
|
20114
|
+
import path42 from "node:path";
|
|
19557
20115
|
var StackDetector;
|
|
19558
20116
|
var init_stack_detector = __esm({
|
|
19559
20117
|
"core/services/stack-detector.ts"() {
|
|
@@ -19712,8 +20270,8 @@ var init_stack_detector = __esm({
|
|
|
19712
20270
|
*/
|
|
19713
20271
|
async readPackageJson() {
|
|
19714
20272
|
try {
|
|
19715
|
-
const pkgPath =
|
|
19716
|
-
const content = await
|
|
20273
|
+
const pkgPath = path42.join(this.projectPath, "package.json");
|
|
20274
|
+
const content = await fs40.readFile(pkgPath, "utf-8");
|
|
19717
20275
|
return JSON.parse(content);
|
|
19718
20276
|
} catch {
|
|
19719
20277
|
return null;
|
|
@@ -19724,7 +20282,7 @@ var init_stack_detector = __esm({
|
|
|
19724
20282
|
*/
|
|
19725
20283
|
async fileExists(filename) {
|
|
19726
20284
|
try {
|
|
19727
|
-
await
|
|
20285
|
+
await fs40.access(path42.join(this.projectPath, filename));
|
|
19728
20286
|
return true;
|
|
19729
20287
|
} catch {
|
|
19730
20288
|
return false;
|
|
@@ -19735,11 +20293,11 @@ var init_stack_detector = __esm({
|
|
|
19735
20293
|
});
|
|
19736
20294
|
|
|
19737
20295
|
// core/services/sync-service.ts
|
|
19738
|
-
import { exec as
|
|
19739
|
-
import
|
|
19740
|
-
import
|
|
19741
|
-
import { promisify as
|
|
19742
|
-
var
|
|
20296
|
+
import { exec as exec11 } from "node:child_process";
|
|
20297
|
+
import fs41 from "node:fs/promises";
|
|
20298
|
+
import path43 from "node:path";
|
|
20299
|
+
import { promisify as promisify11 } from "node:util";
|
|
20300
|
+
var execAsync6, SyncService, syncService;
|
|
19743
20301
|
var init_sync_service = __esm({
|
|
19744
20302
|
"core/services/sync-service.ts"() {
|
|
19745
20303
|
"use strict";
|
|
@@ -19751,7 +20309,7 @@ var init_sync_service = __esm({
|
|
|
19751
20309
|
init_date_helper();
|
|
19752
20310
|
init_context_generator();
|
|
19753
20311
|
init_stack_detector();
|
|
19754
|
-
|
|
20312
|
+
execAsync6 = promisify11(exec11);
|
|
19755
20313
|
SyncService = class {
|
|
19756
20314
|
static {
|
|
19757
20315
|
__name(this, "SyncService");
|
|
@@ -19886,7 +20444,7 @@ var init_sync_service = __esm({
|
|
|
19886
20444
|
async ensureDirectories() {
|
|
19887
20445
|
const dirs = ["storage", "context", "agents", "memory", "analysis", "config", "sync"];
|
|
19888
20446
|
await Promise.all(
|
|
19889
|
-
dirs.map((dir) =>
|
|
20447
|
+
dirs.map((dir) => fs41.mkdir(path43.join(this.globalPath, dir), { recursive: true }))
|
|
19890
20448
|
);
|
|
19891
20449
|
}
|
|
19892
20450
|
// ==========================================================================
|
|
@@ -19905,19 +20463,19 @@ var init_sync_service = __esm({
|
|
|
19905
20463
|
weeklyCommits: 0
|
|
19906
20464
|
};
|
|
19907
20465
|
try {
|
|
19908
|
-
const { stdout: branch } = await
|
|
20466
|
+
const { stdout: branch } = await execAsync6("git branch --show-current", {
|
|
19909
20467
|
cwd: this.projectPath
|
|
19910
20468
|
});
|
|
19911
20469
|
data.branch = branch.trim() || "main";
|
|
19912
|
-
const { stdout: commits } = await
|
|
20470
|
+
const { stdout: commits } = await execAsync6("git rev-list --count HEAD", {
|
|
19913
20471
|
cwd: this.projectPath
|
|
19914
20472
|
});
|
|
19915
20473
|
data.commits = parseInt(commits.trim(), 10) || 0;
|
|
19916
|
-
const { stdout: contributors } = await
|
|
20474
|
+
const { stdout: contributors } = await execAsync6("git shortlog -sn --all | wc -l", {
|
|
19917
20475
|
cwd: this.projectPath
|
|
19918
20476
|
});
|
|
19919
20477
|
data.contributors = parseInt(contributors.trim(), 10) || 0;
|
|
19920
|
-
const { stdout: status } = await
|
|
20478
|
+
const { stdout: status } = await execAsync6("git status --porcelain", {
|
|
19921
20479
|
cwd: this.projectPath
|
|
19922
20480
|
});
|
|
19923
20481
|
const lines = status.trim().split("\n").filter(Boolean);
|
|
@@ -19933,7 +20491,7 @@ var init_sync_service = __esm({
|
|
|
19933
20491
|
data.untrackedFiles.push(file);
|
|
19934
20492
|
}
|
|
19935
20493
|
}
|
|
19936
|
-
const { stdout: log } = await
|
|
20494
|
+
const { stdout: log } = await execAsync6(
|
|
19937
20495
|
'git log --oneline -20 --pretty=format:"%h|%s|%ad" --date=short',
|
|
19938
20496
|
{ cwd: this.projectPath }
|
|
19939
20497
|
);
|
|
@@ -19941,7 +20499,7 @@ var init_sync_service = __esm({
|
|
|
19941
20499
|
const [hash, message, date] = line.split("|");
|
|
19942
20500
|
return { hash, message, date };
|
|
19943
20501
|
});
|
|
19944
|
-
const { stdout: weekly } = await
|
|
20502
|
+
const { stdout: weekly } = await execAsync6('git log --oneline --since="1 week ago" | wc -l', {
|
|
19945
20503
|
cwd: this.projectPath
|
|
19946
20504
|
});
|
|
19947
20505
|
data.weeklyCommits = parseInt(weekly.trim(), 10) || 0;
|
|
@@ -19956,14 +20514,14 @@ var init_sync_service = __esm({
|
|
|
19956
20514
|
const stats = {
|
|
19957
20515
|
fileCount: 0,
|
|
19958
20516
|
version: "0.0.0",
|
|
19959
|
-
name:
|
|
20517
|
+
name: path43.basename(this.projectPath),
|
|
19960
20518
|
ecosystem: "unknown",
|
|
19961
20519
|
projectType: "simple",
|
|
19962
20520
|
languages: [],
|
|
19963
20521
|
frameworks: []
|
|
19964
20522
|
};
|
|
19965
20523
|
try {
|
|
19966
|
-
const { stdout } = await
|
|
20524
|
+
const { stdout } = await execAsync6(
|
|
19967
20525
|
'find . -type f \\( -name "*.js" -o -name "*.ts" -o -name "*.tsx" -o -name "*.py" -o -name "*.go" -o -name "*.rs" \\) -not -path "./node_modules/*" -not -path "./.git/*" | wc -l',
|
|
19968
20526
|
{ cwd: this.projectPath }
|
|
19969
20527
|
);
|
|
@@ -19972,8 +20530,8 @@ var init_sync_service = __esm({
|
|
|
19972
20530
|
stats.fileCount = 0;
|
|
19973
20531
|
}
|
|
19974
20532
|
try {
|
|
19975
|
-
const pkgPath =
|
|
19976
|
-
const pkg = JSON.parse(await
|
|
20533
|
+
const pkgPath = path43.join(this.projectPath, "package.json");
|
|
20534
|
+
const pkg = JSON.parse(await fs41.readFile(pkgPath, "utf-8"));
|
|
19977
20535
|
stats.version = pkg.version || "0.0.0";
|
|
19978
20536
|
stats.name = pkg.name || stats.name;
|
|
19979
20537
|
stats.ecosystem = "JavaScript";
|
|
@@ -20081,12 +20639,12 @@ var init_sync_service = __esm({
|
|
|
20081
20639
|
// ==========================================================================
|
|
20082
20640
|
async generateAgents(stack, stats) {
|
|
20083
20641
|
const agents = [];
|
|
20084
|
-
const agentsPath =
|
|
20642
|
+
const agentsPath = path43.join(this.globalPath, "agents");
|
|
20085
20643
|
try {
|
|
20086
|
-
const files = await
|
|
20644
|
+
const files = await fs41.readdir(agentsPath);
|
|
20087
20645
|
for (const file of files) {
|
|
20088
20646
|
if (file.endsWith(".md")) {
|
|
20089
|
-
await
|
|
20647
|
+
await fs41.unlink(path43.join(agentsPath, file));
|
|
20090
20648
|
}
|
|
20091
20649
|
}
|
|
20092
20650
|
} catch {
|
|
@@ -20126,7 +20684,7 @@ var init_sync_service = __esm({
|
|
|
20126
20684
|
async generateWorkflowAgent(name, agentsPath) {
|
|
20127
20685
|
let content = "";
|
|
20128
20686
|
try {
|
|
20129
|
-
const templatePath =
|
|
20687
|
+
const templatePath = path43.join(
|
|
20130
20688
|
__dirname,
|
|
20131
20689
|
"..",
|
|
20132
20690
|
"..",
|
|
@@ -20135,16 +20693,16 @@ var init_sync_service = __esm({
|
|
|
20135
20693
|
"workflow",
|
|
20136
20694
|
`${name}.md`
|
|
20137
20695
|
);
|
|
20138
|
-
content = await
|
|
20696
|
+
content = await fs41.readFile(templatePath, "utf-8");
|
|
20139
20697
|
} catch {
|
|
20140
20698
|
content = this.generateMinimalWorkflowAgent(name);
|
|
20141
20699
|
}
|
|
20142
|
-
await
|
|
20700
|
+
await fs41.writeFile(path43.join(agentsPath, `${name}.md`), content, "utf-8");
|
|
20143
20701
|
}
|
|
20144
20702
|
async generateDomainAgent(name, agentsPath, stats, stack) {
|
|
20145
20703
|
let content = "";
|
|
20146
20704
|
try {
|
|
20147
|
-
const templatePath =
|
|
20705
|
+
const templatePath = path43.join(
|
|
20148
20706
|
__dirname,
|
|
20149
20707
|
"..",
|
|
20150
20708
|
"..",
|
|
@@ -20153,14 +20711,14 @@ var init_sync_service = __esm({
|
|
|
20153
20711
|
"domain",
|
|
20154
20712
|
`${name}.md`
|
|
20155
20713
|
);
|
|
20156
|
-
content = await
|
|
20714
|
+
content = await fs41.readFile(templatePath, "utf-8");
|
|
20157
20715
|
content = content.replace("{projectName}", stats.name);
|
|
20158
20716
|
content = content.replace("{frameworks}", stack.frameworks.join(", ") || "None detected");
|
|
20159
20717
|
content = content.replace("{ecosystem}", stats.ecosystem);
|
|
20160
20718
|
} catch {
|
|
20161
20719
|
content = this.generateMinimalDomainAgent(name, stats, stack);
|
|
20162
20720
|
}
|
|
20163
|
-
await
|
|
20721
|
+
await fs41.writeFile(path43.join(agentsPath, `${name}.md`), content, "utf-8");
|
|
20164
20722
|
}
|
|
20165
20723
|
generateMinimalWorkflowAgent(name) {
|
|
20166
20724
|
const descriptions = {
|
|
@@ -20228,8 +20786,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
20228
20786
|
})),
|
|
20229
20787
|
agentSkillMap: Object.fromEntries(skills.map((s) => [s.agent, s.skill]))
|
|
20230
20788
|
};
|
|
20231
|
-
|
|
20232
|
-
|
|
20789
|
+
fs41.writeFile(
|
|
20790
|
+
path43.join(this.globalPath, "config", "skills.json"),
|
|
20233
20791
|
JSON.stringify(skillsConfig, null, 2),
|
|
20234
20792
|
"utf-8"
|
|
20235
20793
|
).catch(() => {
|
|
@@ -20251,10 +20809,10 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
20251
20809
|
// PROJECT.JSON UPDATE
|
|
20252
20810
|
// ==========================================================================
|
|
20253
20811
|
async updateProjectJson(git, stats) {
|
|
20254
|
-
const projectJsonPath =
|
|
20812
|
+
const projectJsonPath = path43.join(this.globalPath, "project.json");
|
|
20255
20813
|
let existing = {};
|
|
20256
20814
|
try {
|
|
20257
|
-
existing = JSON.parse(await
|
|
20815
|
+
existing = JSON.parse(await fs41.readFile(projectJsonPath, "utf-8"));
|
|
20258
20816
|
} catch {
|
|
20259
20817
|
}
|
|
20260
20818
|
const updated = {
|
|
@@ -20271,18 +20829,21 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
20271
20829
|
currentBranch: git.branch,
|
|
20272
20830
|
hasUncommittedChanges: git.hasChanges,
|
|
20273
20831
|
createdAt: existing.createdAt || date_helper_default.getTimestamp(),
|
|
20274
|
-
lastSync: date_helper_default.getTimestamp()
|
|
20832
|
+
lastSync: date_helper_default.getTimestamp(),
|
|
20833
|
+
// Staleness tracking (PRJ-120)
|
|
20834
|
+
lastSyncCommit: git.recentCommits[0]?.hash || null,
|
|
20835
|
+
lastSyncBranch: git.branch
|
|
20275
20836
|
};
|
|
20276
|
-
await
|
|
20837
|
+
await fs41.writeFile(projectJsonPath, JSON.stringify(updated, null, 2), "utf-8");
|
|
20277
20838
|
}
|
|
20278
20839
|
// ==========================================================================
|
|
20279
20840
|
// STATE.JSON UPDATE
|
|
20280
20841
|
// ==========================================================================
|
|
20281
20842
|
async updateStateJson(stats, stack) {
|
|
20282
|
-
const statePath =
|
|
20843
|
+
const statePath = path43.join(this.globalPath, "storage", "state.json");
|
|
20283
20844
|
let state = {};
|
|
20284
20845
|
try {
|
|
20285
|
-
state = JSON.parse(await
|
|
20846
|
+
state = JSON.parse(await fs41.readFile(statePath, "utf-8"));
|
|
20286
20847
|
} catch {
|
|
20287
20848
|
}
|
|
20288
20849
|
state.projectId = this.projectId;
|
|
@@ -20309,13 +20870,13 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
20309
20870
|
lastAction: "Synced project",
|
|
20310
20871
|
nextAction: 'Run `p. task "description"` to start working'
|
|
20311
20872
|
};
|
|
20312
|
-
await
|
|
20873
|
+
await fs41.writeFile(statePath, JSON.stringify(state, null, 2), "utf-8");
|
|
20313
20874
|
}
|
|
20314
20875
|
// ==========================================================================
|
|
20315
20876
|
// MEMORY LOGGING
|
|
20316
20877
|
// ==========================================================================
|
|
20317
20878
|
async logToMemory(git, stats) {
|
|
20318
|
-
const memoryPath =
|
|
20879
|
+
const memoryPath = path43.join(this.globalPath, "memory", "events.jsonl");
|
|
20319
20880
|
const event = {
|
|
20320
20881
|
ts: date_helper_default.getTimestamp(),
|
|
20321
20882
|
action: "sync",
|
|
@@ -20324,7 +20885,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
20324
20885
|
fileCount: stats.fileCount,
|
|
20325
20886
|
commitCount: git.commits
|
|
20326
20887
|
};
|
|
20327
|
-
await
|
|
20888
|
+
await fs41.appendFile(memoryPath, `${JSON.stringify(event)}
|
|
20328
20889
|
`, "utf-8");
|
|
20329
20890
|
}
|
|
20330
20891
|
// ==========================================================================
|
|
@@ -20344,16 +20905,16 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
20344
20905
|
let filteredChars = 0;
|
|
20345
20906
|
for (const file of contextFiles) {
|
|
20346
20907
|
try {
|
|
20347
|
-
const filePath =
|
|
20348
|
-
const content = await
|
|
20908
|
+
const filePath = path43.join(this.globalPath, file);
|
|
20909
|
+
const content = await fs41.readFile(filePath, "utf-8");
|
|
20349
20910
|
filteredChars += content.length;
|
|
20350
20911
|
} catch {
|
|
20351
20912
|
}
|
|
20352
20913
|
}
|
|
20353
20914
|
for (const agent of agents) {
|
|
20354
20915
|
try {
|
|
20355
|
-
const agentPath =
|
|
20356
|
-
const content = await
|
|
20916
|
+
const agentPath = path43.join(this.globalPath, "agents", `${agent.name}.md`);
|
|
20917
|
+
const content = await fs41.readFile(agentPath, "utf-8");
|
|
20357
20918
|
filteredChars += content.length;
|
|
20358
20919
|
} catch {
|
|
20359
20920
|
}
|
|
@@ -20385,7 +20946,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
20385
20946
|
// ==========================================================================
|
|
20386
20947
|
async fileExists(filename) {
|
|
20387
20948
|
try {
|
|
20388
|
-
await
|
|
20949
|
+
await fs41.access(path43.join(this.projectPath, filename));
|
|
20389
20950
|
return true;
|
|
20390
20951
|
} catch {
|
|
20391
20952
|
return false;
|
|
@@ -20393,8 +20954,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
20393
20954
|
}
|
|
20394
20955
|
async getCliVersion() {
|
|
20395
20956
|
try {
|
|
20396
|
-
const pkgPath =
|
|
20397
|
-
const pkg = JSON.parse(await
|
|
20957
|
+
const pkgPath = path43.join(__dirname, "..", "..", "package.json");
|
|
20958
|
+
const pkg = JSON.parse(await fs41.readFile(pkgPath, "utf-8"));
|
|
20398
20959
|
return pkg.version || "0.0.0";
|
|
20399
20960
|
} catch {
|
|
20400
20961
|
return "0.0.0";
|
|
@@ -20467,6 +21028,7 @@ var init_services = __esm({
|
|
|
20467
21028
|
init_nested_context_resolver();
|
|
20468
21029
|
init_project_index();
|
|
20469
21030
|
init_project_service();
|
|
21031
|
+
init_staleness_checker();
|
|
20470
21032
|
init_sync_service();
|
|
20471
21033
|
}
|
|
20472
21034
|
});
|
|
@@ -20554,22 +21116,22 @@ __export(uninstall_exports, {
|
|
|
20554
21116
|
});
|
|
20555
21117
|
import { execSync as execSync5 } from "node:child_process";
|
|
20556
21118
|
import fsSync2 from "node:fs";
|
|
20557
|
-
import
|
|
21119
|
+
import fs42 from "node:fs/promises";
|
|
20558
21120
|
import os12 from "node:os";
|
|
20559
|
-
import
|
|
21121
|
+
import path44 from "node:path";
|
|
20560
21122
|
import readline2 from "node:readline";
|
|
20561
21123
|
import chalk9 from "chalk";
|
|
20562
21124
|
async function getDirectorySize(dirPath) {
|
|
20563
21125
|
let totalSize = 0;
|
|
20564
21126
|
try {
|
|
20565
|
-
const entries = await
|
|
21127
|
+
const entries = await fs42.readdir(dirPath, { withFileTypes: true });
|
|
20566
21128
|
for (const entry of entries) {
|
|
20567
|
-
const entryPath =
|
|
21129
|
+
const entryPath = path44.join(dirPath, entry.name);
|
|
20568
21130
|
if (entry.isDirectory()) {
|
|
20569
21131
|
totalSize += await getDirectorySize(entryPath);
|
|
20570
21132
|
} else {
|
|
20571
21133
|
try {
|
|
20572
|
-
const stats = await
|
|
21134
|
+
const stats = await fs42.stat(entryPath);
|
|
20573
21135
|
totalSize += stats.size;
|
|
20574
21136
|
} catch {
|
|
20575
21137
|
}
|
|
@@ -20588,7 +21150,7 @@ function formatSize(bytes) {
|
|
|
20588
21150
|
}
|
|
20589
21151
|
async function countDirectoryItems(dirPath) {
|
|
20590
21152
|
try {
|
|
20591
|
-
const entries = await
|
|
21153
|
+
const entries = await fs42.readdir(dirPath, { withFileTypes: true });
|
|
20592
21154
|
return entries.filter((e) => e.isDirectory()).length;
|
|
20593
21155
|
} catch {
|
|
20594
21156
|
return 0;
|
|
@@ -20621,7 +21183,7 @@ async function gatherUninstallItems() {
|
|
|
20621
21183
|
const providerPaths = getProviderPaths();
|
|
20622
21184
|
const prjctCliPath = path_manager_default.getGlobalBasePath();
|
|
20623
21185
|
const prjctCliExists = fsSync2.existsSync(prjctCliPath);
|
|
20624
|
-
const projectCount = prjctCliExists ? await countDirectoryItems(
|
|
21186
|
+
const projectCount = prjctCliExists ? await countDirectoryItems(path44.join(prjctCliPath, "projects")) : 0;
|
|
20625
21187
|
const prjctCliSize = prjctCliExists ? await getDirectorySize(prjctCliPath) : 0;
|
|
20626
21188
|
items.push({
|
|
20627
21189
|
path: prjctCliPath,
|
|
@@ -20631,7 +21193,7 @@ async function gatherUninstallItems() {
|
|
|
20631
21193
|
count: projectCount,
|
|
20632
21194
|
exists: prjctCliExists
|
|
20633
21195
|
});
|
|
20634
|
-
const claudeMdPath =
|
|
21196
|
+
const claudeMdPath = path44.join(providerPaths.claude.config, "CLAUDE.md");
|
|
20635
21197
|
const claudeMdExists = fsSync2.existsSync(claudeMdPath);
|
|
20636
21198
|
let hasPrjctSection = false;
|
|
20637
21199
|
if (claudeMdExists) {
|
|
@@ -20665,7 +21227,7 @@ async function gatherUninstallItems() {
|
|
|
20665
21227
|
description: "Claude router",
|
|
20666
21228
|
exists: claudeRouterExists
|
|
20667
21229
|
});
|
|
20668
|
-
const statusLinePath =
|
|
21230
|
+
const statusLinePath = path44.join(providerPaths.claude.config, "prjct-statusline.sh");
|
|
20669
21231
|
const statusLineExists = fsSync2.existsSync(statusLinePath);
|
|
20670
21232
|
items.push({
|
|
20671
21233
|
path: statusLinePath,
|
|
@@ -20681,7 +21243,7 @@ async function gatherUninstallItems() {
|
|
|
20681
21243
|
description: "Gemini router",
|
|
20682
21244
|
exists: geminiRouterExists
|
|
20683
21245
|
});
|
|
20684
|
-
const geminiMdPath =
|
|
21246
|
+
const geminiMdPath = path44.join(providerPaths.gemini.config, "GEMINI.md");
|
|
20685
21247
|
const geminiMdExists = fsSync2.existsSync(geminiMdPath);
|
|
20686
21248
|
let hasGeminiPrjctSection = false;
|
|
20687
21249
|
if (geminiMdExists) {
|
|
@@ -20703,7 +21265,7 @@ async function gatherUninstallItems() {
|
|
|
20703
21265
|
}
|
|
20704
21266
|
async function removePrjctSection(filePath) {
|
|
20705
21267
|
try {
|
|
20706
|
-
const content = await
|
|
21268
|
+
const content = await fs42.readFile(filePath, "utf-8");
|
|
20707
21269
|
if (!content.includes(PRJCT_START_MARKER) || !content.includes(PRJCT_END_MARKER)) {
|
|
20708
21270
|
return false;
|
|
20709
21271
|
}
|
|
@@ -20712,9 +21274,9 @@ async function removePrjctSection(filePath) {
|
|
|
20712
21274
|
let newContent = content.substring(0, startIndex) + content.substring(endIndex);
|
|
20713
21275
|
newContent = newContent.replace(/\n{3,}/g, "\n\n").trim();
|
|
20714
21276
|
if (!newContent || newContent.trim().length === 0) {
|
|
20715
|
-
await
|
|
21277
|
+
await fs42.unlink(filePath);
|
|
20716
21278
|
} else {
|
|
20717
|
-
await
|
|
21279
|
+
await fs42.writeFile(filePath, `${newContent}
|
|
20718
21280
|
`, "utf-8");
|
|
20719
21281
|
}
|
|
20720
21282
|
return true;
|
|
@@ -20725,12 +21287,12 @@ async function removePrjctSection(filePath) {
|
|
|
20725
21287
|
async function createBackup() {
|
|
20726
21288
|
const homeDir = os12.homedir();
|
|
20727
21289
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").substring(0, 19);
|
|
20728
|
-
const backupDir =
|
|
21290
|
+
const backupDir = path44.join(homeDir, `.prjct-backup-${timestamp}`);
|
|
20729
21291
|
try {
|
|
20730
|
-
await
|
|
21292
|
+
await fs42.mkdir(backupDir, { recursive: true });
|
|
20731
21293
|
const prjctCliPath = path_manager_default.getGlobalBasePath();
|
|
20732
21294
|
if (fsSync2.existsSync(prjctCliPath)) {
|
|
20733
|
-
await copyDirectory(prjctCliPath,
|
|
21295
|
+
await copyDirectory(prjctCliPath, path44.join(backupDir, ".prjct-cli"));
|
|
20734
21296
|
}
|
|
20735
21297
|
return backupDir;
|
|
20736
21298
|
} catch {
|
|
@@ -20738,15 +21300,15 @@ async function createBackup() {
|
|
|
20738
21300
|
}
|
|
20739
21301
|
}
|
|
20740
21302
|
async function copyDirectory(src, dest) {
|
|
20741
|
-
await
|
|
20742
|
-
const entries = await
|
|
21303
|
+
await fs42.mkdir(dest, { recursive: true });
|
|
21304
|
+
const entries = await fs42.readdir(src, { withFileTypes: true });
|
|
20743
21305
|
for (const entry of entries) {
|
|
20744
|
-
const srcPath =
|
|
20745
|
-
const destPath =
|
|
21306
|
+
const srcPath = path44.join(src, entry.name);
|
|
21307
|
+
const destPath = path44.join(dest, entry.name);
|
|
20746
21308
|
if (entry.isDirectory()) {
|
|
20747
21309
|
await copyDirectory(srcPath, destPath);
|
|
20748
21310
|
} else {
|
|
20749
|
-
await
|
|
21311
|
+
await fs42.copyFile(srcPath, destPath);
|
|
20750
21312
|
}
|
|
20751
21313
|
}
|
|
20752
21314
|
}
|
|
@@ -20762,10 +21324,10 @@ async function performUninstall(items, installation, options) {
|
|
|
20762
21324
|
deleted.push(item.path);
|
|
20763
21325
|
}
|
|
20764
21326
|
} else if (item.type === "directory") {
|
|
20765
|
-
await
|
|
21327
|
+
await fs42.rm(item.path, { recursive: true, force: true });
|
|
20766
21328
|
deleted.push(item.path);
|
|
20767
21329
|
} else if (item.type === "file") {
|
|
20768
|
-
await
|
|
21330
|
+
await fs42.unlink(item.path);
|
|
20769
21331
|
deleted.push(item.path);
|
|
20770
21332
|
}
|
|
20771
21333
|
} catch (error) {
|
|
@@ -20940,7 +21502,7 @@ __export(watch_service_exports, {
|
|
|
20940
21502
|
WatchService: () => WatchService,
|
|
20941
21503
|
watchService: () => watchService
|
|
20942
21504
|
});
|
|
20943
|
-
import
|
|
21505
|
+
import path45 from "node:path";
|
|
20944
21506
|
import chalk10 from "chalk";
|
|
20945
21507
|
import chokidar from "chokidar";
|
|
20946
21508
|
var TRIGGER_PATTERNS, IGNORE_PATTERNS2, WatchService, watchService;
|
|
@@ -21145,7 +21707,7 @@ ${chalk10.dim(`[${timestamp}]`)} ${chalk10.cyan("\u27F3")} ${filesSummary} chang
|
|
|
21145
21707
|
printStartup() {
|
|
21146
21708
|
console.log("");
|
|
21147
21709
|
console.log(chalk10.cyan("\u{1F441}\uFE0F Watching for changes..."));
|
|
21148
|
-
console.log(chalk10.dim(` Project: ${
|
|
21710
|
+
console.log(chalk10.dim(` Project: ${path45.basename(this.projectPath)}`));
|
|
21149
21711
|
console.log(chalk10.dim(` Debounce: ${this.options.debounceMs}ms`));
|
|
21150
21712
|
console.log(chalk10.dim(` Min interval: ${this.options.minIntervalMs / 1e3}s`));
|
|
21151
21713
|
console.log("");
|
|
@@ -21337,6 +21899,22 @@ var init_command_data = __esm({
|
|
|
21337
21899
|
hasTemplate: true,
|
|
21338
21900
|
requiresProject: true
|
|
21339
21901
|
},
|
|
21902
|
+
{
|
|
21903
|
+
name: "status",
|
|
21904
|
+
group: "core",
|
|
21905
|
+
description: "Check if CLAUDE.md context is stale and needs resync",
|
|
21906
|
+
usage: { claude: "/p:status", terminal: "prjct status" },
|
|
21907
|
+
params: "[--json]",
|
|
21908
|
+
implemented: true,
|
|
21909
|
+
hasTemplate: false,
|
|
21910
|
+
requiresProject: true,
|
|
21911
|
+
features: [
|
|
21912
|
+
"Compares current HEAD with last sync commit",
|
|
21913
|
+
"Counts commits and days since sync",
|
|
21914
|
+
"Detects significant file changes",
|
|
21915
|
+
"Configurable staleness thresholds"
|
|
21916
|
+
]
|
|
21917
|
+
},
|
|
21340
21918
|
{
|
|
21341
21919
|
name: "help",
|
|
21342
21920
|
group: "core",
|
|
@@ -21802,9 +22380,9 @@ __export(setup_exports, {
|
|
|
21802
22380
|
run: () => run
|
|
21803
22381
|
});
|
|
21804
22382
|
import { execSync as execSync6 } from "node:child_process";
|
|
21805
|
-
import
|
|
22383
|
+
import fs43 from "node:fs";
|
|
21806
22384
|
import os13 from "node:os";
|
|
21807
|
-
import
|
|
22385
|
+
import path46 from "node:path";
|
|
21808
22386
|
async function installAICLI(provider) {
|
|
21809
22387
|
const packageName = provider.name === "claude" ? "@anthropic-ai/claude-code" : "@google/gemini-cli";
|
|
21810
22388
|
try {
|
|
@@ -21910,12 +22488,12 @@ async function run() {
|
|
|
21910
22488
|
}
|
|
21911
22489
|
async function installGeminiRouter() {
|
|
21912
22490
|
try {
|
|
21913
|
-
const geminiCommandsDir =
|
|
21914
|
-
const routerSource =
|
|
21915
|
-
const routerDest =
|
|
21916
|
-
|
|
21917
|
-
if (
|
|
21918
|
-
|
|
22491
|
+
const geminiCommandsDir = path46.join(os13.homedir(), ".gemini", "commands");
|
|
22492
|
+
const routerSource = path46.join(getPackageRoot(), "templates", "commands", "p.toml");
|
|
22493
|
+
const routerDest = path46.join(geminiCommandsDir, "p.toml");
|
|
22494
|
+
fs43.mkdirSync(geminiCommandsDir, { recursive: true });
|
|
22495
|
+
if (fs43.existsSync(routerSource)) {
|
|
22496
|
+
fs43.copyFileSync(routerSource, routerDest);
|
|
21919
22497
|
return true;
|
|
21920
22498
|
}
|
|
21921
22499
|
return false;
|
|
@@ -21926,15 +22504,15 @@ async function installGeminiRouter() {
|
|
|
21926
22504
|
}
|
|
21927
22505
|
async function installGeminiGlobalConfig() {
|
|
21928
22506
|
try {
|
|
21929
|
-
const geminiDir =
|
|
21930
|
-
const globalConfigPath =
|
|
21931
|
-
const templatePath =
|
|
21932
|
-
|
|
21933
|
-
const templateContent =
|
|
22507
|
+
const geminiDir = path46.join(os13.homedir(), ".gemini");
|
|
22508
|
+
const globalConfigPath = path46.join(geminiDir, "GEMINI.md");
|
|
22509
|
+
const templatePath = path46.join(getPackageRoot(), "templates", "global", "GEMINI.md");
|
|
22510
|
+
fs43.mkdirSync(geminiDir, { recursive: true });
|
|
22511
|
+
const templateContent = fs43.readFileSync(templatePath, "utf-8");
|
|
21934
22512
|
let existingContent = "";
|
|
21935
22513
|
let fileExists2 = false;
|
|
21936
22514
|
try {
|
|
21937
|
-
existingContent =
|
|
22515
|
+
existingContent = fs43.readFileSync(globalConfigPath, "utf-8");
|
|
21938
22516
|
fileExists2 = true;
|
|
21939
22517
|
} catch (error) {
|
|
21940
22518
|
if (isNotFoundError(error)) {
|
|
@@ -21944,7 +22522,7 @@ async function installGeminiGlobalConfig() {
|
|
|
21944
22522
|
}
|
|
21945
22523
|
}
|
|
21946
22524
|
if (!fileExists2) {
|
|
21947
|
-
|
|
22525
|
+
fs43.writeFileSync(globalConfigPath, templateContent, "utf-8");
|
|
21948
22526
|
return { success: true, action: "created" };
|
|
21949
22527
|
}
|
|
21950
22528
|
const startMarker = "<!-- prjct:start - DO NOT REMOVE THIS MARKER -->";
|
|
@@ -21954,7 +22532,7 @@ async function installGeminiGlobalConfig() {
|
|
|
21954
22532
|
const updatedContent2 = `${existingContent}
|
|
21955
22533
|
|
|
21956
22534
|
${templateContent}`;
|
|
21957
|
-
|
|
22535
|
+
fs43.writeFileSync(globalConfigPath, updatedContent2, "utf-8");
|
|
21958
22536
|
return { success: true, action: "appended" };
|
|
21959
22537
|
}
|
|
21960
22538
|
const beforeMarker = existingContent.substring(0, existingContent.indexOf(startMarker));
|
|
@@ -21966,7 +22544,7 @@ ${templateContent}`;
|
|
|
21966
22544
|
templateContent.indexOf(endMarker) + endMarker.length
|
|
21967
22545
|
);
|
|
21968
22546
|
const updatedContent = beforeMarker + prjctSection + afterMarker;
|
|
21969
|
-
|
|
22547
|
+
fs43.writeFileSync(globalConfigPath, updatedContent, "utf-8");
|
|
21970
22548
|
return { success: true, action: "updated" };
|
|
21971
22549
|
} catch (error) {
|
|
21972
22550
|
console.error(`Gemini config warning: ${error.message}`);
|
|
@@ -21975,18 +22553,18 @@ ${templateContent}`;
|
|
|
21975
22553
|
}
|
|
21976
22554
|
async function installAntigravitySkill() {
|
|
21977
22555
|
try {
|
|
21978
|
-
const antigravitySkillsDir =
|
|
21979
|
-
const prjctSkillDir =
|
|
21980
|
-
const skillMdPath =
|
|
21981
|
-
const templatePath =
|
|
21982
|
-
|
|
21983
|
-
const fileExists2 =
|
|
21984
|
-
if (!
|
|
22556
|
+
const antigravitySkillsDir = path46.join(os13.homedir(), ".gemini", "antigravity", "skills");
|
|
22557
|
+
const prjctSkillDir = path46.join(antigravitySkillsDir, "prjct");
|
|
22558
|
+
const skillMdPath = path46.join(prjctSkillDir, "SKILL.md");
|
|
22559
|
+
const templatePath = path46.join(getPackageRoot(), "templates", "antigravity", "SKILL.md");
|
|
22560
|
+
fs43.mkdirSync(prjctSkillDir, { recursive: true });
|
|
22561
|
+
const fileExists2 = fs43.existsSync(skillMdPath);
|
|
22562
|
+
if (!fs43.existsSync(templatePath)) {
|
|
21985
22563
|
console.error("Antigravity SKILL.md template not found");
|
|
21986
22564
|
return { success: false, action: null };
|
|
21987
22565
|
}
|
|
21988
|
-
const templateContent =
|
|
21989
|
-
|
|
22566
|
+
const templateContent = fs43.readFileSync(templatePath, "utf-8");
|
|
22567
|
+
fs43.writeFileSync(skillMdPath, templateContent, "utf-8");
|
|
21990
22568
|
return { success: true, action: fileExists2 ? "updated" : "created" };
|
|
21991
22569
|
} catch (error) {
|
|
21992
22570
|
console.error(`Antigravity skill warning: ${error.message}`);
|
|
@@ -22005,24 +22583,24 @@ async function installCursorProject(projectRoot) {
|
|
|
22005
22583
|
gitignoreUpdated: false
|
|
22006
22584
|
};
|
|
22007
22585
|
try {
|
|
22008
|
-
const cursorDir =
|
|
22009
|
-
const rulesDir =
|
|
22010
|
-
const commandsDir =
|
|
22011
|
-
const routerMdcDest =
|
|
22012
|
-
const routerMdcSource =
|
|
22013
|
-
const cursorCommandsSource =
|
|
22014
|
-
|
|
22015
|
-
|
|
22016
|
-
if (
|
|
22017
|
-
|
|
22586
|
+
const cursorDir = path46.join(projectRoot, ".cursor");
|
|
22587
|
+
const rulesDir = path46.join(cursorDir, "rules");
|
|
22588
|
+
const commandsDir = path46.join(cursorDir, "commands");
|
|
22589
|
+
const routerMdcDest = path46.join(rulesDir, "prjct.mdc");
|
|
22590
|
+
const routerMdcSource = path46.join(getPackageRoot(), "templates", "cursor", "router.mdc");
|
|
22591
|
+
const cursorCommandsSource = path46.join(getPackageRoot(), "templates", "cursor", "commands");
|
|
22592
|
+
fs43.mkdirSync(rulesDir, { recursive: true });
|
|
22593
|
+
fs43.mkdirSync(commandsDir, { recursive: true });
|
|
22594
|
+
if (fs43.existsSync(routerMdcSource)) {
|
|
22595
|
+
fs43.copyFileSync(routerMdcSource, routerMdcDest);
|
|
22018
22596
|
result.rulesCreated = true;
|
|
22019
22597
|
}
|
|
22020
|
-
if (
|
|
22021
|
-
const commandFiles =
|
|
22598
|
+
if (fs43.existsSync(cursorCommandsSource)) {
|
|
22599
|
+
const commandFiles = fs43.readdirSync(cursorCommandsSource).filter((f) => f.endsWith(".md"));
|
|
22022
22600
|
for (const file of commandFiles) {
|
|
22023
|
-
const src =
|
|
22024
|
-
const dest =
|
|
22025
|
-
|
|
22601
|
+
const src = path46.join(cursorCommandsSource, file);
|
|
22602
|
+
const dest = path46.join(commandsDir, file);
|
|
22603
|
+
fs43.copyFileSync(src, dest);
|
|
22026
22604
|
}
|
|
22027
22605
|
result.commandsCreated = commandFiles.length > 0;
|
|
22028
22606
|
}
|
|
@@ -22036,7 +22614,7 @@ async function installCursorProject(projectRoot) {
|
|
|
22036
22614
|
}
|
|
22037
22615
|
async function addCursorToGitignore(projectRoot) {
|
|
22038
22616
|
try {
|
|
22039
|
-
const gitignorePath =
|
|
22617
|
+
const gitignorePath = path46.join(projectRoot, ".gitignore");
|
|
22040
22618
|
const entriesToAdd = [
|
|
22041
22619
|
"# prjct Cursor routers (regenerated per-developer)",
|
|
22042
22620
|
".cursor/rules/prjct.mdc",
|
|
@@ -22051,7 +22629,7 @@ async function addCursorToGitignore(projectRoot) {
|
|
|
22051
22629
|
let content = "";
|
|
22052
22630
|
let fileExists2 = false;
|
|
22053
22631
|
try {
|
|
22054
|
-
content =
|
|
22632
|
+
content = fs43.readFileSync(gitignorePath, "utf-8");
|
|
22055
22633
|
fileExists2 = true;
|
|
22056
22634
|
} catch (error) {
|
|
22057
22635
|
if (!isNotFoundError(error)) {
|
|
@@ -22066,7 +22644,7 @@ async function addCursorToGitignore(projectRoot) {
|
|
|
22066
22644
|
${entriesToAdd.join("\n")}
|
|
22067
22645
|
` : `${entriesToAdd.join("\n")}
|
|
22068
22646
|
`;
|
|
22069
|
-
|
|
22647
|
+
fs43.writeFileSync(gitignorePath, newContent, "utf-8");
|
|
22070
22648
|
return true;
|
|
22071
22649
|
} catch (error) {
|
|
22072
22650
|
console.error(`Gitignore update warning: ${error.message}`);
|
|
@@ -22074,12 +22652,12 @@ ${entriesToAdd.join("\n")}
|
|
|
22074
22652
|
}
|
|
22075
22653
|
}
|
|
22076
22654
|
function hasCursorProject(projectRoot) {
|
|
22077
|
-
return
|
|
22655
|
+
return fs43.existsSync(path46.join(projectRoot, ".cursor"));
|
|
22078
22656
|
}
|
|
22079
22657
|
function needsCursorRegeneration(projectRoot) {
|
|
22080
|
-
const cursorDir =
|
|
22081
|
-
const routerPath =
|
|
22082
|
-
return
|
|
22658
|
+
const cursorDir = path46.join(projectRoot, ".cursor");
|
|
22659
|
+
const routerPath = path46.join(cursorDir, "rules", "prjct.mdc");
|
|
22660
|
+
return fs43.existsSync(cursorDir) && !fs43.existsSync(routerPath);
|
|
22083
22661
|
}
|
|
22084
22662
|
async function installWindsurfProject(projectRoot) {
|
|
22085
22663
|
const result = {
|
|
@@ -22089,29 +22667,29 @@ async function installWindsurfProject(projectRoot) {
|
|
|
22089
22667
|
gitignoreUpdated: false
|
|
22090
22668
|
};
|
|
22091
22669
|
try {
|
|
22092
|
-
const windsurfDir =
|
|
22093
|
-
const rulesDir =
|
|
22094
|
-
const workflowsDir =
|
|
22095
|
-
const routerDest =
|
|
22096
|
-
const routerSource =
|
|
22097
|
-
const windsurfWorkflowsSource =
|
|
22670
|
+
const windsurfDir = path46.join(projectRoot, ".windsurf");
|
|
22671
|
+
const rulesDir = path46.join(windsurfDir, "rules");
|
|
22672
|
+
const workflowsDir = path46.join(windsurfDir, "workflows");
|
|
22673
|
+
const routerDest = path46.join(rulesDir, "prjct.md");
|
|
22674
|
+
const routerSource = path46.join(getPackageRoot(), "templates", "windsurf", "router.md");
|
|
22675
|
+
const windsurfWorkflowsSource = path46.join(
|
|
22098
22676
|
getPackageRoot(),
|
|
22099
22677
|
"templates",
|
|
22100
22678
|
"windsurf",
|
|
22101
22679
|
"workflows"
|
|
22102
22680
|
);
|
|
22103
|
-
|
|
22104
|
-
|
|
22105
|
-
if (
|
|
22106
|
-
|
|
22681
|
+
fs43.mkdirSync(rulesDir, { recursive: true });
|
|
22682
|
+
fs43.mkdirSync(workflowsDir, { recursive: true });
|
|
22683
|
+
if (fs43.existsSync(routerSource)) {
|
|
22684
|
+
fs43.copyFileSync(routerSource, routerDest);
|
|
22107
22685
|
result.rulesCreated = true;
|
|
22108
22686
|
}
|
|
22109
|
-
if (
|
|
22110
|
-
const workflowFiles =
|
|
22687
|
+
if (fs43.existsSync(windsurfWorkflowsSource)) {
|
|
22688
|
+
const workflowFiles = fs43.readdirSync(windsurfWorkflowsSource).filter((f) => f.endsWith(".md"));
|
|
22111
22689
|
for (const file of workflowFiles) {
|
|
22112
|
-
const src =
|
|
22113
|
-
const dest =
|
|
22114
|
-
|
|
22690
|
+
const src = path46.join(windsurfWorkflowsSource, file);
|
|
22691
|
+
const dest = path46.join(workflowsDir, file);
|
|
22692
|
+
fs43.copyFileSync(src, dest);
|
|
22115
22693
|
}
|
|
22116
22694
|
result.workflowsCreated = workflowFiles.length > 0;
|
|
22117
22695
|
}
|
|
@@ -22125,7 +22703,7 @@ async function installWindsurfProject(projectRoot) {
|
|
|
22125
22703
|
}
|
|
22126
22704
|
async function addWindsurfToGitignore(projectRoot) {
|
|
22127
22705
|
try {
|
|
22128
|
-
const gitignorePath =
|
|
22706
|
+
const gitignorePath = path46.join(projectRoot, ".gitignore");
|
|
22129
22707
|
const entriesToAdd = [
|
|
22130
22708
|
"# prjct Windsurf routers (regenerated per-developer)",
|
|
22131
22709
|
".windsurf/rules/prjct.md",
|
|
@@ -22140,7 +22718,7 @@ async function addWindsurfToGitignore(projectRoot) {
|
|
|
22140
22718
|
let content = "";
|
|
22141
22719
|
let fileExists2 = false;
|
|
22142
22720
|
try {
|
|
22143
|
-
content =
|
|
22721
|
+
content = fs43.readFileSync(gitignorePath, "utf-8");
|
|
22144
22722
|
fileExists2 = true;
|
|
22145
22723
|
} catch (error) {
|
|
22146
22724
|
if (!isNotFoundError(error)) {
|
|
@@ -22155,7 +22733,7 @@ async function addWindsurfToGitignore(projectRoot) {
|
|
|
22155
22733
|
${entriesToAdd.join("\n")}
|
|
22156
22734
|
` : `${entriesToAdd.join("\n")}
|
|
22157
22735
|
`;
|
|
22158
|
-
|
|
22736
|
+
fs43.writeFileSync(gitignorePath, newContent, "utf-8");
|
|
22159
22737
|
return true;
|
|
22160
22738
|
} catch (error) {
|
|
22161
22739
|
console.error(`Gitignore update warning: ${error.message}`);
|
|
@@ -22163,32 +22741,32 @@ ${entriesToAdd.join("\n")}
|
|
|
22163
22741
|
}
|
|
22164
22742
|
}
|
|
22165
22743
|
function hasWindsurfProject(projectRoot) {
|
|
22166
|
-
return
|
|
22744
|
+
return fs43.existsSync(path46.join(projectRoot, ".windsurf"));
|
|
22167
22745
|
}
|
|
22168
22746
|
function needsWindsurfRegeneration(projectRoot) {
|
|
22169
|
-
const windsurfDir =
|
|
22170
|
-
const routerPath =
|
|
22171
|
-
return
|
|
22747
|
+
const windsurfDir = path46.join(projectRoot, ".windsurf");
|
|
22748
|
+
const routerPath = path46.join(windsurfDir, "rules", "prjct.md");
|
|
22749
|
+
return fs43.existsSync(windsurfDir) && !fs43.existsSync(routerPath);
|
|
22172
22750
|
}
|
|
22173
22751
|
async function migrateProjectsCliVersion() {
|
|
22174
22752
|
try {
|
|
22175
|
-
const projectsDir =
|
|
22176
|
-
if (!
|
|
22753
|
+
const projectsDir = path46.join(os13.homedir(), ".prjct-cli", "projects");
|
|
22754
|
+
if (!fs43.existsSync(projectsDir)) {
|
|
22177
22755
|
return;
|
|
22178
22756
|
}
|
|
22179
|
-
const projectDirs =
|
|
22757
|
+
const projectDirs = fs43.readdirSync(projectsDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
22180
22758
|
let migrated = 0;
|
|
22181
22759
|
for (const projectId of projectDirs) {
|
|
22182
|
-
const projectJsonPath =
|
|
22183
|
-
if (!
|
|
22760
|
+
const projectJsonPath = path46.join(projectsDir, projectId, "project.json");
|
|
22761
|
+
if (!fs43.existsSync(projectJsonPath)) {
|
|
22184
22762
|
continue;
|
|
22185
22763
|
}
|
|
22186
22764
|
try {
|
|
22187
|
-
const content =
|
|
22765
|
+
const content = fs43.readFileSync(projectJsonPath, "utf8");
|
|
22188
22766
|
const project = JSON.parse(content);
|
|
22189
22767
|
if (project.cliVersion !== VERSION) {
|
|
22190
22768
|
project.cliVersion = VERSION;
|
|
22191
|
-
|
|
22769
|
+
fs43.writeFileSync(projectJsonPath, JSON.stringify(project, null, 2));
|
|
22192
22770
|
migrated++;
|
|
22193
22771
|
}
|
|
22194
22772
|
} catch (error) {
|
|
@@ -22208,9 +22786,9 @@ async function migrateProjectsCliVersion() {
|
|
|
22208
22786
|
}
|
|
22209
22787
|
function ensureStatusLineSettings(settingsPath, statusLinePath) {
|
|
22210
22788
|
let settings = {};
|
|
22211
|
-
if (
|
|
22789
|
+
if (fs43.existsSync(settingsPath)) {
|
|
22212
22790
|
try {
|
|
22213
|
-
settings = JSON.parse(
|
|
22791
|
+
settings = JSON.parse(fs43.readFileSync(settingsPath, "utf8"));
|
|
22214
22792
|
} catch (error) {
|
|
22215
22793
|
if (!(error instanceof SyntaxError)) {
|
|
22216
22794
|
throw error;
|
|
@@ -22218,42 +22796,42 @@ function ensureStatusLineSettings(settingsPath, statusLinePath) {
|
|
|
22218
22796
|
}
|
|
22219
22797
|
}
|
|
22220
22798
|
settings.statusLine = { type: "command", command: statusLinePath };
|
|
22221
|
-
|
|
22799
|
+
fs43.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
22222
22800
|
}
|
|
22223
22801
|
async function installStatusLine() {
|
|
22224
22802
|
try {
|
|
22225
|
-
const claudeDir =
|
|
22226
|
-
const settingsPath =
|
|
22227
|
-
const claudeStatusLinePath =
|
|
22228
|
-
const prjctStatusLineDir =
|
|
22229
|
-
const prjctStatusLinePath =
|
|
22230
|
-
const prjctThemesDir =
|
|
22231
|
-
const prjctLibDir =
|
|
22232
|
-
const prjctComponentsDir =
|
|
22233
|
-
const prjctConfigPath =
|
|
22234
|
-
const assetsDir =
|
|
22235
|
-
const sourceScript =
|
|
22236
|
-
const sourceThemeDir =
|
|
22237
|
-
const sourceLibDir =
|
|
22238
|
-
const sourceComponentsDir =
|
|
22239
|
-
const sourceConfigPath =
|
|
22240
|
-
if (!
|
|
22241
|
-
|
|
22803
|
+
const claudeDir = path46.join(os13.homedir(), ".claude");
|
|
22804
|
+
const settingsPath = path46.join(claudeDir, "settings.json");
|
|
22805
|
+
const claudeStatusLinePath = path46.join(claudeDir, "prjct-statusline.sh");
|
|
22806
|
+
const prjctStatusLineDir = path46.join(os13.homedir(), ".prjct-cli", "statusline");
|
|
22807
|
+
const prjctStatusLinePath = path46.join(prjctStatusLineDir, "statusline.sh");
|
|
22808
|
+
const prjctThemesDir = path46.join(prjctStatusLineDir, "themes");
|
|
22809
|
+
const prjctLibDir = path46.join(prjctStatusLineDir, "lib");
|
|
22810
|
+
const prjctComponentsDir = path46.join(prjctStatusLineDir, "components");
|
|
22811
|
+
const prjctConfigPath = path46.join(prjctStatusLineDir, "config.json");
|
|
22812
|
+
const assetsDir = path46.join(getPackageRoot(), "assets", "statusline");
|
|
22813
|
+
const sourceScript = path46.join(assetsDir, "statusline.sh");
|
|
22814
|
+
const sourceThemeDir = path46.join(assetsDir, "themes");
|
|
22815
|
+
const sourceLibDir = path46.join(assetsDir, "lib");
|
|
22816
|
+
const sourceComponentsDir = path46.join(assetsDir, "components");
|
|
22817
|
+
const sourceConfigPath = path46.join(assetsDir, "default-config.json");
|
|
22818
|
+
if (!fs43.existsSync(claudeDir)) {
|
|
22819
|
+
fs43.mkdirSync(claudeDir, { recursive: true });
|
|
22242
22820
|
}
|
|
22243
|
-
if (!
|
|
22244
|
-
|
|
22821
|
+
if (!fs43.existsSync(prjctStatusLineDir)) {
|
|
22822
|
+
fs43.mkdirSync(prjctStatusLineDir, { recursive: true });
|
|
22245
22823
|
}
|
|
22246
|
-
if (!
|
|
22247
|
-
|
|
22824
|
+
if (!fs43.existsSync(prjctThemesDir)) {
|
|
22825
|
+
fs43.mkdirSync(prjctThemesDir, { recursive: true });
|
|
22248
22826
|
}
|
|
22249
|
-
if (!
|
|
22250
|
-
|
|
22827
|
+
if (!fs43.existsSync(prjctLibDir)) {
|
|
22828
|
+
fs43.mkdirSync(prjctLibDir, { recursive: true });
|
|
22251
22829
|
}
|
|
22252
|
-
if (!
|
|
22253
|
-
|
|
22830
|
+
if (!fs43.existsSync(prjctComponentsDir)) {
|
|
22831
|
+
fs43.mkdirSync(prjctComponentsDir, { recursive: true });
|
|
22254
22832
|
}
|
|
22255
|
-
if (
|
|
22256
|
-
const existingContent =
|
|
22833
|
+
if (fs43.existsSync(prjctStatusLinePath)) {
|
|
22834
|
+
const existingContent = fs43.readFileSync(prjctStatusLinePath, "utf8");
|
|
22257
22835
|
if (existingContent.includes("CLI_VERSION=")) {
|
|
22258
22836
|
const versionMatch = existingContent.match(/CLI_VERSION="([^"]*)"/);
|
|
22259
22837
|
if (versionMatch && versionMatch[1] !== VERSION) {
|
|
@@ -22261,7 +22839,7 @@ async function installStatusLine() {
|
|
|
22261
22839
|
/CLI_VERSION="[^"]*"/,
|
|
22262
22840
|
`CLI_VERSION="${VERSION}"`
|
|
22263
22841
|
);
|
|
22264
|
-
|
|
22842
|
+
fs43.writeFileSync(prjctStatusLinePath, updatedContent, { mode: 493 });
|
|
22265
22843
|
}
|
|
22266
22844
|
installStatusLineModules(sourceLibDir, prjctLibDir);
|
|
22267
22845
|
installStatusLineModules(sourceComponentsDir, prjctComponentsDir);
|
|
@@ -22270,22 +22848,22 @@ async function installStatusLine() {
|
|
|
22270
22848
|
return;
|
|
22271
22849
|
}
|
|
22272
22850
|
}
|
|
22273
|
-
if (
|
|
22274
|
-
let scriptContent =
|
|
22851
|
+
if (fs43.existsSync(sourceScript)) {
|
|
22852
|
+
let scriptContent = fs43.readFileSync(sourceScript, "utf8");
|
|
22275
22853
|
scriptContent = scriptContent.replace(/CLI_VERSION="[^"]*"/, `CLI_VERSION="${VERSION}"`);
|
|
22276
|
-
|
|
22854
|
+
fs43.writeFileSync(prjctStatusLinePath, scriptContent, { mode: 493 });
|
|
22277
22855
|
installStatusLineModules(sourceLibDir, prjctLibDir);
|
|
22278
22856
|
installStatusLineModules(sourceComponentsDir, prjctComponentsDir);
|
|
22279
|
-
if (
|
|
22280
|
-
const themes =
|
|
22857
|
+
if (fs43.existsSync(sourceThemeDir)) {
|
|
22858
|
+
const themes = fs43.readdirSync(sourceThemeDir);
|
|
22281
22859
|
for (const theme of themes) {
|
|
22282
|
-
const src =
|
|
22283
|
-
const dest =
|
|
22284
|
-
|
|
22860
|
+
const src = path46.join(sourceThemeDir, theme);
|
|
22861
|
+
const dest = path46.join(prjctThemesDir, theme);
|
|
22862
|
+
fs43.copyFileSync(src, dest);
|
|
22285
22863
|
}
|
|
22286
22864
|
}
|
|
22287
|
-
if (!
|
|
22288
|
-
|
|
22865
|
+
if (!fs43.existsSync(prjctConfigPath) && fs43.existsSync(sourceConfigPath)) {
|
|
22866
|
+
fs43.copyFileSync(sourceConfigPath, prjctConfigPath);
|
|
22289
22867
|
}
|
|
22290
22868
|
} else {
|
|
22291
22869
|
const scriptContent = `#!/bin/bash
|
|
@@ -22320,7 +22898,7 @@ if [ -f "$CONFIG" ]; then
|
|
|
22320
22898
|
fi
|
|
22321
22899
|
echo "prjct"
|
|
22322
22900
|
`;
|
|
22323
|
-
|
|
22901
|
+
fs43.writeFileSync(prjctStatusLinePath, scriptContent, { mode: 493 });
|
|
22324
22902
|
}
|
|
22325
22903
|
ensureStatusLineSymlink(claudeStatusLinePath, prjctStatusLinePath);
|
|
22326
22904
|
ensureStatusLineSettings(settingsPath, claudeStatusLinePath);
|
|
@@ -22332,10 +22910,10 @@ echo "prjct"
|
|
|
22332
22910
|
}
|
|
22333
22911
|
async function installContext7MCP() {
|
|
22334
22912
|
try {
|
|
22335
|
-
const claudeDir =
|
|
22336
|
-
const mcpConfigPath =
|
|
22337
|
-
if (!
|
|
22338
|
-
|
|
22913
|
+
const claudeDir = path46.join(os13.homedir(), ".claude");
|
|
22914
|
+
const mcpConfigPath = path46.join(claudeDir, "mcp.json");
|
|
22915
|
+
if (!fs43.existsSync(claudeDir)) {
|
|
22916
|
+
fs43.mkdirSync(claudeDir, { recursive: true });
|
|
22339
22917
|
}
|
|
22340
22918
|
const context7Config = {
|
|
22341
22919
|
mcpServers: {
|
|
@@ -22345,54 +22923,54 @@ async function installContext7MCP() {
|
|
|
22345
22923
|
}
|
|
22346
22924
|
}
|
|
22347
22925
|
};
|
|
22348
|
-
if (
|
|
22349
|
-
const existingContent =
|
|
22926
|
+
if (fs43.existsSync(mcpConfigPath)) {
|
|
22927
|
+
const existingContent = fs43.readFileSync(mcpConfigPath, "utf-8");
|
|
22350
22928
|
const existingConfig = JSON.parse(existingContent);
|
|
22351
22929
|
if (existingConfig.mcpServers?.context7) {
|
|
22352
22930
|
return;
|
|
22353
22931
|
}
|
|
22354
22932
|
existingConfig.mcpServers = existingConfig.mcpServers || {};
|
|
22355
22933
|
existingConfig.mcpServers.context7 = context7Config.mcpServers.context7;
|
|
22356
|
-
|
|
22934
|
+
fs43.writeFileSync(mcpConfigPath, JSON.stringify(existingConfig, null, 2), "utf-8");
|
|
22357
22935
|
} else {
|
|
22358
|
-
|
|
22936
|
+
fs43.writeFileSync(mcpConfigPath, JSON.stringify(context7Config, null, 2), "utf-8");
|
|
22359
22937
|
}
|
|
22360
22938
|
} catch (error) {
|
|
22361
22939
|
console.error(`Context7 MCP setup warning: ${error.message}`);
|
|
22362
22940
|
}
|
|
22363
22941
|
}
|
|
22364
22942
|
function installStatusLineModules(sourceDir, destDir) {
|
|
22365
|
-
if (!
|
|
22943
|
+
if (!fs43.existsSync(sourceDir)) {
|
|
22366
22944
|
return;
|
|
22367
22945
|
}
|
|
22368
|
-
const files =
|
|
22946
|
+
const files = fs43.readdirSync(sourceDir);
|
|
22369
22947
|
for (const file of files) {
|
|
22370
22948
|
if (file.endsWith(".sh")) {
|
|
22371
|
-
const src =
|
|
22372
|
-
const dest =
|
|
22373
|
-
|
|
22374
|
-
|
|
22949
|
+
const src = path46.join(sourceDir, file);
|
|
22950
|
+
const dest = path46.join(destDir, file);
|
|
22951
|
+
fs43.copyFileSync(src, dest);
|
|
22952
|
+
fs43.chmodSync(dest, 493);
|
|
22375
22953
|
}
|
|
22376
22954
|
}
|
|
22377
22955
|
}
|
|
22378
22956
|
function ensureStatusLineSymlink(linkPath, targetPath) {
|
|
22379
22957
|
try {
|
|
22380
|
-
if (
|
|
22381
|
-
const stats =
|
|
22958
|
+
if (fs43.existsSync(linkPath)) {
|
|
22959
|
+
const stats = fs43.lstatSync(linkPath);
|
|
22382
22960
|
if (stats.isSymbolicLink()) {
|
|
22383
|
-
const existingTarget =
|
|
22961
|
+
const existingTarget = fs43.readlinkSync(linkPath);
|
|
22384
22962
|
if (existingTarget === targetPath) {
|
|
22385
22963
|
return;
|
|
22386
22964
|
}
|
|
22387
22965
|
}
|
|
22388
|
-
|
|
22966
|
+
fs43.unlinkSync(linkPath);
|
|
22389
22967
|
}
|
|
22390
|
-
|
|
22968
|
+
fs43.symlinkSync(targetPath, linkPath);
|
|
22391
22969
|
} catch (_error) {
|
|
22392
22970
|
try {
|
|
22393
|
-
if (
|
|
22394
|
-
|
|
22395
|
-
|
|
22971
|
+
if (fs43.existsSync(targetPath)) {
|
|
22972
|
+
fs43.copyFileSync(targetPath, linkPath);
|
|
22973
|
+
fs43.chmodSync(linkPath, 493);
|
|
22396
22974
|
}
|
|
22397
22975
|
} catch (copyError) {
|
|
22398
22976
|
if (!isNotFoundError(copyError)) {
|
|
@@ -22807,11 +23385,12 @@ var init_registry2 = __esm({
|
|
|
22807
23385
|
});
|
|
22808
23386
|
|
|
22809
23387
|
// core/commands/analytics.ts
|
|
22810
|
-
import
|
|
23388
|
+
import path47 from "node:path";
|
|
22811
23389
|
var AnalyticsCommands;
|
|
22812
23390
|
var init_analytics = __esm({
|
|
22813
23391
|
"core/commands/analytics.ts"() {
|
|
22814
23392
|
"use strict";
|
|
23393
|
+
init_services();
|
|
22815
23394
|
init_storage2();
|
|
22816
23395
|
init_base();
|
|
22817
23396
|
init_registry2();
|
|
@@ -22832,7 +23411,7 @@ var init_analytics = __esm({
|
|
|
22832
23411
|
output_default.failWithHint("NO_PROJECT_ID");
|
|
22833
23412
|
return { success: false, error: "No project ID found" };
|
|
22834
23413
|
}
|
|
22835
|
-
const projectName =
|
|
23414
|
+
const projectName = path47.basename(projectPath);
|
|
22836
23415
|
const currentTask = await stateStorage.getCurrentTask(projectId);
|
|
22837
23416
|
const queueTasks = await queueStorage.getActiveTasks(projectId);
|
|
22838
23417
|
const shipped = await shippedStorage.getRecent(projectId, 5);
|
|
@@ -22902,6 +23481,13 @@ var init_analytics = __esm({
|
|
|
22902
23481
|
\u{1F4CA} DASHBOARD - ${projectName}
|
|
22903
23482
|
`);
|
|
22904
23483
|
console.log("\u2550".repeat(50));
|
|
23484
|
+
const checker = createStalenessChecker(projectPath);
|
|
23485
|
+
const stalenessStatus = await checker.check(projectId);
|
|
23486
|
+
const stalenessWarning = checker.getWarning(stalenessStatus);
|
|
23487
|
+
if (stalenessWarning) {
|
|
23488
|
+
console.log(`
|
|
23489
|
+
${stalenessWarning}`);
|
|
23490
|
+
}
|
|
22905
23491
|
console.log("\n\u{1F3AF} CURRENT FOCUS");
|
|
22906
23492
|
if (currentTask) {
|
|
22907
23493
|
console.log(` ${currentTask.description}`);
|
|
@@ -23077,8 +23663,8 @@ ${"\u2550".repeat(50)}
|
|
|
23077
23663
|
});
|
|
23078
23664
|
|
|
23079
23665
|
// core/commands/context.ts
|
|
23080
|
-
import
|
|
23081
|
-
import
|
|
23666
|
+
import fs44 from "node:fs/promises";
|
|
23667
|
+
import path48 from "node:path";
|
|
23082
23668
|
var ContextCommands, contextCommands;
|
|
23083
23669
|
var init_context = __esm({
|
|
23084
23670
|
"core/commands/context.ts"() {
|
|
@@ -23204,8 +23790,8 @@ var init_context = __esm({
|
|
|
23204
23790
|
*/
|
|
23205
23791
|
async loadRepoAnalysis(globalPath) {
|
|
23206
23792
|
try {
|
|
23207
|
-
const analysisPath =
|
|
23208
|
-
const content = await
|
|
23793
|
+
const analysisPath = path48.join(globalPath, "analysis", "repo-analysis.json");
|
|
23794
|
+
const content = await fs44.readFile(analysisPath, "utf-8");
|
|
23209
23795
|
const data = JSON.parse(content);
|
|
23210
23796
|
return {
|
|
23211
23797
|
ecosystem: data.ecosystem || "unknown",
|
|
@@ -23224,7 +23810,7 @@ var init_context = __esm({
|
|
|
23224
23810
|
});
|
|
23225
23811
|
|
|
23226
23812
|
// core/commands/cleanup.ts
|
|
23227
|
-
import
|
|
23813
|
+
import path49 from "node:path";
|
|
23228
23814
|
async function cleanupMemory(projectPath) {
|
|
23229
23815
|
const projectId = await config_manager_default.getProjectId(projectPath);
|
|
23230
23816
|
const results = { rotated: [], totalSize: 0, freedSpace: 0 };
|
|
@@ -23240,7 +23826,7 @@ async function cleanupMemory(projectPath) {
|
|
|
23240
23826
|
results.totalSize += sizeMB;
|
|
23241
23827
|
const rotated = await jsonl_helper_default.rotateJsonLinesIfNeeded(filePath, 10);
|
|
23242
23828
|
if (rotated) {
|
|
23243
|
-
results.rotated.push(
|
|
23829
|
+
results.rotated.push(path49.basename(filePath));
|
|
23244
23830
|
results.freedSpace += sizeMB;
|
|
23245
23831
|
}
|
|
23246
23832
|
}
|
|
@@ -23347,7 +23933,7 @@ var init_cleanup = __esm({
|
|
|
23347
23933
|
});
|
|
23348
23934
|
|
|
23349
23935
|
// core/commands/design.ts
|
|
23350
|
-
import
|
|
23936
|
+
import path50 from "node:path";
|
|
23351
23937
|
async function design(target = null, options = {}, projectPath = process.cwd()) {
|
|
23352
23938
|
try {
|
|
23353
23939
|
const designType = options.type || "architecture";
|
|
@@ -23359,7 +23945,7 @@ async function design(target = null, options = {}, projectPath = process.cwd())
|
|
|
23359
23945
|
const designTarget = target || "system";
|
|
23360
23946
|
output_default.spin(`designing ${designType}...`);
|
|
23361
23947
|
const projectId = await config_manager_default.getProjectId(projectPath);
|
|
23362
|
-
const designsPath =
|
|
23948
|
+
const designsPath = path50.join(
|
|
23363
23949
|
path_manager_default.getGlobalProjectPath(projectId),
|
|
23364
23950
|
"planning",
|
|
23365
23951
|
"designs"
|
|
@@ -23399,7 +23985,7 @@ async function design(target = null, options = {}, projectPath = process.cwd())
|
|
|
23399
23985
|
break;
|
|
23400
23986
|
}
|
|
23401
23987
|
const designFileName = `${designType}-${designTarget.toLowerCase().replace(/\s+/g, "-")}.md`;
|
|
23402
|
-
const designFilePath =
|
|
23988
|
+
const designFilePath = path50.join(designsPath, designFileName);
|
|
23403
23989
|
await file_helper_exports.writeFile(designFilePath, designContent);
|
|
23404
23990
|
await memoryService.log(projectPath, "design_created", {
|
|
23405
23991
|
type: designType,
|
|
@@ -23423,7 +24009,7 @@ var init_design = __esm({
|
|
|
23423
24009
|
});
|
|
23424
24010
|
|
|
23425
24011
|
// core/commands/snapshots.ts
|
|
23426
|
-
import
|
|
24012
|
+
import path51 from "node:path";
|
|
23427
24013
|
async function recover(projectPath = process.cwd()) {
|
|
23428
24014
|
try {
|
|
23429
24015
|
const projectId = await config_manager_default.getProjectId(projectPath);
|
|
@@ -23475,7 +24061,7 @@ async function undo(projectPath = process.cwd()) {
|
|
|
23475
24061
|
output_default.failWithHint("NO_PROJECT_ID");
|
|
23476
24062
|
return { success: false, error: "No project ID found" };
|
|
23477
24063
|
}
|
|
23478
|
-
const snapshotsPath =
|
|
24064
|
+
const snapshotsPath = path51.join(path_manager_default.getGlobalProjectPath(projectId), "snapshots");
|
|
23479
24065
|
await file_helper_exports.ensureDir(snapshotsPath);
|
|
23480
24066
|
const { execSync: execSync7 } = await import("node:child_process");
|
|
23481
24067
|
try {
|
|
@@ -23493,7 +24079,7 @@ async function undo(projectPath = process.cwd()) {
|
|
|
23493
24079
|
cwd: projectPath,
|
|
23494
24080
|
encoding: "utf-8"
|
|
23495
24081
|
});
|
|
23496
|
-
const snapshotFile =
|
|
24082
|
+
const snapshotFile = path51.join(snapshotsPath, "history.json");
|
|
23497
24083
|
let history2 = { snapshots: [], current: -1 };
|
|
23498
24084
|
try {
|
|
23499
24085
|
const content = await file_helper_exports.readFile(snapshotFile);
|
|
@@ -23533,8 +24119,8 @@ async function redo(projectPath = process.cwd()) {
|
|
|
23533
24119
|
output_default.failWithHint("NO_PROJECT_ID");
|
|
23534
24120
|
return { success: false, error: "No project ID found" };
|
|
23535
24121
|
}
|
|
23536
|
-
const snapshotsPath =
|
|
23537
|
-
const snapshotFile =
|
|
24122
|
+
const snapshotsPath = path51.join(path_manager_default.getGlobalProjectPath(projectId), "snapshots");
|
|
24123
|
+
const snapshotFile = path51.join(snapshotsPath, "history.json");
|
|
23538
24124
|
let history2;
|
|
23539
24125
|
try {
|
|
23540
24126
|
const content = await file_helper_exports.readFile(snapshotFile);
|
|
@@ -23593,8 +24179,8 @@ async function history(projectPath = process.cwd()) {
|
|
|
23593
24179
|
output_default.failWithHint("NO_PROJECT_ID");
|
|
23594
24180
|
return { success: false, error: "No project ID found" };
|
|
23595
24181
|
}
|
|
23596
|
-
const snapshotsPath =
|
|
23597
|
-
const snapshotFile =
|
|
24182
|
+
const snapshotsPath = path51.join(path_manager_default.getGlobalProjectPath(projectId), "snapshots");
|
|
24183
|
+
const snapshotFile = path51.join(snapshotsPath, "history.json");
|
|
23598
24184
|
let snapshotHistory;
|
|
23599
24185
|
try {
|
|
23600
24186
|
const content = await file_helper_exports.readFile(snapshotFile);
|
|
@@ -23701,8 +24287,8 @@ var init_maintenance = __esm({
|
|
|
23701
24287
|
});
|
|
23702
24288
|
|
|
23703
24289
|
// core/commands/setup.ts
|
|
23704
|
-
import
|
|
23705
|
-
import
|
|
24290
|
+
import fs45 from "node:fs";
|
|
24291
|
+
import path52 from "node:path";
|
|
23706
24292
|
import chalk11 from "chalk";
|
|
23707
24293
|
var SetupCommands;
|
|
23708
24294
|
var init_setup2 = __esm({
|
|
@@ -23829,7 +24415,7 @@ Please install it first:
|
|
|
23829
24415
|
try {
|
|
23830
24416
|
const claudeDir = path_manager_default.getClaudeDir();
|
|
23831
24417
|
const settingsPath = path_manager_default.getClaudeSettingsPath();
|
|
23832
|
-
const statusLinePath =
|
|
24418
|
+
const statusLinePath = path52.join(claudeDir, "prjct-statusline.sh");
|
|
23833
24419
|
const scriptContent = `#!/bin/bash
|
|
23834
24420
|
# prjct Status Line for Claude Code
|
|
23835
24421
|
# Shows version update notifications and current task
|
|
@@ -23887,11 +24473,11 @@ fi
|
|
|
23887
24473
|
# Default: show prjct branding
|
|
23888
24474
|
echo "\u26A1 prjct"
|
|
23889
24475
|
`;
|
|
23890
|
-
|
|
24476
|
+
fs45.writeFileSync(statusLinePath, scriptContent, { mode: 493 });
|
|
23891
24477
|
let settings = {};
|
|
23892
|
-
if (
|
|
24478
|
+
if (fs45.existsSync(settingsPath)) {
|
|
23893
24479
|
try {
|
|
23894
|
-
settings = JSON.parse(
|
|
24480
|
+
settings = JSON.parse(fs45.readFileSync(settingsPath, "utf8"));
|
|
23895
24481
|
} catch (_error) {
|
|
23896
24482
|
}
|
|
23897
24483
|
}
|
|
@@ -23899,7 +24485,7 @@ echo "\u26A1 prjct"
|
|
|
23899
24485
|
type: "command",
|
|
23900
24486
|
command: statusLinePath
|
|
23901
24487
|
};
|
|
23902
|
-
|
|
24488
|
+
fs45.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
23903
24489
|
return { success: true };
|
|
23904
24490
|
} catch (error) {
|
|
23905
24491
|
return { success: false, error: error.message };
|
|
@@ -23955,18 +24541,18 @@ echo "\u26A1 prjct"
|
|
|
23955
24541
|
});
|
|
23956
24542
|
|
|
23957
24543
|
// core/utils/project-commands.ts
|
|
23958
|
-
import
|
|
24544
|
+
import path53 from "node:path";
|
|
23959
24545
|
async function detectPackageManager(projectPath, pkg) {
|
|
23960
24546
|
const declared = pkg?.packageManager?.trim().toLowerCase();
|
|
23961
24547
|
if (declared?.startsWith("pnpm@")) return "pnpm";
|
|
23962
24548
|
if (declared?.startsWith("yarn@")) return "yarn";
|
|
23963
24549
|
if (declared?.startsWith("bun@")) return "bun";
|
|
23964
24550
|
if (declared?.startsWith("npm@")) return "npm";
|
|
23965
|
-
if (await fileExists(
|
|
23966
|
-
if (await fileExists(
|
|
23967
|
-
if (await fileExists(
|
|
23968
|
-
if (await fileExists(
|
|
23969
|
-
if (await fileExists(
|
|
24551
|
+
if (await fileExists(path53.join(projectPath, "pnpm-lock.yaml"))) return "pnpm";
|
|
24552
|
+
if (await fileExists(path53.join(projectPath, "yarn.lock"))) return "yarn";
|
|
24553
|
+
if (await fileExists(path53.join(projectPath, "bun.lockb"))) return "bun";
|
|
24554
|
+
if (await fileExists(path53.join(projectPath, "bun.lock"))) return "bun";
|
|
24555
|
+
if (await fileExists(path53.join(projectPath, "package-lock.json"))) return "npm";
|
|
23970
24556
|
return "npm";
|
|
23971
24557
|
}
|
|
23972
24558
|
function pmRun(pm, scriptName) {
|
|
@@ -23982,7 +24568,7 @@ function pmTest(pm) {
|
|
|
23982
24568
|
return "npm test";
|
|
23983
24569
|
}
|
|
23984
24570
|
async function detectProjectCommands(projectPath) {
|
|
23985
|
-
const pkgPath =
|
|
24571
|
+
const pkgPath = path53.join(projectPath, "package.json");
|
|
23986
24572
|
const pkg = await readJson(pkgPath, null);
|
|
23987
24573
|
if (pkg) {
|
|
23988
24574
|
const pm = await detectPackageManager(projectPath, pkg);
|
|
@@ -23999,27 +24585,27 @@ async function detectProjectCommands(projectPath) {
|
|
|
23999
24585
|
}
|
|
24000
24586
|
return result;
|
|
24001
24587
|
}
|
|
24002
|
-
if (await fileExists(
|
|
24588
|
+
if (await fileExists(path53.join(projectPath, "pytest.ini"))) {
|
|
24003
24589
|
return { stack: "python", test: { tool: "pytest", command: "pytest" } };
|
|
24004
24590
|
}
|
|
24005
|
-
const pyproject = await readFile(
|
|
24591
|
+
const pyproject = await readFile(path53.join(projectPath, "pyproject.toml"), "");
|
|
24006
24592
|
if (pyproject.includes("[tool.pytest") || pyproject.includes("pytest")) {
|
|
24007
24593
|
return { stack: "python", test: { tool: "pytest", command: "pytest" } };
|
|
24008
24594
|
}
|
|
24009
|
-
if (await fileExists(
|
|
24595
|
+
if (await fileExists(path53.join(projectPath, "Cargo.toml"))) {
|
|
24010
24596
|
return { stack: "rust", test: { tool: "cargo", command: "cargo test" } };
|
|
24011
24597
|
}
|
|
24012
|
-
if (await fileExists(
|
|
24598
|
+
if (await fileExists(path53.join(projectPath, "go.mod"))) {
|
|
24013
24599
|
return { stack: "go", test: { tool: "go", command: "go test ./..." } };
|
|
24014
24600
|
}
|
|
24015
24601
|
const files = await listFiles(projectPath);
|
|
24016
24602
|
if (files.some((f) => f.endsWith(".sln") || f.endsWith(".csproj") || f.endsWith(".fsproj"))) {
|
|
24017
24603
|
return { stack: "dotnet", test: { tool: "dotnet", command: "dotnet test" } };
|
|
24018
24604
|
}
|
|
24019
|
-
if (await fileExists(
|
|
24605
|
+
if (await fileExists(path53.join(projectPath, "pom.xml"))) {
|
|
24020
24606
|
return { stack: "java", test: { tool: "maven", command: "mvn test" } };
|
|
24021
24607
|
}
|
|
24022
|
-
if (await fileExists(
|
|
24608
|
+
if (await fileExists(path53.join(projectPath, "gradlew")) && (await fileExists(path53.join(projectPath, "build.gradle")) || await fileExists(path53.join(projectPath, "build.gradle.kts")))) {
|
|
24023
24609
|
return { stack: "java", test: { tool: "gradle", command: "./gradlew test" } };
|
|
24024
24610
|
}
|
|
24025
24611
|
return { stack: "unknown" };
|
|
@@ -24036,8 +24622,8 @@ var init_project_commands = __esm({
|
|
|
24036
24622
|
});
|
|
24037
24623
|
|
|
24038
24624
|
// core/workflow/workflow-preferences.ts
|
|
24039
|
-
import { exec as
|
|
24040
|
-
import { promisify as
|
|
24625
|
+
import { exec as exec12 } from "node:child_process";
|
|
24626
|
+
import { promisify as promisify12 } from "node:util";
|
|
24041
24627
|
function prefKey(hook, command) {
|
|
24042
24628
|
return `workflow:${hook}_${command}`;
|
|
24043
24629
|
}
|
|
@@ -24108,7 +24694,7 @@ async function runWorkflowHooks(projectId, phase, command, options = {}) {
|
|
|
24108
24694
|
${DIM5}Running ${phase}-${command}: ${action}${RESET4}`);
|
|
24109
24695
|
try {
|
|
24110
24696
|
const startTime = Date.now();
|
|
24111
|
-
await
|
|
24697
|
+
await execAsync7(action, {
|
|
24112
24698
|
timeout: 6e4,
|
|
24113
24699
|
cwd: options.projectPath || process.cwd(),
|
|
24114
24700
|
env: { ...process.env }
|
|
@@ -24172,12 +24758,12 @@ Set one: "p. workflow antes de ship corre los tests"`;
|
|
|
24172
24758
|
lines.push(`${DIM5}Remove: "p. workflow quita el hook de ship"${RESET4}`);
|
|
24173
24759
|
return lines.join("\n");
|
|
24174
24760
|
}
|
|
24175
|
-
var
|
|
24761
|
+
var execAsync7, DIM5, GREEN5, RED, YELLOW5, RESET4, sessionPreferences, oncePreferences;
|
|
24176
24762
|
var init_workflow_preferences = __esm({
|
|
24177
24763
|
"core/workflow/workflow-preferences.ts"() {
|
|
24178
24764
|
"use strict";
|
|
24179
24765
|
init_memory_system();
|
|
24180
|
-
|
|
24766
|
+
execAsync7 = promisify12(exec12);
|
|
24181
24767
|
DIM5 = "\x1B[2m";
|
|
24182
24768
|
GREEN5 = "\x1B[32m";
|
|
24183
24769
|
RED = "\x1B[31m";
|
|
@@ -24196,7 +24782,7 @@ var init_workflow_preferences = __esm({
|
|
|
24196
24782
|
});
|
|
24197
24783
|
|
|
24198
24784
|
// core/commands/shipping.ts
|
|
24199
|
-
import
|
|
24785
|
+
import path54 from "node:path";
|
|
24200
24786
|
var ShippingCommands;
|
|
24201
24787
|
var init_shipping = __esm({
|
|
24202
24788
|
"core/commands/shipping.ts"() {
|
|
@@ -24342,7 +24928,7 @@ ${result.stderr}`.trim();
|
|
|
24342
24928
|
*/
|
|
24343
24929
|
async _bumpVersion(projectPath) {
|
|
24344
24930
|
try {
|
|
24345
|
-
const pkgPath =
|
|
24931
|
+
const pkgPath = path54.join(projectPath, "package.json");
|
|
24346
24932
|
const pkg = await file_helper_exports.readJson(pkgPath, { version: "0.0.0" });
|
|
24347
24933
|
const oldVersion = pkg?.version || "0.0.0";
|
|
24348
24934
|
const [major, minor, patch] = oldVersion.split(".").map(Number);
|
|
@@ -24364,7 +24950,7 @@ ${result.stderr}`.trim();
|
|
|
24364
24950
|
*/
|
|
24365
24951
|
async _updateChangelog(feature, version, projectPath) {
|
|
24366
24952
|
try {
|
|
24367
|
-
const changelogPath =
|
|
24953
|
+
const changelogPath = path54.join(projectPath, "CHANGELOG.md");
|
|
24368
24954
|
const changelog = await file_helper_exports.readFile(changelogPath, "# Changelog\n\n");
|
|
24369
24955
|
const entry = `## [${version}] - ${date_helper_default.formatDate(/* @__PURE__ */ new Date())}
|
|
24370
24956
|
|
|
@@ -24463,14 +25049,14 @@ var init_cache2 = __esm({
|
|
|
24463
25049
|
});
|
|
24464
25050
|
|
|
24465
25051
|
// core/utils/keychain.ts
|
|
24466
|
-
import { exec as
|
|
24467
|
-
import { promisify as
|
|
25052
|
+
import { exec as exec13 } from "node:child_process";
|
|
25053
|
+
import { promisify as promisify13 } from "node:util";
|
|
24468
25054
|
async function getCredential(key) {
|
|
24469
25055
|
if (process.platform !== "darwin") {
|
|
24470
25056
|
return getEnvFallback(key);
|
|
24471
25057
|
}
|
|
24472
25058
|
try {
|
|
24473
|
-
const { stdout } = await
|
|
25059
|
+
const { stdout } = await execAsync8(
|
|
24474
25060
|
`security find-generic-password -s "${SERVICE_NAME}" -a "${key}" -w 2>/dev/null`
|
|
24475
25061
|
);
|
|
24476
25062
|
return stdout.trim() || null;
|
|
@@ -24486,11 +25072,11 @@ function getEnvFallback(key) {
|
|
|
24486
25072
|
const envVar = envMap[key];
|
|
24487
25073
|
return process.env[envVar] || null;
|
|
24488
25074
|
}
|
|
24489
|
-
var
|
|
25075
|
+
var execAsync8, SERVICE_NAME;
|
|
24490
25076
|
var init_keychain = __esm({
|
|
24491
25077
|
"core/utils/keychain.ts"() {
|
|
24492
25078
|
"use strict";
|
|
24493
|
-
|
|
25079
|
+
execAsync8 = promisify13(exec13);
|
|
24494
25080
|
SERVICE_NAME = "prjct-cli";
|
|
24495
25081
|
__name(getCredential, "getCredential");
|
|
24496
25082
|
__name(getEnvFallback, "getEnvFallback");
|
|
@@ -25256,19 +25842,19 @@ var init_linear = __esm({
|
|
|
25256
25842
|
});
|
|
25257
25843
|
|
|
25258
25844
|
// core/utils/project-credentials.ts
|
|
25259
|
-
import
|
|
25845
|
+
import fs46 from "node:fs";
|
|
25260
25846
|
import os14 from "node:os";
|
|
25261
|
-
import
|
|
25847
|
+
import path55 from "node:path";
|
|
25262
25848
|
function getCredentialsPath(projectId) {
|
|
25263
|
-
return
|
|
25849
|
+
return path55.join(os14.homedir(), ".prjct-cli", "projects", projectId, "config", "credentials.json");
|
|
25264
25850
|
}
|
|
25265
25851
|
async function getProjectCredentials(projectId) {
|
|
25266
25852
|
const credPath = getCredentialsPath(projectId);
|
|
25267
|
-
if (!
|
|
25853
|
+
if (!fs46.existsSync(credPath)) {
|
|
25268
25854
|
return {};
|
|
25269
25855
|
}
|
|
25270
25856
|
try {
|
|
25271
|
-
return JSON.parse(
|
|
25857
|
+
return JSON.parse(fs46.readFileSync(credPath, "utf-8"));
|
|
25272
25858
|
} catch (error) {
|
|
25273
25859
|
console.error("[project-credentials] Failed to read credentials:", error.message);
|
|
25274
25860
|
return {};
|
|
@@ -25721,6 +26307,9 @@ var init_commands = __esm({
|
|
|
25721
26307
|
async stats(projectPath = process.cwd(), options = {}) {
|
|
25722
26308
|
return this.analysis.stats(projectPath, options);
|
|
25723
26309
|
}
|
|
26310
|
+
async status(projectPath = process.cwd(), options = {}) {
|
|
26311
|
+
return this.analysis.status(projectPath, options);
|
|
26312
|
+
}
|
|
25724
26313
|
// ========== Context Commands ==========
|
|
25725
26314
|
async context(input = null, projectPath = process.cwd()) {
|
|
25726
26315
|
return this.contextCmds.context(input, projectPath);
|
|
@@ -25790,6 +26379,7 @@ function registerAllCommands() {
|
|
|
25790
26379
|
commandRegistry.registerMethod("analyze", analysis, "analyze", getMeta("analyze"));
|
|
25791
26380
|
commandRegistry.registerMethod("sync", analysis, "sync", getMeta("sync"));
|
|
25792
26381
|
commandRegistry.registerMethod("stats", analysis, "stats", getMeta("stats"));
|
|
26382
|
+
commandRegistry.registerMethod("status", analysis, "status", getMeta("status"));
|
|
25793
26383
|
commandRegistry.registerMethod("start", setup, "start", getMeta("start"));
|
|
25794
26384
|
commandRegistry.registerMethod("setup", setup, "setup", getMeta("setup"));
|
|
25795
26385
|
commandRegistry.registerMethod("uninstall", uninstallCmd, "uninstall", getMeta("uninstall"));
|
|
@@ -25841,7 +26431,7 @@ var require_package = __commonJS({
|
|
|
25841
26431
|
"package.json"(exports, module) {
|
|
25842
26432
|
module.exports = {
|
|
25843
26433
|
name: "prjct-cli",
|
|
25844
|
-
version: "0.
|
|
26434
|
+
version: "0.60.0",
|
|
25845
26435
|
description: "Context layer for AI agents. Project context for Claude Code, Gemini CLI, and more.",
|
|
25846
26436
|
main: "core/index.ts",
|
|
25847
26437
|
bin: {
|
|
@@ -25948,9 +26538,9 @@ var require_package = __commonJS({
|
|
|
25948
26538
|
|
|
25949
26539
|
// core/index.ts
|
|
25950
26540
|
var core_exports = {};
|
|
25951
|
-
import
|
|
26541
|
+
import fs47 from "node:fs";
|
|
25952
26542
|
import os15 from "node:os";
|
|
25953
|
-
import
|
|
26543
|
+
import path56 from "node:path";
|
|
25954
26544
|
async function main() {
|
|
25955
26545
|
const [commandName, ...rawArgs] = process.argv.slice(2);
|
|
25956
26546
|
if (["-v", "--version", "version"].includes(commandName)) {
|
|
@@ -26020,6 +26610,9 @@ Use 'prjct --help' to see available commands.`);
|
|
|
26020
26610
|
json: options.json === true,
|
|
26021
26611
|
export: options.export === true
|
|
26022
26612
|
}), "stats"),
|
|
26613
|
+
status: /* @__PURE__ */ __name(() => commands.status(process.cwd(), {
|
|
26614
|
+
json: options.json === true
|
|
26615
|
+
}), "status"),
|
|
26023
26616
|
help: /* @__PURE__ */ __name((p) => commands.help(p || ""), "help"),
|
|
26024
26617
|
// Maintenance
|
|
26025
26618
|
recover: /* @__PURE__ */ __name(() => commands.recover(), "recover"),
|
|
@@ -26079,12 +26672,12 @@ function parseCommandArgs(_cmd, rawArgs) {
|
|
|
26079
26672
|
}
|
|
26080
26673
|
function displayVersion(version) {
|
|
26081
26674
|
const detection = detectAllProviders();
|
|
26082
|
-
const claudeCommandPath =
|
|
26083
|
-
const geminiCommandPath =
|
|
26084
|
-
const claudeConfigured =
|
|
26085
|
-
const geminiConfigured =
|
|
26086
|
-
const cursorConfigured =
|
|
26087
|
-
const cursorExists =
|
|
26675
|
+
const claudeCommandPath = path56.join(os15.homedir(), ".claude", "commands", "p.md");
|
|
26676
|
+
const geminiCommandPath = path56.join(os15.homedir(), ".gemini", "commands", "p.toml");
|
|
26677
|
+
const claudeConfigured = fs47.existsSync(claudeCommandPath);
|
|
26678
|
+
const geminiConfigured = fs47.existsSync(geminiCommandPath);
|
|
26679
|
+
const cursorConfigured = fs47.existsSync(path56.join(process.cwd(), ".cursor", "commands", "sync.md"));
|
|
26680
|
+
const cursorExists = fs47.existsSync(path56.join(process.cwd(), ".cursor"));
|
|
26088
26681
|
console.log(`
|
|
26089
26682
|
${CYAN3}p/${RESET5} prjct v${version}
|
|
26090
26683
|
${DIM6}Context layer for AI coding agents${RESET5}
|
|
@@ -26217,9 +26810,9 @@ var init_core = __esm({
|
|
|
26217
26810
|
init_ai_provider();
|
|
26218
26811
|
init_config_manager();
|
|
26219
26812
|
init_editors_config();
|
|
26220
|
-
import
|
|
26813
|
+
import fs48 from "node:fs";
|
|
26221
26814
|
import os16 from "node:os";
|
|
26222
|
-
import
|
|
26815
|
+
import path57 from "node:path";
|
|
26223
26816
|
|
|
26224
26817
|
// core/server/server.ts
|
|
26225
26818
|
import { Hono as Hono3 } from "hono";
|
|
@@ -26961,14 +27554,14 @@ function checkRoutersInstalled() {
|
|
|
26961
27554
|
const home = os16.homedir();
|
|
26962
27555
|
const detection = detectAllProviders();
|
|
26963
27556
|
if (detection.claude.installed) {
|
|
26964
|
-
const claudeRouter =
|
|
26965
|
-
if (!
|
|
27557
|
+
const claudeRouter = path57.join(home, ".claude", "commands", "p.md");
|
|
27558
|
+
if (!fs48.existsSync(claudeRouter)) {
|
|
26966
27559
|
return false;
|
|
26967
27560
|
}
|
|
26968
27561
|
}
|
|
26969
27562
|
if (detection.gemini.installed) {
|
|
26970
|
-
const geminiRouter =
|
|
26971
|
-
if (!
|
|
27563
|
+
const geminiRouter = path57.join(home, ".gemini", "commands", "p.toml");
|
|
27564
|
+
if (!fs48.existsSync(geminiRouter)) {
|
|
26972
27565
|
return false;
|
|
26973
27566
|
}
|
|
26974
27567
|
}
|
|
@@ -27069,7 +27662,7 @@ if (args[0] === "start" || args[0] === "setup") {
|
|
|
27069
27662
|
console.error('No prjct project found. Run "prjct init" first.');
|
|
27070
27663
|
process.exitCode = 1;
|
|
27071
27664
|
} else {
|
|
27072
|
-
const linearCliPath =
|
|
27665
|
+
const linearCliPath = path57.join(__dirname, "..", "core", "cli", "linear.ts");
|
|
27073
27666
|
const linearArgs = ["--project", projectId, ...args.slice(1)];
|
|
27074
27667
|
const child = spawn("bun", [linearCliPath, ...linearArgs], {
|
|
27075
27668
|
stdio: "inherit",
|
|
@@ -27088,12 +27681,12 @@ if (args[0] === "start" || args[0] === "setup") {
|
|
|
27088
27681
|
const detection = detectAllProviders();
|
|
27089
27682
|
const home = os16.homedir();
|
|
27090
27683
|
const cwd = process.cwd();
|
|
27091
|
-
const claudeConfigured =
|
|
27092
|
-
const geminiConfigured =
|
|
27093
|
-
const cursorDetected =
|
|
27094
|
-
const cursorConfigured =
|
|
27095
|
-
const windsurfDetected =
|
|
27096
|
-
const windsurfConfigured =
|
|
27684
|
+
const claudeConfigured = fs48.existsSync(path57.join(home, ".claude", "commands", "p.md"));
|
|
27685
|
+
const geminiConfigured = fs48.existsSync(path57.join(home, ".gemini", "commands", "p.toml"));
|
|
27686
|
+
const cursorDetected = fs48.existsSync(path57.join(cwd, ".cursor"));
|
|
27687
|
+
const cursorConfigured = fs48.existsSync(path57.join(cwd, ".cursor", "rules", "prjct.mdc"));
|
|
27688
|
+
const windsurfDetected = fs48.existsSync(path57.join(cwd, ".windsurf"));
|
|
27689
|
+
const windsurfConfigured = fs48.existsSync(path57.join(cwd, ".windsurf", "rules", "prjct.md"));
|
|
27097
27690
|
const GREEN7 = "\x1B[32m";
|
|
27098
27691
|
console.log(`
|
|
27099
27692
|
${CYAN4}p/${RESET6} prjct v${VERSION}
|
|
@@ -27132,9 +27725,9 @@ ${DIM7}Run 'prjct init' to configure (Cursor/Windsurf IDE)${RESET6}
|
|
|
27132
27725
|
${CYAN4}https://prjct.app${RESET6}
|
|
27133
27726
|
`);
|
|
27134
27727
|
} else {
|
|
27135
|
-
const configPath =
|
|
27728
|
+
const configPath = path57.join(os16.homedir(), ".prjct-cli", "config", "installed-editors.json");
|
|
27136
27729
|
const routersInstalled = checkRoutersInstalled();
|
|
27137
|
-
if (!
|
|
27730
|
+
if (!fs48.existsSync(configPath) || !routersInstalled) {
|
|
27138
27731
|
console.log(`
|
|
27139
27732
|
${CYAN4}${BOLD4} Welcome to prjct!${RESET6}
|
|
27140
27733
|
|