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.
@@ -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) => (path57) => {
20
- var fn = map[path57];
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: " + path57);
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 fs48 = __require("node:fs");
4023
- if (fs48.existsSync(fullPath) && fs48.statSync(fullPath).isFile()) {
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 fs48 = await import("node:fs/promises");
5207
- const path57 = await import("node:path");
5208
- const fullPath = path57.isAbsolute(filePath) ? filePath : path57.join(projectPath, filePath);
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 fs48.stat(fullPath);
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 fs48 = await import("node:fs/promises");
5278
- const path57 = await import("node:path");
5279
- const fullPath = path57.isAbsolute(targetPath) ? targetPath : path57.join(projectPath, targetPath);
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 fs48.stat(fullPath);
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 fs48 = await import("node:fs/promises");
16444
- const path57 = await import("node:path");
16763
+ const fs49 = await import("node:fs/promises");
16764
+ const path58 = await import("node:path");
16445
16765
  try {
16446
- const files = await fs48.readdir(this.projectPath);
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 = path57.join(this.projectPath, "package.json");
16452
- const pkgContent = await fs48.readFile(pkgPath, "utf-8");
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 fs48 = await import("node:fs/promises");
16489
- const path57 = await import("node:path");
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 fs48.access(path57.join(os17.homedir(), ".claude"));
16813
+ await fs49.access(path58.join(os17.homedir(), ".claude"));
16494
16814
  agents.push("claude");
16495
16815
  } catch {
16496
16816
  }
16497
16817
  try {
16498
- await fs48.access(path57.join(this.projectPath, ".cursorrules"));
16818
+ await fs49.access(path58.join(this.projectPath, ".cursorrules"));
16499
16819
  agents.push("cursor");
16500
16820
  } catch {
16501
16821
  }
16502
16822
  try {
16503
- await fs48.access(path57.join(this.projectPath, ".windsurfrules"));
16823
+ await fs49.access(path58.join(this.projectPath, ".windsurfrules"));
16504
16824
  agents.push("windsurf");
16505
16825
  } catch {
16506
16826
  }
16507
16827
  try {
16508
- await fs48.access(path57.join(this.projectPath, ".github", "copilot-instructions.md"));
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 fs48.access(path57.join(os17.homedir(), ".gemini"));
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 fs48 = await import("node:fs/promises");
16524
- const path57 = await import("node:path");
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 fs48.readdir(this.projectPath);
16850
+ const files = await fs49.readdir(this.projectPath);
16531
16851
  if (files.includes("package.json")) {
16532
- const pkgPath = path57.join(this.projectPath, "package.json");
16533
- const pkgContent = await fs48.readFile(pkgPath, "utf-8");
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 fs48 = await import("node:fs/promises");
18603
- const files = await fs48.readdir(specsPath2);
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 fs36 from "node:fs";
19592
+ import fs37 from "node:fs";
19035
19593
  import os11 from "node:os";
19036
- import path38 from "node:path";
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") || fs36.existsSync(path38.join(repoPath, ".cursor"))) {
19611
+ if (commandExists("cursor") || fs37.existsSync(path39.join(repoPath, ".cursor"))) {
19054
19612
  detected.push("cursor");
19055
19613
  }
19056
- if (fs36.existsSync(path38.join(repoPath, ".github"))) {
19614
+ if (fs37.existsSync(path39.join(repoPath, ".github"))) {
19057
19615
  detected.push("copilot");
19058
19616
  }
19059
- if (commandExists("windsurf") || fs36.existsSync(path38.join(repoPath, ".windsurf"))) {
19617
+ if (commandExists("windsurf") || fs37.existsSync(path39.join(repoPath, ".windsurf"))) {
19060
19618
  detected.push("windsurf");
19061
19619
  }
19062
- if (fs36.existsSync(path38.join(repoPath, ".continue")) || fs36.existsSync(path38.join(os11.homedir(), ".continue"))) {
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 fs37 from "node:fs/promises";
19139
- import path39 from "node:path";
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 = path39.join(repoPath, config.outputFile);
19732
+ outputPath = path40.join(repoPath, config.outputFile);
19175
19733
  } else {
19176
- outputPath = path39.join(globalPath, "context", config.outputFile);
19734
+ outputPath = path40.join(globalPath, "context", config.outputFile);
19177
19735
  }
19178
- await fs37.mkdir(path39.dirname(outputPath), { recursive: true });
19736
+ await fs38.mkdir(path40.dirname(outputPath), { recursive: true });
19179
19737
  try {
19180
- const existingContent = await fs37.readFile(outputPath, "utf-8");
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 fs37.writeFile(outputPath, content, "utf-8");
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 fs38 from "node:fs/promises";
19231
- import path40 from "node:path";
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 fs38.readFile(filePath, "utf-8");
19813
+ const existingContent = await fs39.readFile(filePath, "utf-8");
19256
19814
  const validation = validatePreserveBlocks(existingContent);
19257
19815
  if (!validation.valid) {
19258
- const filename = path40.basename(filePath);
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 fs38.writeFile(filePath, finalContent, "utf-8");
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 = path40.join(this.config.globalPath, "context");
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 = path40.join(contextPath, "CLAUDE.md");
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 = path40.join(this.config.globalPath, "storage", "state.json");
19377
- const state = JSON.parse(await fs38.readFile(statePath, "utf-8"));
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(path40.join(contextPath, "now.md"), content);
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 = path40.join(this.config.globalPath, "storage", "queue.json");
19402
- queue = JSON.parse(await fs38.readFile(queuePath, "utf-8"));
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(path40.join(contextPath, "next.md"), content);
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 = path40.join(this.config.globalPath, "storage", "ideas.json");
19418
- ideas = JSON.parse(await fs38.readFile(ideasPath, "utf-8"));
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(path40.join(contextPath, "ideas.md"), content);
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 = path40.join(this.config.globalPath, "storage", "shipped.json");
19436
- shipped = JSON.parse(await fs38.readFile(shippedPath, "utf-8"));
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(path40.join(contextPath, "shipped.md"), content);
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 = path40.join(pkg.path, "CLAUDE.md");
20032
+ const claudePath = path41.join(pkg.path, "CLAUDE.md");
19475
20033
  await this.writeWithPreservation(claudePath, content);
19476
- generatedFiles.push(path40.relative(this.config.projectPath, claudePath));
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 = path40.join(pkg.path, "package.json");
19490
- const pkgJson = JSON.parse(await fs38.readFile(pkgJsonPath, "utf-8"));
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 fs39 from "node:fs/promises";
19556
- import path41 from "node:path";
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 = path41.join(this.projectPath, "package.json");
19716
- const content = await fs39.readFile(pkgPath, "utf-8");
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 fs39.access(path41.join(this.projectPath, filename));
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 exec10 } from "node:child_process";
19739
- import fs40 from "node:fs/promises";
19740
- import path42 from "node:path";
19741
- import { promisify as promisify10 } from "node:util";
19742
- var execAsync5, SyncService, syncService;
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
- execAsync5 = promisify10(exec10);
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) => fs40.mkdir(path42.join(this.globalPath, dir), { recursive: true }))
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 execAsync5("git branch --show-current", {
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 execAsync5("git rev-list --count HEAD", {
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 execAsync5("git shortlog -sn --all | wc -l", {
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 execAsync5("git status --porcelain", {
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 execAsync5(
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 execAsync5('git log --oneline --since="1 week ago" | wc -l', {
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: path42.basename(this.projectPath),
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 execAsync5(
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 = path42.join(this.projectPath, "package.json");
19976
- const pkg = JSON.parse(await fs40.readFile(pkgPath, "utf-8"));
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 = path42.join(this.globalPath, "agents");
20642
+ const agentsPath = path43.join(this.globalPath, "agents");
20085
20643
  try {
20086
- const files = await fs40.readdir(agentsPath);
20644
+ const files = await fs41.readdir(agentsPath);
20087
20645
  for (const file of files) {
20088
20646
  if (file.endsWith(".md")) {
20089
- await fs40.unlink(path42.join(agentsPath, file));
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 = path42.join(
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 fs40.readFile(templatePath, "utf-8");
20696
+ content = await fs41.readFile(templatePath, "utf-8");
20139
20697
  } catch {
20140
20698
  content = this.generateMinimalWorkflowAgent(name);
20141
20699
  }
20142
- await fs40.writeFile(path42.join(agentsPath, `${name}.md`), content, "utf-8");
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 = path42.join(
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 fs40.readFile(templatePath, "utf-8");
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 fs40.writeFile(path42.join(agentsPath, `${name}.md`), content, "utf-8");
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
- fs40.writeFile(
20232
- path42.join(this.globalPath, "config", "skills.json"),
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 = path42.join(this.globalPath, "project.json");
20812
+ const projectJsonPath = path43.join(this.globalPath, "project.json");
20255
20813
  let existing = {};
20256
20814
  try {
20257
- existing = JSON.parse(await fs40.readFile(projectJsonPath, "utf-8"));
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 fs40.writeFile(projectJsonPath, JSON.stringify(updated, null, 2), "utf-8");
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 = path42.join(this.globalPath, "storage", "state.json");
20843
+ const statePath = path43.join(this.globalPath, "storage", "state.json");
20283
20844
  let state = {};
20284
20845
  try {
20285
- state = JSON.parse(await fs40.readFile(statePath, "utf-8"));
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 fs40.writeFile(statePath, JSON.stringify(state, null, 2), "utf-8");
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 = path42.join(this.globalPath, "memory", "events.jsonl");
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 fs40.appendFile(memoryPath, `${JSON.stringify(event)}
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 = path42.join(this.globalPath, file);
20348
- const content = await fs40.readFile(filePath, "utf-8");
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 = path42.join(this.globalPath, "agents", `${agent.name}.md`);
20356
- const content = await fs40.readFile(agentPath, "utf-8");
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 fs40.access(path42.join(this.projectPath, filename));
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 = path42.join(__dirname, "..", "..", "package.json");
20397
- const pkg = JSON.parse(await fs40.readFile(pkgPath, "utf-8"));
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 fs41 from "node:fs/promises";
21119
+ import fs42 from "node:fs/promises";
20558
21120
  import os12 from "node:os";
20559
- import path43 from "node:path";
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 fs41.readdir(dirPath, { withFileTypes: true });
21127
+ const entries = await fs42.readdir(dirPath, { withFileTypes: true });
20566
21128
  for (const entry of entries) {
20567
- const entryPath = path43.join(dirPath, entry.name);
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 fs41.stat(entryPath);
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 fs41.readdir(dirPath, { withFileTypes: true });
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(path43.join(prjctCliPath, "projects")) : 0;
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 = path43.join(providerPaths.claude.config, "CLAUDE.md");
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 = path43.join(providerPaths.claude.config, "prjct-statusline.sh");
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 = path43.join(providerPaths.gemini.config, "GEMINI.md");
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 fs41.readFile(filePath, "utf-8");
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 fs41.unlink(filePath);
21277
+ await fs42.unlink(filePath);
20716
21278
  } else {
20717
- await fs41.writeFile(filePath, `${newContent}
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 = path43.join(homeDir, `.prjct-backup-${timestamp}`);
21290
+ const backupDir = path44.join(homeDir, `.prjct-backup-${timestamp}`);
20729
21291
  try {
20730
- await fs41.mkdir(backupDir, { recursive: true });
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, path43.join(backupDir, ".prjct-cli"));
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 fs41.mkdir(dest, { recursive: true });
20742
- const entries = await fs41.readdir(src, { withFileTypes: true });
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 = path43.join(src, entry.name);
20745
- const destPath = path43.join(dest, entry.name);
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 fs41.copyFile(srcPath, destPath);
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 fs41.rm(item.path, { recursive: true, force: true });
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 fs41.unlink(item.path);
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 path44 from "node:path";
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: ${path44.basename(this.projectPath)}`));
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 fs42 from "node:fs";
22383
+ import fs43 from "node:fs";
21806
22384
  import os13 from "node:os";
21807
- import path45 from "node:path";
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 = path45.join(os13.homedir(), ".gemini", "commands");
21914
- const routerSource = path45.join(getPackageRoot(), "templates", "commands", "p.toml");
21915
- const routerDest = path45.join(geminiCommandsDir, "p.toml");
21916
- fs42.mkdirSync(geminiCommandsDir, { recursive: true });
21917
- if (fs42.existsSync(routerSource)) {
21918
- fs42.copyFileSync(routerSource, routerDest);
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 = path45.join(os13.homedir(), ".gemini");
21930
- const globalConfigPath = path45.join(geminiDir, "GEMINI.md");
21931
- const templatePath = path45.join(getPackageRoot(), "templates", "global", "GEMINI.md");
21932
- fs42.mkdirSync(geminiDir, { recursive: true });
21933
- const templateContent = fs42.readFileSync(templatePath, "utf-8");
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 = fs42.readFileSync(globalConfigPath, "utf-8");
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
- fs42.writeFileSync(globalConfigPath, templateContent, "utf-8");
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
- fs42.writeFileSync(globalConfigPath, updatedContent2, "utf-8");
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
- fs42.writeFileSync(globalConfigPath, updatedContent, "utf-8");
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 = path45.join(os13.homedir(), ".gemini", "antigravity", "skills");
21979
- const prjctSkillDir = path45.join(antigravitySkillsDir, "prjct");
21980
- const skillMdPath = path45.join(prjctSkillDir, "SKILL.md");
21981
- const templatePath = path45.join(getPackageRoot(), "templates", "antigravity", "SKILL.md");
21982
- fs42.mkdirSync(prjctSkillDir, { recursive: true });
21983
- const fileExists2 = fs42.existsSync(skillMdPath);
21984
- if (!fs42.existsSync(templatePath)) {
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 = fs42.readFileSync(templatePath, "utf-8");
21989
- fs42.writeFileSync(skillMdPath, templateContent, "utf-8");
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 = path45.join(projectRoot, ".cursor");
22009
- const rulesDir = path45.join(cursorDir, "rules");
22010
- const commandsDir = path45.join(cursorDir, "commands");
22011
- const routerMdcDest = path45.join(rulesDir, "prjct.mdc");
22012
- const routerMdcSource = path45.join(getPackageRoot(), "templates", "cursor", "router.mdc");
22013
- const cursorCommandsSource = path45.join(getPackageRoot(), "templates", "cursor", "commands");
22014
- fs42.mkdirSync(rulesDir, { recursive: true });
22015
- fs42.mkdirSync(commandsDir, { recursive: true });
22016
- if (fs42.existsSync(routerMdcSource)) {
22017
- fs42.copyFileSync(routerMdcSource, routerMdcDest);
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 (fs42.existsSync(cursorCommandsSource)) {
22021
- const commandFiles = fs42.readdirSync(cursorCommandsSource).filter((f) => f.endsWith(".md"));
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 = path45.join(cursorCommandsSource, file);
22024
- const dest = path45.join(commandsDir, file);
22025
- fs42.copyFileSync(src, dest);
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 = path45.join(projectRoot, ".gitignore");
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 = fs42.readFileSync(gitignorePath, "utf-8");
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
- fs42.writeFileSync(gitignorePath, newContent, "utf-8");
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 fs42.existsSync(path45.join(projectRoot, ".cursor"));
22655
+ return fs43.existsSync(path46.join(projectRoot, ".cursor"));
22078
22656
  }
22079
22657
  function needsCursorRegeneration(projectRoot) {
22080
- const cursorDir = path45.join(projectRoot, ".cursor");
22081
- const routerPath = path45.join(cursorDir, "rules", "prjct.mdc");
22082
- return fs42.existsSync(cursorDir) && !fs42.existsSync(routerPath);
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 = path45.join(projectRoot, ".windsurf");
22093
- const rulesDir = path45.join(windsurfDir, "rules");
22094
- const workflowsDir = path45.join(windsurfDir, "workflows");
22095
- const routerDest = path45.join(rulesDir, "prjct.md");
22096
- const routerSource = path45.join(getPackageRoot(), "templates", "windsurf", "router.md");
22097
- const windsurfWorkflowsSource = path45.join(
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
- fs42.mkdirSync(rulesDir, { recursive: true });
22104
- fs42.mkdirSync(workflowsDir, { recursive: true });
22105
- if (fs42.existsSync(routerSource)) {
22106
- fs42.copyFileSync(routerSource, routerDest);
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 (fs42.existsSync(windsurfWorkflowsSource)) {
22110
- const workflowFiles = fs42.readdirSync(windsurfWorkflowsSource).filter((f) => f.endsWith(".md"));
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 = path45.join(windsurfWorkflowsSource, file);
22113
- const dest = path45.join(workflowsDir, file);
22114
- fs42.copyFileSync(src, dest);
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 = path45.join(projectRoot, ".gitignore");
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 = fs42.readFileSync(gitignorePath, "utf-8");
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
- fs42.writeFileSync(gitignorePath, newContent, "utf-8");
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 fs42.existsSync(path45.join(projectRoot, ".windsurf"));
22744
+ return fs43.existsSync(path46.join(projectRoot, ".windsurf"));
22167
22745
  }
22168
22746
  function needsWindsurfRegeneration(projectRoot) {
22169
- const windsurfDir = path45.join(projectRoot, ".windsurf");
22170
- const routerPath = path45.join(windsurfDir, "rules", "prjct.md");
22171
- return fs42.existsSync(windsurfDir) && !fs42.existsSync(routerPath);
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 = path45.join(os13.homedir(), ".prjct-cli", "projects");
22176
- if (!fs42.existsSync(projectsDir)) {
22753
+ const projectsDir = path46.join(os13.homedir(), ".prjct-cli", "projects");
22754
+ if (!fs43.existsSync(projectsDir)) {
22177
22755
  return;
22178
22756
  }
22179
- const projectDirs = fs42.readdirSync(projectsDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
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 = path45.join(projectsDir, projectId, "project.json");
22183
- if (!fs42.existsSync(projectJsonPath)) {
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 = fs42.readFileSync(projectJsonPath, "utf8");
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
- fs42.writeFileSync(projectJsonPath, JSON.stringify(project, null, 2));
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 (fs42.existsSync(settingsPath)) {
22789
+ if (fs43.existsSync(settingsPath)) {
22212
22790
  try {
22213
- settings = JSON.parse(fs42.readFileSync(settingsPath, "utf8"));
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
- fs42.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
22799
+ fs43.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
22222
22800
  }
22223
22801
  async function installStatusLine() {
22224
22802
  try {
22225
- const claudeDir = path45.join(os13.homedir(), ".claude");
22226
- const settingsPath = path45.join(claudeDir, "settings.json");
22227
- const claudeStatusLinePath = path45.join(claudeDir, "prjct-statusline.sh");
22228
- const prjctStatusLineDir = path45.join(os13.homedir(), ".prjct-cli", "statusline");
22229
- const prjctStatusLinePath = path45.join(prjctStatusLineDir, "statusline.sh");
22230
- const prjctThemesDir = path45.join(prjctStatusLineDir, "themes");
22231
- const prjctLibDir = path45.join(prjctStatusLineDir, "lib");
22232
- const prjctComponentsDir = path45.join(prjctStatusLineDir, "components");
22233
- const prjctConfigPath = path45.join(prjctStatusLineDir, "config.json");
22234
- const assetsDir = path45.join(getPackageRoot(), "assets", "statusline");
22235
- const sourceScript = path45.join(assetsDir, "statusline.sh");
22236
- const sourceThemeDir = path45.join(assetsDir, "themes");
22237
- const sourceLibDir = path45.join(assetsDir, "lib");
22238
- const sourceComponentsDir = path45.join(assetsDir, "components");
22239
- const sourceConfigPath = path45.join(assetsDir, "default-config.json");
22240
- if (!fs42.existsSync(claudeDir)) {
22241
- fs42.mkdirSync(claudeDir, { recursive: true });
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 (!fs42.existsSync(prjctStatusLineDir)) {
22244
- fs42.mkdirSync(prjctStatusLineDir, { recursive: true });
22821
+ if (!fs43.existsSync(prjctStatusLineDir)) {
22822
+ fs43.mkdirSync(prjctStatusLineDir, { recursive: true });
22245
22823
  }
22246
- if (!fs42.existsSync(prjctThemesDir)) {
22247
- fs42.mkdirSync(prjctThemesDir, { recursive: true });
22824
+ if (!fs43.existsSync(prjctThemesDir)) {
22825
+ fs43.mkdirSync(prjctThemesDir, { recursive: true });
22248
22826
  }
22249
- if (!fs42.existsSync(prjctLibDir)) {
22250
- fs42.mkdirSync(prjctLibDir, { recursive: true });
22827
+ if (!fs43.existsSync(prjctLibDir)) {
22828
+ fs43.mkdirSync(prjctLibDir, { recursive: true });
22251
22829
  }
22252
- if (!fs42.existsSync(prjctComponentsDir)) {
22253
- fs42.mkdirSync(prjctComponentsDir, { recursive: true });
22830
+ if (!fs43.existsSync(prjctComponentsDir)) {
22831
+ fs43.mkdirSync(prjctComponentsDir, { recursive: true });
22254
22832
  }
22255
- if (fs42.existsSync(prjctStatusLinePath)) {
22256
- const existingContent = fs42.readFileSync(prjctStatusLinePath, "utf8");
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
- fs42.writeFileSync(prjctStatusLinePath, updatedContent, { mode: 493 });
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 (fs42.existsSync(sourceScript)) {
22274
- let scriptContent = fs42.readFileSync(sourceScript, "utf8");
22851
+ if (fs43.existsSync(sourceScript)) {
22852
+ let scriptContent = fs43.readFileSync(sourceScript, "utf8");
22275
22853
  scriptContent = scriptContent.replace(/CLI_VERSION="[^"]*"/, `CLI_VERSION="${VERSION}"`);
22276
- fs42.writeFileSync(prjctStatusLinePath, scriptContent, { mode: 493 });
22854
+ fs43.writeFileSync(prjctStatusLinePath, scriptContent, { mode: 493 });
22277
22855
  installStatusLineModules(sourceLibDir, prjctLibDir);
22278
22856
  installStatusLineModules(sourceComponentsDir, prjctComponentsDir);
22279
- if (fs42.existsSync(sourceThemeDir)) {
22280
- const themes = fs42.readdirSync(sourceThemeDir);
22857
+ if (fs43.existsSync(sourceThemeDir)) {
22858
+ const themes = fs43.readdirSync(sourceThemeDir);
22281
22859
  for (const theme of themes) {
22282
- const src = path45.join(sourceThemeDir, theme);
22283
- const dest = path45.join(prjctThemesDir, theme);
22284
- fs42.copyFileSync(src, dest);
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 (!fs42.existsSync(prjctConfigPath) && fs42.existsSync(sourceConfigPath)) {
22288
- fs42.copyFileSync(sourceConfigPath, prjctConfigPath);
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
- fs42.writeFileSync(prjctStatusLinePath, scriptContent, { mode: 493 });
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 = path45.join(os13.homedir(), ".claude");
22336
- const mcpConfigPath = path45.join(claudeDir, "mcp.json");
22337
- if (!fs42.existsSync(claudeDir)) {
22338
- fs42.mkdirSync(claudeDir, { recursive: true });
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 (fs42.existsSync(mcpConfigPath)) {
22349
- const existingContent = fs42.readFileSync(mcpConfigPath, "utf-8");
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
- fs42.writeFileSync(mcpConfigPath, JSON.stringify(existingConfig, null, 2), "utf-8");
22934
+ fs43.writeFileSync(mcpConfigPath, JSON.stringify(existingConfig, null, 2), "utf-8");
22357
22935
  } else {
22358
- fs42.writeFileSync(mcpConfigPath, JSON.stringify(context7Config, null, 2), "utf-8");
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 (!fs42.existsSync(sourceDir)) {
22943
+ if (!fs43.existsSync(sourceDir)) {
22366
22944
  return;
22367
22945
  }
22368
- const files = fs42.readdirSync(sourceDir);
22946
+ const files = fs43.readdirSync(sourceDir);
22369
22947
  for (const file of files) {
22370
22948
  if (file.endsWith(".sh")) {
22371
- const src = path45.join(sourceDir, file);
22372
- const dest = path45.join(destDir, file);
22373
- fs42.copyFileSync(src, dest);
22374
- fs42.chmodSync(dest, 493);
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 (fs42.existsSync(linkPath)) {
22381
- const stats = fs42.lstatSync(linkPath);
22958
+ if (fs43.existsSync(linkPath)) {
22959
+ const stats = fs43.lstatSync(linkPath);
22382
22960
  if (stats.isSymbolicLink()) {
22383
- const existingTarget = fs42.readlinkSync(linkPath);
22961
+ const existingTarget = fs43.readlinkSync(linkPath);
22384
22962
  if (existingTarget === targetPath) {
22385
22963
  return;
22386
22964
  }
22387
22965
  }
22388
- fs42.unlinkSync(linkPath);
22966
+ fs43.unlinkSync(linkPath);
22389
22967
  }
22390
- fs42.symlinkSync(targetPath, linkPath);
22968
+ fs43.symlinkSync(targetPath, linkPath);
22391
22969
  } catch (_error) {
22392
22970
  try {
22393
- if (fs42.existsSync(targetPath)) {
22394
- fs42.copyFileSync(targetPath, linkPath);
22395
- fs42.chmodSync(linkPath, 493);
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 path46 from "node:path";
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 = path46.basename(projectPath);
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 fs43 from "node:fs/promises";
23081
- import path47 from "node:path";
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 = path47.join(globalPath, "analysis", "repo-analysis.json");
23208
- const content = await fs43.readFile(analysisPath, "utf-8");
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 path48 from "node:path";
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(path48.basename(filePath));
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 path49 from "node:path";
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 = path49.join(
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 = path49.join(designsPath, designFileName);
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 path50 from "node:path";
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 = path50.join(path_manager_default.getGlobalProjectPath(projectId), "snapshots");
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 = path50.join(snapshotsPath, "history.json");
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 = path50.join(path_manager_default.getGlobalProjectPath(projectId), "snapshots");
23537
- const snapshotFile = path50.join(snapshotsPath, "history.json");
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 = path50.join(path_manager_default.getGlobalProjectPath(projectId), "snapshots");
23597
- const snapshotFile = path50.join(snapshotsPath, "history.json");
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 fs44 from "node:fs";
23705
- import path51 from "node:path";
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 = path51.join(claudeDir, "prjct-statusline.sh");
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
- fs44.writeFileSync(statusLinePath, scriptContent, { mode: 493 });
24476
+ fs45.writeFileSync(statusLinePath, scriptContent, { mode: 493 });
23891
24477
  let settings = {};
23892
- if (fs44.existsSync(settingsPath)) {
24478
+ if (fs45.existsSync(settingsPath)) {
23893
24479
  try {
23894
- settings = JSON.parse(fs44.readFileSync(settingsPath, "utf8"));
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
- fs44.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
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 path52 from "node:path";
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(path52.join(projectPath, "pnpm-lock.yaml"))) return "pnpm";
23966
- if (await fileExists(path52.join(projectPath, "yarn.lock"))) return "yarn";
23967
- if (await fileExists(path52.join(projectPath, "bun.lockb"))) return "bun";
23968
- if (await fileExists(path52.join(projectPath, "bun.lock"))) return "bun";
23969
- if (await fileExists(path52.join(projectPath, "package-lock.json"))) return "npm";
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 = path52.join(projectPath, "package.json");
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(path52.join(projectPath, "pytest.ini"))) {
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(path52.join(projectPath, "pyproject.toml"), "");
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(path52.join(projectPath, "Cargo.toml"))) {
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(path52.join(projectPath, "go.mod"))) {
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(path52.join(projectPath, "pom.xml"))) {
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(path52.join(projectPath, "gradlew")) && (await fileExists(path52.join(projectPath, "build.gradle")) || await fileExists(path52.join(projectPath, "build.gradle.kts")))) {
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 exec11 } from "node:child_process";
24040
- import { promisify as promisify11 } from "node:util";
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 execAsync6(action, {
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 execAsync6, DIM5, GREEN5, RED, YELLOW5, RESET4, sessionPreferences, oncePreferences;
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
- execAsync6 = promisify11(exec11);
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 path53 from "node:path";
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 = path53.join(projectPath, "package.json");
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 = path53.join(projectPath, "CHANGELOG.md");
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 exec12 } from "node:child_process";
24467
- import { promisify as promisify12 } from "node:util";
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 execAsync7(
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 execAsync7, SERVICE_NAME;
25075
+ var execAsync8, SERVICE_NAME;
24490
25076
  var init_keychain = __esm({
24491
25077
  "core/utils/keychain.ts"() {
24492
25078
  "use strict";
24493
- execAsync7 = promisify12(exec12);
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 fs45 from "node:fs";
25845
+ import fs46 from "node:fs";
25260
25846
  import os14 from "node:os";
25261
- import path54 from "node:path";
25847
+ import path55 from "node:path";
25262
25848
  function getCredentialsPath(projectId) {
25263
- return path54.join(os14.homedir(), ".prjct-cli", "projects", projectId, "config", "credentials.json");
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 (!fs45.existsSync(credPath)) {
25853
+ if (!fs46.existsSync(credPath)) {
25268
25854
  return {};
25269
25855
  }
25270
25856
  try {
25271
- return JSON.parse(fs45.readFileSync(credPath, "utf-8"));
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.58.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 fs46 from "node:fs";
26541
+ import fs47 from "node:fs";
25952
26542
  import os15 from "node:os";
25953
- import path55 from "node:path";
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 = path55.join(os15.homedir(), ".claude", "commands", "p.md");
26083
- const geminiCommandPath = path55.join(os15.homedir(), ".gemini", "commands", "p.toml");
26084
- const claudeConfigured = fs46.existsSync(claudeCommandPath);
26085
- const geminiConfigured = fs46.existsSync(geminiCommandPath);
26086
- const cursorConfigured = fs46.existsSync(path55.join(process.cwd(), ".cursor", "commands", "sync.md"));
26087
- const cursorExists = fs46.existsSync(path55.join(process.cwd(), ".cursor"));
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 fs47 from "node:fs";
26813
+ import fs48 from "node:fs";
26221
26814
  import os16 from "node:os";
26222
- import path56 from "node:path";
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 = path56.join(home, ".claude", "commands", "p.md");
26965
- if (!fs47.existsSync(claudeRouter)) {
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 = path56.join(home, ".gemini", "commands", "p.toml");
26971
- if (!fs47.existsSync(geminiRouter)) {
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 = path56.join(__dirname, "..", "core", "cli", "linear.ts");
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 = fs47.existsSync(path56.join(home, ".claude", "commands", "p.md"));
27092
- const geminiConfigured = fs47.existsSync(path56.join(home, ".gemini", "commands", "p.toml"));
27093
- const cursorDetected = fs47.existsSync(path56.join(cwd, ".cursor"));
27094
- const cursorConfigured = fs47.existsSync(path56.join(cwd, ".cursor", "rules", "prjct.mdc"));
27095
- const windsurfDetected = fs47.existsSync(path56.join(cwd, ".windsurf"));
27096
- const windsurfConfigured = fs47.existsSync(path56.join(cwd, ".windsurf", "rules", "prjct.md"));
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 = path56.join(os16.homedir(), ".prjct-cli", "config", "installed-editors.json");
27728
+ const configPath = path57.join(os16.homedir(), ".prjct-cli", "config", "installed-editors.json");
27136
27729
  const routersInstalled = checkRoutersInstalled();
27137
- if (!fs47.existsSync(configPath) || !routersInstalled) {
27730
+ if (!fs48.existsSync(configPath) || !routersInstalled) {
27138
27731
  console.log(`
27139
27732
  ${CYAN4}${BOLD4} Welcome to prjct!${RESET6}
27140
27733