prjct-cli 1.5.1 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +98 -0
- package/core/__tests__/utils/output.test.ts +7 -1
- package/core/agentic/orchestrator-executor.ts +126 -8
- package/core/agentic/prompt-builder.ts +40 -3
- package/core/ai-tools/registry.ts +1 -1
- package/core/bus/bus.ts +6 -4
- package/core/commands/analysis.ts +5 -0
- package/core/context-tools/token-counter.ts +2 -0
- package/core/domain/agent-loader.ts +35 -1
- package/core/services/context-selector.ts +6 -3
- package/core/services/hierarchical-agent-resolver.ts +2 -0
- package/core/services/sync-service.ts +112 -0
- package/core/session/compaction.ts +1 -1
- package/core/types/agentic.ts +22 -0
- package/core/types/agents.ts +5 -0
- package/core/types/index.ts +1 -0
- package/core/utils/output.ts +15 -1
- package/dist/bin/prjct.mjs +996 -358
- package/package.json +1 -1
- package/templates/config/skill-mappings.json +23 -60
- package/templates/subagents/domain/backend.md +1 -0
- package/templates/subagents/domain/database.md +1 -0
- package/templates/subagents/domain/devops.md +1 -0
- package/templates/subagents/domain/frontend.md +1 -0
- package/templates/subagents/domain/testing.md +1 -0
- package/templates/subagents/workflow/chief-architect.md +2 -1
- package/templates/subagents/workflow/prjct-planner.md +2 -1
- package/templates/subagents/workflow/prjct-shipper.md +1 -0
- package/templates/subagents/workflow/prjct-workflow.md +1 -0
package/dist/bin/prjct.mjs
CHANGED
|
@@ -16,10 +16,10 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
16
16
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
17
17
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
18
18
|
});
|
|
19
|
-
var __glob = (map) => (
|
|
20
|
-
var fn = map[
|
|
19
|
+
var __glob = (map) => (path64) => {
|
|
20
|
+
var fn = map[path64];
|
|
21
21
|
if (fn) return fn();
|
|
22
|
-
throw new Error("Module not found in bundle: " +
|
|
22
|
+
throw new Error("Module not found in bundle: " + path64);
|
|
23
23
|
};
|
|
24
24
|
var __esm = (fn, res) => function __init() {
|
|
25
25
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
@@ -2390,7 +2390,7 @@ var init_output = __esm({
|
|
|
2390
2390
|
}, "truncate");
|
|
2391
2391
|
__name(limitLines, "limitLines");
|
|
2392
2392
|
__name(formatForHuman, "formatForHuman");
|
|
2393
|
-
clear = /* @__PURE__ */ __name(() => process.stdout.write(`\r${" ".repeat(80)}\r`), "clear");
|
|
2393
|
+
clear = /* @__PURE__ */ __name(() => process.stdout.isTTY ? process.stdout.write(`\r${" ".repeat(80)}\r`) : true, "clear");
|
|
2394
2394
|
out = {
|
|
2395
2395
|
// Branding: Show header at start
|
|
2396
2396
|
start() {
|
|
@@ -2403,9 +2403,15 @@ var init_output = __esm({
|
|
|
2403
2403
|
return this;
|
|
2404
2404
|
},
|
|
2405
2405
|
// Branded spinner: prjct message...
|
|
2406
|
+
// In non-TTY (CI, Claude Code), prints a static line instead of animating
|
|
2406
2407
|
spin(msg) {
|
|
2407
2408
|
if (quietMode) return this;
|
|
2408
2409
|
this.stop();
|
|
2410
|
+
if (!process.stdout.isTTY) {
|
|
2411
|
+
process.stdout.write(`${branding_default.cli.spin(0, truncate(msg, 45))}
|
|
2412
|
+
`);
|
|
2413
|
+
return this;
|
|
2414
|
+
}
|
|
2409
2415
|
interval = setInterval(() => {
|
|
2410
2416
|
process.stdout.write(`\r${branding_default.cli.spin(frame++, truncate(msg, 45))}`);
|
|
2411
2417
|
}, SPEED);
|
|
@@ -2549,6 +2555,11 @@ ${chalk2.bold(title)}`);
|
|
|
2549
2555
|
if (quietMode) return this;
|
|
2550
2556
|
this.stop();
|
|
2551
2557
|
const counter = chalk2.dim(`[${current}/${total}]`);
|
|
2558
|
+
if (!process.stdout.isTTY) {
|
|
2559
|
+
process.stdout.write(`${branding_default.cli.spin(0, `${counter} ${truncate(msg, 35)}`)}
|
|
2560
|
+
`);
|
|
2561
|
+
return this;
|
|
2562
|
+
}
|
|
2552
2563
|
interval = setInterval(() => {
|
|
2553
2564
|
process.stdout.write(`\r${branding_default.cli.spin(frame++, `${counter} ${truncate(msg, 35)}`)}`);
|
|
2554
2565
|
}, SPEED);
|
|
@@ -2563,6 +2574,11 @@ ${chalk2.bold(title)}`);
|
|
|
2563
2574
|
const empty = 10 - filled;
|
|
2564
2575
|
const bar = chalk2.cyan("\u2588".repeat(filled)) + chalk2.dim("\u2591".repeat(empty));
|
|
2565
2576
|
const text = msg ? ` ${truncate(msg, 25)}` : "";
|
|
2577
|
+
if (!process.stdout.isTTY) {
|
|
2578
|
+
process.stdout.write(`${branding_default.cli.spin(0, `[${bar}] ${percent}%${text}`)}
|
|
2579
|
+
`);
|
|
2580
|
+
return this;
|
|
2581
|
+
}
|
|
2566
2582
|
interval = setInterval(() => {
|
|
2567
2583
|
process.stdout.write(`\r${branding_default.cli.spin(frame++, `[${bar}] ${percent}%${text}`)}`);
|
|
2568
2584
|
}, SPEED);
|
|
@@ -4259,8 +4275,8 @@ function tryResolve(basePath, projectPath) {
|
|
|
4259
4275
|
for (const ext of extensions) {
|
|
4260
4276
|
const fullPath = basePath + ext;
|
|
4261
4277
|
try {
|
|
4262
|
-
const
|
|
4263
|
-
if (
|
|
4278
|
+
const fs51 = __require("node:fs");
|
|
4279
|
+
if (fs51.existsSync(fullPath) && fs51.statSync(fullPath).isFile()) {
|
|
4264
4280
|
return path13.relative(projectPath, fullPath);
|
|
4265
4281
|
}
|
|
4266
4282
|
} catch {
|
|
@@ -4753,6 +4769,8 @@ var init_token_counter = __esm({
|
|
|
4753
4769
|
// $1/$5 per M
|
|
4754
4770
|
"claude-opus-4": { input: 0.015, output: 0.075 },
|
|
4755
4771
|
// $15/$75 per M (legacy)
|
|
4772
|
+
"claude-opus-4-6": { input: 0.015, output: 0.075 },
|
|
4773
|
+
// $15/$75 per M
|
|
4756
4774
|
// OpenAI
|
|
4757
4775
|
"gpt-4o": { input: 25e-4, output: 0.01 },
|
|
4758
4776
|
// $2.50/$10 per M
|
|
@@ -4771,6 +4789,7 @@ var init_token_counter = __esm({
|
|
|
4771
4789
|
BREAKDOWN_MODELS = [
|
|
4772
4790
|
"claude-sonnet-4.5",
|
|
4773
4791
|
"claude-opus-4.5",
|
|
4792
|
+
"claude-opus-4-6",
|
|
4774
4793
|
"gpt-4o",
|
|
4775
4794
|
"gemini-1.5-pro"
|
|
4776
4795
|
];
|
|
@@ -5443,11 +5462,11 @@ async function runSignaturesTool(args2, projectPath) {
|
|
|
5443
5462
|
}
|
|
5444
5463
|
};
|
|
5445
5464
|
}
|
|
5446
|
-
const
|
|
5447
|
-
const
|
|
5448
|
-
const fullPath =
|
|
5465
|
+
const fs51 = await import("node:fs/promises");
|
|
5466
|
+
const path64 = await import("node:path");
|
|
5467
|
+
const fullPath = path64.isAbsolute(filePath) ? filePath : path64.join(projectPath, filePath);
|
|
5449
5468
|
try {
|
|
5450
|
-
const stat = await
|
|
5469
|
+
const stat = await fs51.stat(fullPath);
|
|
5451
5470
|
if (stat.isDirectory()) {
|
|
5452
5471
|
const results = await extractDirectorySignatures(filePath, projectPath, {
|
|
5453
5472
|
recursive: args2.includes("--recursive") || args2.includes("-r")
|
|
@@ -5514,11 +5533,11 @@ async function runSummaryTool(args2, projectPath) {
|
|
|
5514
5533
|
}
|
|
5515
5534
|
};
|
|
5516
5535
|
}
|
|
5517
|
-
const
|
|
5518
|
-
const
|
|
5519
|
-
const fullPath =
|
|
5536
|
+
const fs51 = await import("node:fs/promises");
|
|
5537
|
+
const path64 = await import("node:path");
|
|
5538
|
+
const fullPath = path64.isAbsolute(targetPath) ? targetPath : path64.join(projectPath, targetPath);
|
|
5520
5539
|
try {
|
|
5521
|
-
const stat = await
|
|
5540
|
+
const stat = await fs51.stat(fullPath);
|
|
5522
5541
|
if (stat.isDirectory()) {
|
|
5523
5542
|
const results = await summarizeDirectory(targetPath, projectPath, {
|
|
5524
5543
|
recursive: args2.includes("--recursive") || args2.includes("-r")
|
|
@@ -12246,18 +12265,24 @@ var init_template_loader = __esm({
|
|
|
12246
12265
|
});
|
|
12247
12266
|
|
|
12248
12267
|
// core/agentic/orchestrator-executor.ts
|
|
12268
|
+
import { exec as execCallback5 } from "node:child_process";
|
|
12249
12269
|
import fs26 from "node:fs/promises";
|
|
12250
12270
|
import os8 from "node:os";
|
|
12251
12271
|
import path25 from "node:path";
|
|
12252
|
-
|
|
12272
|
+
import { promisify as promisify7 } from "node:util";
|
|
12273
|
+
var execAsync3, DOMAIN_KEYWORDS2, DOMAIN_DEPENDENCY_ORDER, OrchestratorExecutor, orchestratorExecutor, orchestrator_executor_default;
|
|
12253
12274
|
var init_orchestrator_executor = __esm({
|
|
12254
12275
|
"core/agentic/orchestrator-executor.ts"() {
|
|
12255
12276
|
"use strict";
|
|
12277
|
+
init_files_tool();
|
|
12278
|
+
init_recent_tool();
|
|
12279
|
+
init_signatures_tool();
|
|
12256
12280
|
init_config_manager();
|
|
12257
12281
|
init_path_manager();
|
|
12258
12282
|
init_storage2();
|
|
12259
12283
|
init_fs();
|
|
12260
12284
|
init_template_loader();
|
|
12285
|
+
execAsync3 = promisify7(execCallback5);
|
|
12261
12286
|
DOMAIN_KEYWORDS2 = {
|
|
12262
12287
|
database: [
|
|
12263
12288
|
"database",
|
|
@@ -12408,6 +12433,7 @@ var init_orchestrator_executor = __esm({
|
|
|
12408
12433
|
const { domains, primary } = await this.detectDomains(taskDescription, projectId, repoAnalysis);
|
|
12409
12434
|
const agents = await this.loadAgents(domains, projectId);
|
|
12410
12435
|
const skills = await this.loadSkills(agents);
|
|
12436
|
+
const realContext = await this.gatherRealContext(taskDescription, projectPath);
|
|
12411
12437
|
const requiresFragmentation = this.shouldFragment(domains, taskDescription);
|
|
12412
12438
|
let subtasks = null;
|
|
12413
12439
|
if (requiresFragmentation && command === "task") {
|
|
@@ -12424,9 +12450,87 @@ var init_orchestrator_executor = __esm({
|
|
|
12424
12450
|
id: projectId,
|
|
12425
12451
|
ecosystem: repoAnalysis?.ecosystem || "unknown",
|
|
12426
12452
|
conventions: repoAnalysis?.conventions || []
|
|
12427
|
-
}
|
|
12453
|
+
},
|
|
12454
|
+
realContext
|
|
12428
12455
|
};
|
|
12429
12456
|
}
|
|
12457
|
+
/**
|
|
12458
|
+
* Gather real codebase context proactively.
|
|
12459
|
+
*
|
|
12460
|
+
* Calls existing context tools (files-tool, recent-tool, signatures-tool)
|
|
12461
|
+
* to build a briefing so the agent doesn't need to explore first.
|
|
12462
|
+
*/
|
|
12463
|
+
async gatherRealContext(taskDescription, projectPath) {
|
|
12464
|
+
try {
|
|
12465
|
+
const [gitResult, filesResult, recentResult] = await Promise.all([
|
|
12466
|
+
this.getGitState(projectPath),
|
|
12467
|
+
findRelevantFiles(taskDescription, projectPath, { maxFiles: 10, minScore: 0.15 }),
|
|
12468
|
+
getRecentFiles(projectPath, { commits: 10, maxFiles: 10 })
|
|
12469
|
+
]);
|
|
12470
|
+
const topFiles = filesResult.files.slice(0, 3);
|
|
12471
|
+
const signatureResults = await Promise.all(
|
|
12472
|
+
topFiles.map(async (f) => {
|
|
12473
|
+
try {
|
|
12474
|
+
const result = await extractSignatures(f.path, projectPath);
|
|
12475
|
+
if (result.signatures.length === 0) return null;
|
|
12476
|
+
const sigContent = result.signatures.map((s) => `${s.exported ? "export " : ""}${s.type} ${s.name}: ${s.signature}`).join("\n");
|
|
12477
|
+
return { path: f.path, content: sigContent };
|
|
12478
|
+
} catch {
|
|
12479
|
+
return null;
|
|
12480
|
+
}
|
|
12481
|
+
})
|
|
12482
|
+
);
|
|
12483
|
+
return {
|
|
12484
|
+
gitBranch: gitResult.branch,
|
|
12485
|
+
gitStatus: gitResult.status,
|
|
12486
|
+
relevantFiles: filesResult.files.map((f) => ({
|
|
12487
|
+
path: f.path,
|
|
12488
|
+
score: Math.round(f.score * 100),
|
|
12489
|
+
reason: f.reasons.join(", ")
|
|
12490
|
+
})),
|
|
12491
|
+
recentFiles: recentResult.hotFiles.slice(0, 5).map((f) => ({
|
|
12492
|
+
path: f.path,
|
|
12493
|
+
lastChanged: f.lastChanged,
|
|
12494
|
+
changes: f.changes
|
|
12495
|
+
})),
|
|
12496
|
+
signatures: signatureResults.filter(
|
|
12497
|
+
(s) => s !== null
|
|
12498
|
+
)
|
|
12499
|
+
};
|
|
12500
|
+
} catch {
|
|
12501
|
+
return void 0;
|
|
12502
|
+
}
|
|
12503
|
+
}
|
|
12504
|
+
/**
|
|
12505
|
+
* Get current git state (branch + short status)
|
|
12506
|
+
*/
|
|
12507
|
+
async getGitState(projectPath) {
|
|
12508
|
+
try {
|
|
12509
|
+
const [branchResult, statusResult] = await Promise.all([
|
|
12510
|
+
execAsync3("git branch --show-current", { cwd: projectPath }),
|
|
12511
|
+
execAsync3("git status --porcelain", { cwd: projectPath })
|
|
12512
|
+
]);
|
|
12513
|
+
const branch = branchResult.stdout.trim() || "main";
|
|
12514
|
+
const lines = statusResult.stdout.trim().split("\n").filter(Boolean);
|
|
12515
|
+
let modified = 0;
|
|
12516
|
+
let untracked = 0;
|
|
12517
|
+
let staged = 0;
|
|
12518
|
+
for (const line of lines) {
|
|
12519
|
+
const code = line.substring(0, 2);
|
|
12520
|
+
if (code.startsWith("??")) untracked++;
|
|
12521
|
+
else if (code[0] !== " " && code[0] !== "?") staged++;
|
|
12522
|
+
else modified++;
|
|
12523
|
+
}
|
|
12524
|
+
const parts = [];
|
|
12525
|
+
if (staged > 0) parts.push(`${staged} staged`);
|
|
12526
|
+
if (modified > 0) parts.push(`${modified} modified`);
|
|
12527
|
+
if (untracked > 0) parts.push(`${untracked} untracked`);
|
|
12528
|
+
const status = parts.length > 0 ? parts.join(", ") : "clean";
|
|
12529
|
+
return { branch, status };
|
|
12530
|
+
} catch {
|
|
12531
|
+
return { branch: "unknown", status: "git unavailable" };
|
|
12532
|
+
}
|
|
12533
|
+
}
|
|
12430
12534
|
/**
|
|
12431
12535
|
* Load repo-analysis.json for project context
|
|
12432
12536
|
*/
|
|
@@ -12527,7 +12631,9 @@ var init_orchestrator_executor = __esm({
|
|
|
12527
12631
|
domain,
|
|
12528
12632
|
content: body,
|
|
12529
12633
|
skills: frontmatter.skills || [],
|
|
12530
|
-
filePath
|
|
12634
|
+
filePath,
|
|
12635
|
+
effort: frontmatter.effort,
|
|
12636
|
+
model: frontmatter.model
|
|
12531
12637
|
};
|
|
12532
12638
|
} catch {
|
|
12533
12639
|
}
|
|
@@ -12560,13 +12666,15 @@ var init_orchestrator_executor = __esm({
|
|
|
12560
12666
|
*/
|
|
12561
12667
|
async loadSkills(agents) {
|
|
12562
12668
|
const skillsDir = path25.join(os8.homedir(), ".claude", "skills");
|
|
12563
|
-
const
|
|
12669
|
+
const skillToAgents = /* @__PURE__ */ new Map();
|
|
12564
12670
|
for (const agent of agents) {
|
|
12565
12671
|
for (const skillName of agent.skills) {
|
|
12566
|
-
|
|
12672
|
+
const existing = skillToAgents.get(skillName) || [];
|
|
12673
|
+
existing.push(agent.name);
|
|
12674
|
+
skillToAgents.set(skillName, existing);
|
|
12567
12675
|
}
|
|
12568
12676
|
}
|
|
12569
|
-
const skillPromises = Array.from(
|
|
12677
|
+
const skillPromises = Array.from(skillToAgents.keys()).map(
|
|
12570
12678
|
async (skillName) => {
|
|
12571
12679
|
const flatPath = path25.join(skillsDir, `${skillName}.md`);
|
|
12572
12680
|
const subdirPath = path25.join(skillsDir, skillName, "SKILL.md");
|
|
@@ -12578,6 +12686,10 @@ var init_orchestrator_executor = __esm({
|
|
|
12578
12686
|
const content = await fs26.readFile(flatPath, "utf-8");
|
|
12579
12687
|
return { name: skillName, content, filePath: flatPath };
|
|
12580
12688
|
} catch {
|
|
12689
|
+
const agentNames = skillToAgents.get(skillName) || [];
|
|
12690
|
+
console.warn(
|
|
12691
|
+
`\u26A0 Skill "${skillName}" not installed (needed by: ${agentNames.join(", ")}). Run \`prjct sync\` to auto-install.`
|
|
12692
|
+
);
|
|
12581
12693
|
return null;
|
|
12582
12694
|
}
|
|
12583
12695
|
}
|
|
@@ -13898,6 +14010,10 @@ Apply specialized expertise. Read agent file for details if needed.
|
|
|
13898
14010
|
parts.push("### LOADED AGENTS (Project-Specific Specialists)\n\n");
|
|
13899
14011
|
for (const agent2 of orchestratorContext.agents) {
|
|
13900
14012
|
parts.push(`#### Agent: ${agent2.name} (${agent2.domain})
|
|
14013
|
+
`);
|
|
14014
|
+
if (agent2.effort) parts.push(`Effort: ${agent2.effort}
|
|
14015
|
+
`);
|
|
14016
|
+
if (agent2.model) parts.push(`Model: ${agent2.model}
|
|
13901
14017
|
`);
|
|
13902
14018
|
if (agent2.skills.length > 0) {
|
|
13903
14019
|
parts.push(`Skills: ${agent2.skills.join(", ")}
|
|
@@ -13917,12 +14033,47 @@ ${truncatedContent}
|
|
|
13917
14033
|
for (const skill of orchestratorContext.skills) {
|
|
13918
14034
|
parts.push(`#### Skill: ${skill.name}
|
|
13919
14035
|
`);
|
|
13920
|
-
const truncatedContent = skill.content.length >
|
|
14036
|
+
const truncatedContent = skill.content.length > 2e3 ? `${skill.content.substring(0, 2e3)}
|
|
13921
14037
|
... (truncated)` : skill.content;
|
|
13922
14038
|
parts.push(`\`\`\`markdown
|
|
13923
14039
|
${truncatedContent}
|
|
13924
14040
|
\`\`\`
|
|
13925
14041
|
|
|
14042
|
+
`);
|
|
14043
|
+
}
|
|
14044
|
+
}
|
|
14045
|
+
if (orchestratorContext.realContext) {
|
|
14046
|
+
const rc = orchestratorContext.realContext;
|
|
14047
|
+
parts.push("### CODEBASE CONTEXT (Real \u2014 gathered proactively)\n\n");
|
|
14048
|
+
parts.push(`**Git State**: Branch \`${rc.gitBranch}\` | ${rc.gitStatus}
|
|
14049
|
+
|
|
14050
|
+
`);
|
|
14051
|
+
if (rc.relevantFiles.length > 0) {
|
|
14052
|
+
parts.push("**Relevant Files** (scored by task relevance):\n");
|
|
14053
|
+
parts.push("| Score | File | Why |\n");
|
|
14054
|
+
parts.push("|-------|------|-----|\n");
|
|
14055
|
+
for (const f of rc.relevantFiles.slice(0, 8)) {
|
|
14056
|
+
parts.push(`| ${f.score} | ${f.path} | ${f.reason} |
|
|
14057
|
+
`);
|
|
14058
|
+
}
|
|
14059
|
+
parts.push("\n");
|
|
14060
|
+
}
|
|
14061
|
+
if (rc.signatures.length > 0) {
|
|
14062
|
+
parts.push("**Code Signatures** (top files):\n");
|
|
14063
|
+
for (const sig of rc.signatures) {
|
|
14064
|
+
parts.push(`\`\`\`typescript
|
|
14065
|
+
// ${sig.path}
|
|
14066
|
+
${sig.content}
|
|
14067
|
+
\`\`\`
|
|
14068
|
+
`);
|
|
14069
|
+
}
|
|
14070
|
+
parts.push("\n");
|
|
14071
|
+
}
|
|
14072
|
+
if (rc.recentFiles.length > 0) {
|
|
14073
|
+
parts.push("**Recently Changed**: ");
|
|
14074
|
+
const recentSummary = rc.recentFiles.slice(0, 5).map((f) => `${f.path} (${f.lastChanged})`).join(", ");
|
|
14075
|
+
parts.push(`${recentSummary}
|
|
14076
|
+
|
|
13926
14077
|
`);
|
|
13927
14078
|
}
|
|
13928
14079
|
}
|
|
@@ -14401,12 +14552,12 @@ When fragmenting tasks:
|
|
|
14401
14552
|
// core/agentic/tool-registry.ts
|
|
14402
14553
|
import { exec as exec7 } from "node:child_process";
|
|
14403
14554
|
import fs29 from "node:fs/promises";
|
|
14404
|
-
import { promisify as
|
|
14405
|
-
var
|
|
14555
|
+
import { promisify as promisify8 } from "node:util";
|
|
14556
|
+
var execAsync4, toolRegistry, tool_registry_default;
|
|
14406
14557
|
var init_tool_registry = __esm({
|
|
14407
14558
|
"core/agentic/tool-registry.ts"() {
|
|
14408
14559
|
"use strict";
|
|
14409
|
-
|
|
14560
|
+
execAsync4 = promisify8(exec7);
|
|
14410
14561
|
toolRegistry = {
|
|
14411
14562
|
tools: /* @__PURE__ */ new Map(),
|
|
14412
14563
|
/**
|
|
@@ -14461,7 +14612,7 @@ var init_tool_registry = __esm({
|
|
|
14461
14612
|
"Bash",
|
|
14462
14613
|
async (command) => {
|
|
14463
14614
|
try {
|
|
14464
|
-
const { stdout, stderr } = await
|
|
14615
|
+
const { stdout, stderr } = await execAsync4(command);
|
|
14465
14616
|
return { stdout, stderr };
|
|
14466
14617
|
} catch (error) {
|
|
14467
14618
|
const err = error;
|
|
@@ -15567,11 +15718,12 @@ var init_breakdown_service = __esm({
|
|
|
15567
15718
|
});
|
|
15568
15719
|
|
|
15569
15720
|
// core/services/context-selector.ts
|
|
15570
|
-
var DOMAIN_KEYWORDS3, ContextSelector, contextSelector;
|
|
15721
|
+
var DEFAULT_TOKEN_BUDGET, DOMAIN_KEYWORDS3, ContextSelector, contextSelector;
|
|
15571
15722
|
var init_context_selector = __esm({
|
|
15572
15723
|
"core/services/context-selector.ts"() {
|
|
15573
15724
|
"use strict";
|
|
15574
15725
|
init_index_storage();
|
|
15726
|
+
DEFAULT_TOKEN_BUDGET = 8e4;
|
|
15575
15727
|
DOMAIN_KEYWORDS3 = {
|
|
15576
15728
|
payments: [
|
|
15577
15729
|
"payment",
|
|
@@ -15694,7 +15846,7 @@ var init_context_selector = __esm({
|
|
|
15694
15846
|
const maxFiles = options.maxFiles || 50;
|
|
15695
15847
|
const minScore = options.minScore || 30;
|
|
15696
15848
|
const includeGeneral = options.includeGeneral !== false;
|
|
15697
|
-
const tokenBudget = options.tokenBudget ||
|
|
15849
|
+
const tokenBudget = options.tokenBudget || DEFAULT_TOKEN_BUDGET;
|
|
15698
15850
|
const [index, domainsData, categoriesCache] = await Promise.all([
|
|
15699
15851
|
indexStorage.readIndex(projectId),
|
|
15700
15852
|
indexStorage.readDomains(projectId),
|
|
@@ -15820,7 +15972,7 @@ var init_context_selector = __esm({
|
|
|
15820
15972
|
fallbackSelection(files, options) {
|
|
15821
15973
|
const maxFiles = options.maxFiles || 50;
|
|
15822
15974
|
const minScore = options.minScore || 30;
|
|
15823
|
-
const tokenBudget = options.tokenBudget ||
|
|
15975
|
+
const tokenBudget = options.tokenBudget || DEFAULT_TOKEN_BUDGET;
|
|
15824
15976
|
const filteredFiles = files.filter((f) => f.score >= minScore).sort((a, b) => b.score - a.score);
|
|
15825
15977
|
let estimatedTokens = 0;
|
|
15826
15978
|
const selectedFiles = [];
|
|
@@ -16597,14 +16749,14 @@ ${hints}`
|
|
|
16597
16749
|
|
|
16598
16750
|
// core/services/git-analyzer.ts
|
|
16599
16751
|
import { exec as exec8 } from "node:child_process";
|
|
16600
|
-
import { promisify as
|
|
16601
|
-
var
|
|
16752
|
+
import { promisify as promisify9 } from "node:util";
|
|
16753
|
+
var execAsync5;
|
|
16602
16754
|
var init_git_analyzer = __esm({
|
|
16603
16755
|
"core/services/git-analyzer.ts"() {
|
|
16604
16756
|
"use strict";
|
|
16605
16757
|
init_constants();
|
|
16606
16758
|
init_dependency_validator();
|
|
16607
|
-
|
|
16759
|
+
execAsync5 = promisify9(exec8);
|
|
16608
16760
|
}
|
|
16609
16761
|
});
|
|
16610
16762
|
|
|
@@ -17280,15 +17432,15 @@ ${agent.description}`;
|
|
|
17280
17432
|
|
|
17281
17433
|
// core/services/project-index.ts
|
|
17282
17434
|
import { exec as exec9 } from "node:child_process";
|
|
17283
|
-
import { promisify as
|
|
17284
|
-
var
|
|
17435
|
+
import { promisify as promisify10 } from "node:util";
|
|
17436
|
+
var execAsync6;
|
|
17285
17437
|
var init_project_index = __esm({
|
|
17286
17438
|
"core/services/project-index.ts"() {
|
|
17287
17439
|
"use strict";
|
|
17288
17440
|
init_index_storage();
|
|
17289
17441
|
init_date_helper();
|
|
17290
17442
|
init_file_scorer();
|
|
17291
|
-
|
|
17443
|
+
execAsync6 = promisify10(exec9);
|
|
17292
17444
|
}
|
|
17293
17445
|
});
|
|
17294
17446
|
|
|
@@ -17761,16 +17913,16 @@ var init_onboarding = __esm({
|
|
|
17761
17913
|
* Detect project type from file system
|
|
17762
17914
|
*/
|
|
17763
17915
|
async detectProjectType() {
|
|
17764
|
-
const
|
|
17765
|
-
const
|
|
17916
|
+
const fs51 = await import("node:fs/promises");
|
|
17917
|
+
const path64 = await import("node:path");
|
|
17766
17918
|
try {
|
|
17767
|
-
const files = await
|
|
17919
|
+
const files = await fs51.readdir(this.projectPath);
|
|
17768
17920
|
if (files.includes("turbo.json") || files.includes("lerna.json") || files.includes("nx.json")) {
|
|
17769
17921
|
return "monorepo";
|
|
17770
17922
|
}
|
|
17771
17923
|
if (files.includes("package.json")) {
|
|
17772
|
-
const pkgPath =
|
|
17773
|
-
const pkgContent = await
|
|
17924
|
+
const pkgPath = path64.join(this.projectPath, "package.json");
|
|
17925
|
+
const pkgContent = await fs51.readFile(pkgPath, "utf-8");
|
|
17774
17926
|
const pkg = JSON.parse(pkgContent);
|
|
17775
17927
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
17776
17928
|
if (pkg.bin) return "cli-tool";
|
|
@@ -17806,32 +17958,32 @@ var init_onboarding = __esm({
|
|
|
17806
17958
|
* Detect installed AI agents from config files
|
|
17807
17959
|
*/
|
|
17808
17960
|
async detectInstalledAgents() {
|
|
17809
|
-
const
|
|
17810
|
-
const
|
|
17811
|
-
const
|
|
17961
|
+
const fs51 = await import("node:fs/promises");
|
|
17962
|
+
const path64 = await import("node:path");
|
|
17963
|
+
const os20 = await import("node:os");
|
|
17812
17964
|
const agents = [];
|
|
17813
17965
|
try {
|
|
17814
|
-
await
|
|
17966
|
+
await fs51.access(path64.join(os20.homedir(), ".claude"));
|
|
17815
17967
|
agents.push("claude");
|
|
17816
17968
|
} catch {
|
|
17817
17969
|
}
|
|
17818
17970
|
try {
|
|
17819
|
-
await
|
|
17971
|
+
await fs51.access(path64.join(this.projectPath, ".cursorrules"));
|
|
17820
17972
|
agents.push("cursor");
|
|
17821
17973
|
} catch {
|
|
17822
17974
|
}
|
|
17823
17975
|
try {
|
|
17824
|
-
await
|
|
17976
|
+
await fs51.access(path64.join(this.projectPath, ".windsurfrules"));
|
|
17825
17977
|
agents.push("windsurf");
|
|
17826
17978
|
} catch {
|
|
17827
17979
|
}
|
|
17828
17980
|
try {
|
|
17829
|
-
await
|
|
17981
|
+
await fs51.access(path64.join(this.projectPath, ".github", "copilot-instructions.md"));
|
|
17830
17982
|
agents.push("copilot");
|
|
17831
17983
|
} catch {
|
|
17832
17984
|
}
|
|
17833
17985
|
try {
|
|
17834
|
-
await
|
|
17986
|
+
await fs51.access(path64.join(os20.homedir(), ".gemini"));
|
|
17835
17987
|
agents.push("gemini");
|
|
17836
17988
|
} catch {
|
|
17837
17989
|
}
|
|
@@ -17841,17 +17993,17 @@ var init_onboarding = __esm({
|
|
|
17841
17993
|
* Detect tech stack from project files
|
|
17842
17994
|
*/
|
|
17843
17995
|
async detectStack() {
|
|
17844
|
-
const
|
|
17845
|
-
const
|
|
17996
|
+
const fs51 = await import("node:fs/promises");
|
|
17997
|
+
const path64 = await import("node:path");
|
|
17846
17998
|
const stack = {
|
|
17847
17999
|
language: "Unknown",
|
|
17848
18000
|
technologies: []
|
|
17849
18001
|
};
|
|
17850
18002
|
try {
|
|
17851
|
-
const files = await
|
|
18003
|
+
const files = await fs51.readdir(this.projectPath);
|
|
17852
18004
|
if (files.includes("package.json")) {
|
|
17853
|
-
const pkgPath =
|
|
17854
|
-
const pkgContent = await
|
|
18005
|
+
const pkgPath = path64.join(this.projectPath, "package.json");
|
|
18006
|
+
const pkgContent = await fs51.readFile(pkgPath, "utf-8");
|
|
17855
18007
|
const pkg = JSON.parse(pkgContent);
|
|
17856
18008
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
17857
18009
|
stack.language = deps.typescript ? "TypeScript" : "JavaScript";
|
|
@@ -17960,7 +18112,7 @@ var init_wizard = __esm({
|
|
|
17960
18112
|
import { exec as exec10 } from "node:child_process";
|
|
17961
18113
|
import fs34 from "node:fs/promises";
|
|
17962
18114
|
import path36 from "node:path";
|
|
17963
|
-
import { promisify as
|
|
18115
|
+
import { promisify as promisify11 } from "node:util";
|
|
17964
18116
|
async function generateContext(projectId, repoPath) {
|
|
17965
18117
|
const _globalPath = path_manager_default.getGlobalProjectPath(projectId);
|
|
17966
18118
|
const contextPath = path_manager_default.getContextPath(projectId);
|
|
@@ -18018,17 +18170,17 @@ async function getGitData(repoPath) {
|
|
|
18018
18170
|
recentCommits: []
|
|
18019
18171
|
};
|
|
18020
18172
|
try {
|
|
18021
|
-
const { stdout: branch } = await
|
|
18173
|
+
const { stdout: branch } = await execAsync7("git branch --show-current", { cwd: repoPath });
|
|
18022
18174
|
data.branch = branch.trim() || "main";
|
|
18023
|
-
const { stdout: commits } = await
|
|
18175
|
+
const { stdout: commits } = await execAsync7("git rev-list --count HEAD", { cwd: repoPath });
|
|
18024
18176
|
data.commits = parseInt(commits.trim(), 10) || 0;
|
|
18025
|
-
const { stdout: contributors } = await
|
|
18177
|
+
const { stdout: contributors } = await execAsync7("git shortlog -sn --all | wc -l", {
|
|
18026
18178
|
cwd: repoPath
|
|
18027
18179
|
});
|
|
18028
18180
|
data.contributors = parseInt(contributors.trim(), 10) || 0;
|
|
18029
|
-
const { stdout: status } = await
|
|
18181
|
+
const { stdout: status } = await execAsync7("git status --porcelain", { cwd: repoPath });
|
|
18030
18182
|
data.hasChanges = status.trim().length > 0;
|
|
18031
|
-
const { stdout: log } = await
|
|
18183
|
+
const { stdout: log } = await execAsync7(
|
|
18032
18184
|
'git log --oneline -10 --pretty=format:"%h|%s|%ad" --date=short',
|
|
18033
18185
|
{ cwd: repoPath }
|
|
18034
18186
|
);
|
|
@@ -18177,13 +18329,13 @@ async function generateSummaryMd(contextPath, project, gitData, pkgData) {
|
|
|
18177
18329
|
`;
|
|
18178
18330
|
await fs34.writeFile(path36.join(contextPath, "summary.md"), content, "utf-8");
|
|
18179
18331
|
}
|
|
18180
|
-
var
|
|
18332
|
+
var execAsync7;
|
|
18181
18333
|
var init_generator = __esm({
|
|
18182
18334
|
"core/context/generator.ts"() {
|
|
18183
18335
|
"use strict";
|
|
18184
18336
|
init_path_manager();
|
|
18185
18337
|
init_storage2();
|
|
18186
|
-
|
|
18338
|
+
execAsync7 = promisify11(exec10);
|
|
18187
18339
|
__name(generateContext, "generateContext");
|
|
18188
18340
|
__name(getGitData, "getGitData");
|
|
18189
18341
|
__name(getPackageData, "getPackageData");
|
|
@@ -18195,16 +18347,16 @@ var init_generator = __esm({
|
|
|
18195
18347
|
});
|
|
18196
18348
|
|
|
18197
18349
|
// core/domain/analyzer.ts
|
|
18198
|
-
import { exec as
|
|
18350
|
+
import { exec as execCallback6 } from "node:child_process";
|
|
18199
18351
|
import fs35 from "node:fs/promises";
|
|
18200
18352
|
import path37 from "node:path";
|
|
18201
|
-
import { promisify as
|
|
18353
|
+
import { promisify as promisify12 } from "node:util";
|
|
18202
18354
|
var exec11, CodebaseAnalyzer, analyzer, analyzer_default2;
|
|
18203
18355
|
var init_analyzer2 = __esm({
|
|
18204
18356
|
"core/domain/analyzer.ts"() {
|
|
18205
18357
|
"use strict";
|
|
18206
18358
|
init_fs();
|
|
18207
|
-
exec11 =
|
|
18359
|
+
exec11 = promisify12(execCallback6);
|
|
18208
18360
|
CodebaseAnalyzer = class {
|
|
18209
18361
|
static {
|
|
18210
18362
|
__name(this, "CodebaseAnalyzer");
|
|
@@ -19132,6 +19284,11 @@ ${formatFullDiff(diff)}`);
|
|
|
19132
19284
|
const skillWord = result.skills.length === 1 ? "skill" : "skills";
|
|
19133
19285
|
generatedItems.push(`${result.skills.length} ${skillWord}`);
|
|
19134
19286
|
}
|
|
19287
|
+
const installed = result.skillsInstalled?.filter((s) => s.status === "installed") || [];
|
|
19288
|
+
if (installed.length > 0) {
|
|
19289
|
+
const word = installed.length === 1 ? "skill" : "skills";
|
|
19290
|
+
generatedItems.push(`${installed.length} ${word} auto-installed`);
|
|
19291
|
+
}
|
|
19135
19292
|
output_default.section("Generated");
|
|
19136
19293
|
output_default.list(generatedItems, { bullet: "\u2713" });
|
|
19137
19294
|
console.log("");
|
|
@@ -19969,8 +20126,8 @@ Generated: ${(/* @__PURE__ */ new Date()).toLocaleString()}
|
|
|
19969
20126
|
const globalPath2 = path_manager_default.getGlobalProjectPath(projectId);
|
|
19970
20127
|
const specsPath2 = path39.join(globalPath2, "planning", "specs");
|
|
19971
20128
|
try {
|
|
19972
|
-
const
|
|
19973
|
-
const files = await
|
|
20129
|
+
const fs51 = await import("node:fs/promises");
|
|
20130
|
+
const files = await fs51.readdir(specsPath2);
|
|
19974
20131
|
const specs = files.filter((f) => f.endsWith(".md") && f !== ".gitkeep");
|
|
19975
20132
|
if (specs.length === 0) {
|
|
19976
20133
|
output_default.warn("no specs yet");
|
|
@@ -20186,14 +20343,14 @@ var init_project_service = __esm({
|
|
|
20186
20343
|
import { exec as exec12 } from "node:child_process";
|
|
20187
20344
|
import fs37 from "node:fs/promises";
|
|
20188
20345
|
import path40 from "node:path";
|
|
20189
|
-
import { promisify as
|
|
20190
|
-
var
|
|
20346
|
+
import { promisify as promisify13 } from "node:util";
|
|
20347
|
+
var execAsync8, DEFAULT_CONFIG, StalenessChecker, createStalenessChecker;
|
|
20191
20348
|
var init_staleness_checker = __esm({
|
|
20192
20349
|
"core/services/staleness-checker.ts"() {
|
|
20193
20350
|
"use strict";
|
|
20194
20351
|
init_path_manager();
|
|
20195
20352
|
init_session_tracker();
|
|
20196
|
-
|
|
20353
|
+
execAsync8 = promisify13(exec12);
|
|
20197
20354
|
DEFAULT_CONFIG = {
|
|
20198
20355
|
commitThreshold: 10,
|
|
20199
20356
|
dayThreshold: 3,
|
|
@@ -20246,7 +20403,7 @@ var init_staleness_checker = __esm({
|
|
|
20246
20403
|
status.lastSyncCommit = projectJson.lastSyncCommit || null;
|
|
20247
20404
|
const lastSync = projectJson.lastSync;
|
|
20248
20405
|
try {
|
|
20249
|
-
const { stdout } = await
|
|
20406
|
+
const { stdout } = await execAsync8("git rev-parse --short HEAD", {
|
|
20250
20407
|
cwd: this.projectPath
|
|
20251
20408
|
});
|
|
20252
20409
|
status.currentCommit = stdout.trim();
|
|
@@ -20264,7 +20421,7 @@ var init_staleness_checker = __esm({
|
|
|
20264
20421
|
return status;
|
|
20265
20422
|
}
|
|
20266
20423
|
try {
|
|
20267
|
-
const { stdout } = await
|
|
20424
|
+
const { stdout } = await execAsync8(`git rev-list --count ${status.lastSyncCommit}..HEAD`, {
|
|
20268
20425
|
cwd: this.projectPath
|
|
20269
20426
|
});
|
|
20270
20427
|
status.commitsSinceSync = parseInt(stdout.trim(), 10) || 0;
|
|
@@ -20281,7 +20438,7 @@ var init_staleness_checker = __esm({
|
|
|
20281
20438
|
);
|
|
20282
20439
|
}
|
|
20283
20440
|
try {
|
|
20284
|
-
const { stdout } = await
|
|
20441
|
+
const { stdout } = await execAsync8(`git diff --name-only ${status.lastSyncCommit}..HEAD`, {
|
|
20285
20442
|
cwd: this.projectPath
|
|
20286
20443
|
});
|
|
20287
20444
|
status.changedFiles = stdout.trim().split("\n").filter(Boolean);
|
|
@@ -20700,13 +20857,13 @@ var init_formatters = __esm({
|
|
|
20700
20857
|
import { exec as exec13 } from "node:child_process";
|
|
20701
20858
|
import os11 from "node:os";
|
|
20702
20859
|
import path41 from "node:path";
|
|
20703
|
-
import { promisify as
|
|
20860
|
+
import { promisify as promisify14 } from "node:util";
|
|
20704
20861
|
function getAIToolConfig(id) {
|
|
20705
20862
|
return AI_TOOLS[id] || null;
|
|
20706
20863
|
}
|
|
20707
20864
|
async function commandExists(cmd) {
|
|
20708
20865
|
try {
|
|
20709
|
-
await
|
|
20866
|
+
await execAsync9(`which ${cmd}`);
|
|
20710
20867
|
return true;
|
|
20711
20868
|
} catch {
|
|
20712
20869
|
return false;
|
|
@@ -20741,19 +20898,19 @@ async function resolveToolIds(mode, repoPath = process.cwd()) {
|
|
|
20741
20898
|
}
|
|
20742
20899
|
return mode.filter((id) => AI_TOOLS[id]);
|
|
20743
20900
|
}
|
|
20744
|
-
var
|
|
20901
|
+
var execAsync9, AI_TOOLS, DEFAULT_AI_TOOLS, SUPPORTED_AI_TOOLS;
|
|
20745
20902
|
var init_registry = __esm({
|
|
20746
20903
|
"core/ai-tools/registry.ts"() {
|
|
20747
20904
|
"use strict";
|
|
20748
20905
|
init_fs_helpers();
|
|
20749
|
-
|
|
20906
|
+
execAsync9 = promisify14(exec13);
|
|
20750
20907
|
AI_TOOLS = {
|
|
20751
20908
|
claude: {
|
|
20752
20909
|
id: "claude",
|
|
20753
20910
|
name: "Claude Code",
|
|
20754
20911
|
outputFile: "CLAUDE.md",
|
|
20755
20912
|
outputPath: "global",
|
|
20756
|
-
maxTokens:
|
|
20913
|
+
maxTokens: 6e3,
|
|
20757
20914
|
format: "detailed",
|
|
20758
20915
|
description: "Anthropic Claude Code CLI"
|
|
20759
20916
|
},
|
|
@@ -20895,6 +21052,45 @@ var init_ai_tools = __esm({
|
|
|
20895
21052
|
}
|
|
20896
21053
|
});
|
|
20897
21054
|
|
|
21055
|
+
// core/utils/logger.ts
|
|
21056
|
+
function getLogLevel() {
|
|
21057
|
+
const debugEnv = process.env.PRJCT_DEBUG || process.env.DEBUG || "";
|
|
21058
|
+
if (!debugEnv) return { level: -1, name: "disabled" };
|
|
21059
|
+
if (TRUTHY_VALUES.has(debugEnv) || debugEnv.includes("prjct")) {
|
|
21060
|
+
return { level: LEVELS.debug, name: "debug" };
|
|
21061
|
+
}
|
|
21062
|
+
const levelValue = LEVELS[debugEnv] ?? -1;
|
|
21063
|
+
const levelName = levelValue >= 0 ? debugEnv : "disabled";
|
|
21064
|
+
return { level: levelValue, name: levelName };
|
|
21065
|
+
}
|
|
21066
|
+
function createLogMethod(levelThreshold, prefix, method) {
|
|
21067
|
+
return currentLevel >= levelThreshold ? (...args2) => console[method](prefix, ...args2) : noop;
|
|
21068
|
+
}
|
|
21069
|
+
var LEVELS, TRUTHY_VALUES, currentLevel, currentLevelName, noop, logger2, logger_default;
|
|
21070
|
+
var init_logger = __esm({
|
|
21071
|
+
"core/utils/logger.ts"() {
|
|
21072
|
+
"use strict";
|
|
21073
|
+
LEVELS = { error: 0, warn: 1, info: 2, debug: 3 };
|
|
21074
|
+
TRUTHY_VALUES = /* @__PURE__ */ new Set(["1", "true", "*"]);
|
|
21075
|
+
__name(getLogLevel, "getLogLevel");
|
|
21076
|
+
({ level: currentLevel, name: currentLevelName } = getLogLevel());
|
|
21077
|
+
noop = /* @__PURE__ */ __name(() => {
|
|
21078
|
+
}, "noop");
|
|
21079
|
+
__name(createLogMethod, "createLogMethod");
|
|
21080
|
+
logger2 = {
|
|
21081
|
+
error: createLogMethod(LEVELS.error, "[prjct:error]", "error"),
|
|
21082
|
+
warn: createLogMethod(LEVELS.warn, "[prjct:warn]", "warn"),
|
|
21083
|
+
info: createLogMethod(LEVELS.info, "[prjct:info]", "log"),
|
|
21084
|
+
debug: createLogMethod(LEVELS.debug, "[prjct:debug]", "log"),
|
|
21085
|
+
// Check if logging is enabled (useful for expensive log prep)
|
|
21086
|
+
isEnabled: /* @__PURE__ */ __name(() => currentLevel >= 0, "isEnabled"),
|
|
21087
|
+
// Get current level name (pre-computed, no runtime lookup)
|
|
21088
|
+
level: /* @__PURE__ */ __name(() => currentLevelName, "level")
|
|
21089
|
+
};
|
|
21090
|
+
logger_default = logger2;
|
|
21091
|
+
}
|
|
21092
|
+
});
|
|
21093
|
+
|
|
20898
21094
|
// core/services/context-generator.ts
|
|
20899
21095
|
import fs39 from "node:fs/promises";
|
|
20900
21096
|
import path43 from "node:path";
|
|
@@ -21343,9 +21539,364 @@ var init_local_state_generator = __esm({
|
|
|
21343
21539
|
}
|
|
21344
21540
|
});
|
|
21345
21541
|
|
|
21346
|
-
// core/services/
|
|
21542
|
+
// core/services/skill-lock.ts
|
|
21347
21543
|
import fs41 from "node:fs/promises";
|
|
21544
|
+
import os12 from "node:os";
|
|
21348
21545
|
import path45 from "node:path";
|
|
21546
|
+
function getLockFilePath() {
|
|
21547
|
+
return path45.join(os12.homedir(), ".prjct-cli", "skills", LOCK_FILE_NAME);
|
|
21548
|
+
}
|
|
21549
|
+
function createEmptyLockFile() {
|
|
21550
|
+
return {
|
|
21551
|
+
version: 1,
|
|
21552
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
21553
|
+
skills: {}
|
|
21554
|
+
};
|
|
21555
|
+
}
|
|
21556
|
+
async function read() {
|
|
21557
|
+
try {
|
|
21558
|
+
const content = await fs41.readFile(getLockFilePath(), "utf-8");
|
|
21559
|
+
return JSON.parse(content);
|
|
21560
|
+
} catch {
|
|
21561
|
+
return createEmptyLockFile();
|
|
21562
|
+
}
|
|
21563
|
+
}
|
|
21564
|
+
async function write(lockFile) {
|
|
21565
|
+
const lockPath = getLockFilePath();
|
|
21566
|
+
await fs41.mkdir(path45.dirname(lockPath), { recursive: true });
|
|
21567
|
+
lockFile.generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21568
|
+
await fs41.writeFile(lockPath, JSON.stringify(lockFile, null, 2), "utf-8");
|
|
21569
|
+
}
|
|
21570
|
+
async function addEntry(entry) {
|
|
21571
|
+
const lockFile = await read();
|
|
21572
|
+
lockFile.skills[entry.name] = entry;
|
|
21573
|
+
await write(lockFile);
|
|
21574
|
+
}
|
|
21575
|
+
async function removeEntry(name) {
|
|
21576
|
+
const lockFile = await read();
|
|
21577
|
+
if (!(name in lockFile.skills)) return false;
|
|
21578
|
+
delete lockFile.skills[name];
|
|
21579
|
+
await write(lockFile);
|
|
21580
|
+
return true;
|
|
21581
|
+
}
|
|
21582
|
+
async function getEntry(name) {
|
|
21583
|
+
const lockFile = await read();
|
|
21584
|
+
return lockFile.skills[name] || null;
|
|
21585
|
+
}
|
|
21586
|
+
async function getAll() {
|
|
21587
|
+
const lockFile = await read();
|
|
21588
|
+
return lockFile.skills;
|
|
21589
|
+
}
|
|
21590
|
+
function getPath() {
|
|
21591
|
+
return getLockFilePath();
|
|
21592
|
+
}
|
|
21593
|
+
var LOCK_FILE_NAME, skillLock;
|
|
21594
|
+
var init_skill_lock = __esm({
|
|
21595
|
+
"core/services/skill-lock.ts"() {
|
|
21596
|
+
"use strict";
|
|
21597
|
+
LOCK_FILE_NAME = ".skill-lock.json";
|
|
21598
|
+
__name(getLockFilePath, "getLockFilePath");
|
|
21599
|
+
__name(createEmptyLockFile, "createEmptyLockFile");
|
|
21600
|
+
__name(read, "read");
|
|
21601
|
+
__name(write, "write");
|
|
21602
|
+
__name(addEntry, "addEntry");
|
|
21603
|
+
__name(removeEntry, "removeEntry");
|
|
21604
|
+
__name(getEntry, "getEntry");
|
|
21605
|
+
__name(getAll, "getAll");
|
|
21606
|
+
__name(getPath, "getPath");
|
|
21607
|
+
skillLock = {
|
|
21608
|
+
read,
|
|
21609
|
+
write,
|
|
21610
|
+
addEntry,
|
|
21611
|
+
removeEntry,
|
|
21612
|
+
getEntry,
|
|
21613
|
+
getAll,
|
|
21614
|
+
getPath
|
|
21615
|
+
};
|
|
21616
|
+
}
|
|
21617
|
+
});
|
|
21618
|
+
|
|
21619
|
+
// core/services/skill-installer.ts
|
|
21620
|
+
import { exec as execCallback7 } from "node:child_process";
|
|
21621
|
+
import fs42 from "node:fs/promises";
|
|
21622
|
+
import os13 from "node:os";
|
|
21623
|
+
import path46 from "node:path";
|
|
21624
|
+
import { promisify as promisify15 } from "node:util";
|
|
21625
|
+
import { glob } from "glob";
|
|
21626
|
+
function parseSource(source) {
|
|
21627
|
+
if (source.startsWith("./") || source.startsWith("/") || source.startsWith("~")) {
|
|
21628
|
+
const resolvedPath = source.startsWith("~") ? path46.join(os13.homedir(), source.slice(1)) : path46.resolve(source);
|
|
21629
|
+
return {
|
|
21630
|
+
type: "local",
|
|
21631
|
+
localPath: resolvedPath,
|
|
21632
|
+
url: resolvedPath
|
|
21633
|
+
};
|
|
21634
|
+
}
|
|
21635
|
+
const atIndex = source.indexOf("@");
|
|
21636
|
+
if (atIndex > 0) {
|
|
21637
|
+
const repoPath = source.slice(0, atIndex);
|
|
21638
|
+
const skillName = source.slice(atIndex + 1);
|
|
21639
|
+
const [owner, repo] = repoPath.split("/");
|
|
21640
|
+
if (owner && repo) {
|
|
21641
|
+
return {
|
|
21642
|
+
type: "github",
|
|
21643
|
+
owner,
|
|
21644
|
+
repo,
|
|
21645
|
+
skillName,
|
|
21646
|
+
url: `https://github.com/${owner}/${repo}`
|
|
21647
|
+
};
|
|
21648
|
+
}
|
|
21649
|
+
}
|
|
21650
|
+
const parts = source.split("/");
|
|
21651
|
+
if (parts.length === 2 && parts[0] && parts[1]) {
|
|
21652
|
+
return {
|
|
21653
|
+
type: "github",
|
|
21654
|
+
owner: parts[0],
|
|
21655
|
+
repo: parts[1],
|
|
21656
|
+
url: `https://github.com/${parts[0]}/${parts[1]}`
|
|
21657
|
+
};
|
|
21658
|
+
}
|
|
21659
|
+
throw new Error(
|
|
21660
|
+
`Invalid source format: "${source}". Expected "owner/repo", "owner/repo@skill-name", or "./local-path"`
|
|
21661
|
+
);
|
|
21662
|
+
}
|
|
21663
|
+
async function discoverSkills(dir) {
|
|
21664
|
+
const skills = [];
|
|
21665
|
+
try {
|
|
21666
|
+
const rootSkill = path46.join(dir, "SKILL.md");
|
|
21667
|
+
await fs42.access(rootSkill);
|
|
21668
|
+
const dirName = path46.basename(dir);
|
|
21669
|
+
skills.push({ name: dirName, filePath: rootSkill });
|
|
21670
|
+
} catch {
|
|
21671
|
+
}
|
|
21672
|
+
const subdirSkills = await glob("*/SKILL.md", { cwd: dir, absolute: true });
|
|
21673
|
+
for (const filePath of subdirSkills) {
|
|
21674
|
+
const name = path46.basename(path46.dirname(filePath));
|
|
21675
|
+
if (!skills.some((s) => s.name === name)) {
|
|
21676
|
+
skills.push({ name, filePath });
|
|
21677
|
+
}
|
|
21678
|
+
}
|
|
21679
|
+
const nestedSkills = await glob("skills/*/SKILL.md", { cwd: dir, absolute: true });
|
|
21680
|
+
for (const filePath of nestedSkills) {
|
|
21681
|
+
const name = path46.basename(path46.dirname(filePath));
|
|
21682
|
+
if (!skills.some((s) => s.name === name)) {
|
|
21683
|
+
skills.push({ name, filePath });
|
|
21684
|
+
}
|
|
21685
|
+
}
|
|
21686
|
+
return skills;
|
|
21687
|
+
}
|
|
21688
|
+
function injectSourceMetadata(content, source, sha) {
|
|
21689
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
21690
|
+
const prjctBlock = [
|
|
21691
|
+
`_prjct:`,
|
|
21692
|
+
` sourceUrl: ${source.url}`,
|
|
21693
|
+
` sourceType: ${source.type}`,
|
|
21694
|
+
` installedAt: ${now}`
|
|
21695
|
+
];
|
|
21696
|
+
if (sha) {
|
|
21697
|
+
prjctBlock.push(` sha: ${sha}`);
|
|
21698
|
+
}
|
|
21699
|
+
const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---/;
|
|
21700
|
+
const match = content.match(frontmatterRegex);
|
|
21701
|
+
if (match) {
|
|
21702
|
+
let frontmatter = match[1];
|
|
21703
|
+
frontmatter = frontmatter.replace(/\n?_prjct:[\s\S]*?(?=\n[a-zA-Z]|\n---|\s*$)/g, "");
|
|
21704
|
+
const updatedFrontmatter = `${frontmatter.trimEnd()}
|
|
21705
|
+
${prjctBlock.join("\n")}`;
|
|
21706
|
+
return content.replace(frontmatterRegex, `---
|
|
21707
|
+
${updatedFrontmatter}
|
|
21708
|
+
---`);
|
|
21709
|
+
}
|
|
21710
|
+
return `---
|
|
21711
|
+
${prjctBlock.join("\n")}
|
|
21712
|
+
---
|
|
21713
|
+
|
|
21714
|
+
${content}`;
|
|
21715
|
+
}
|
|
21716
|
+
function getInstallDir() {
|
|
21717
|
+
return path46.join(os13.homedir(), ".claude", "skills");
|
|
21718
|
+
}
|
|
21719
|
+
async function installSkillFile(sourcePath, name, source, sha) {
|
|
21720
|
+
const installDir = getInstallDir();
|
|
21721
|
+
const targetDir = path46.join(installDir, name);
|
|
21722
|
+
const targetPath = path46.join(targetDir, "SKILL.md");
|
|
21723
|
+
const content = await fs42.readFile(sourcePath, "utf-8");
|
|
21724
|
+
const enrichedContent = injectSourceMetadata(content, source, sha);
|
|
21725
|
+
await fs42.mkdir(targetDir, { recursive: true });
|
|
21726
|
+
await fs42.writeFile(targetPath, enrichedContent, "utf-8");
|
|
21727
|
+
return {
|
|
21728
|
+
name,
|
|
21729
|
+
filePath: targetPath,
|
|
21730
|
+
source,
|
|
21731
|
+
sha
|
|
21732
|
+
};
|
|
21733
|
+
}
|
|
21734
|
+
async function installFromGitHub(source) {
|
|
21735
|
+
const result = { installed: [], skipped: [], errors: [] };
|
|
21736
|
+
if (!dependencyValidator.isAvailable("git")) {
|
|
21737
|
+
const gitStatus = dependencyValidator.checkTool("git");
|
|
21738
|
+
result.errors.push(
|
|
21739
|
+
`Cannot install from GitHub: git is not available. ${gitStatus.error?.hint || "Install git and try again."}`
|
|
21740
|
+
);
|
|
21741
|
+
return result;
|
|
21742
|
+
}
|
|
21743
|
+
const tmpDir = path46.join(os13.tmpdir(), `prjct-skill-${Date.now()}`);
|
|
21744
|
+
try {
|
|
21745
|
+
const cloneUrl = `https://github.com/${source.owner}/${source.repo}.git`;
|
|
21746
|
+
await exec14(`git clone --depth 1 ${cloneUrl} ${tmpDir}`, { timeout: getTimeout("GIT_CLONE") });
|
|
21747
|
+
let sha;
|
|
21748
|
+
try {
|
|
21749
|
+
const { stdout } = await exec14("git rev-parse HEAD", {
|
|
21750
|
+
cwd: tmpDir,
|
|
21751
|
+
timeout: getTimeout("TOOL_CHECK")
|
|
21752
|
+
});
|
|
21753
|
+
sha = stdout.trim();
|
|
21754
|
+
} catch {
|
|
21755
|
+
}
|
|
21756
|
+
const discoveredSkills = await discoverSkills(tmpDir);
|
|
21757
|
+
if (discoveredSkills.length === 0) {
|
|
21758
|
+
result.errors.push(`No SKILL.md files found in ${source.owner}/${source.repo}`);
|
|
21759
|
+
return result;
|
|
21760
|
+
}
|
|
21761
|
+
const skillsToInstall = source.skillName ? discoveredSkills.filter((s) => s.name === source.skillName) : discoveredSkills;
|
|
21762
|
+
if (source.skillName && skillsToInstall.length === 0) {
|
|
21763
|
+
result.errors.push(`Skill "${source.skillName}" not found in ${source.owner}/${source.repo}`);
|
|
21764
|
+
return result;
|
|
21765
|
+
}
|
|
21766
|
+
for (const skill of skillsToInstall) {
|
|
21767
|
+
try {
|
|
21768
|
+
const installed = await installSkillFile(skill.filePath, skill.name, source, sha);
|
|
21769
|
+
const lockEntry = {
|
|
21770
|
+
name: skill.name,
|
|
21771
|
+
source: {
|
|
21772
|
+
type: "github",
|
|
21773
|
+
url: `${source.owner}/${source.repo}`,
|
|
21774
|
+
sha
|
|
21775
|
+
},
|
|
21776
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
21777
|
+
filePath: installed.filePath
|
|
21778
|
+
};
|
|
21779
|
+
await skillLock.addEntry(lockEntry);
|
|
21780
|
+
result.installed.push(installed);
|
|
21781
|
+
} catch (error) {
|
|
21782
|
+
result.errors.push(`Failed to install ${skill.name}: ${error.message}`);
|
|
21783
|
+
}
|
|
21784
|
+
}
|
|
21785
|
+
} finally {
|
|
21786
|
+
try {
|
|
21787
|
+
await fs42.rm(tmpDir, { recursive: true, force: true });
|
|
21788
|
+
} catch {
|
|
21789
|
+
}
|
|
21790
|
+
}
|
|
21791
|
+
return result;
|
|
21792
|
+
}
|
|
21793
|
+
async function installFromLocal(source) {
|
|
21794
|
+
const result = { installed: [], skipped: [], errors: [] };
|
|
21795
|
+
const localPath = source.localPath;
|
|
21796
|
+
try {
|
|
21797
|
+
await fs42.access(localPath);
|
|
21798
|
+
} catch {
|
|
21799
|
+
result.errors.push(`Local path not found: ${localPath}`);
|
|
21800
|
+
return result;
|
|
21801
|
+
}
|
|
21802
|
+
const stat = await fs42.stat(localPath);
|
|
21803
|
+
if (stat.isFile()) {
|
|
21804
|
+
const name = path46.basename(path46.dirname(localPath));
|
|
21805
|
+
try {
|
|
21806
|
+
const installed = await installSkillFile(localPath, name, source);
|
|
21807
|
+
const lockEntry = {
|
|
21808
|
+
name,
|
|
21809
|
+
source: { type: "local", url: localPath },
|
|
21810
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
21811
|
+
filePath: installed.filePath
|
|
21812
|
+
};
|
|
21813
|
+
await skillLock.addEntry(lockEntry);
|
|
21814
|
+
result.installed.push(installed);
|
|
21815
|
+
} catch (error) {
|
|
21816
|
+
result.errors.push(`Failed to install from ${localPath}: ${error.message}`);
|
|
21817
|
+
}
|
|
21818
|
+
} else {
|
|
21819
|
+
const discoveredSkills = await discoverSkills(localPath);
|
|
21820
|
+
if (discoveredSkills.length === 0) {
|
|
21821
|
+
result.errors.push(`No SKILL.md files found in ${localPath}`);
|
|
21822
|
+
return result;
|
|
21823
|
+
}
|
|
21824
|
+
for (const skill of discoveredSkills) {
|
|
21825
|
+
try {
|
|
21826
|
+
const installed = await installSkillFile(skill.filePath, skill.name, source);
|
|
21827
|
+
const lockEntry = {
|
|
21828
|
+
name: skill.name,
|
|
21829
|
+
source: { type: "local", url: localPath },
|
|
21830
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
21831
|
+
filePath: installed.filePath
|
|
21832
|
+
};
|
|
21833
|
+
await skillLock.addEntry(lockEntry);
|
|
21834
|
+
result.installed.push(installed);
|
|
21835
|
+
} catch (error) {
|
|
21836
|
+
result.errors.push(`Failed to install ${skill.name}: ${error.message}`);
|
|
21837
|
+
}
|
|
21838
|
+
}
|
|
21839
|
+
}
|
|
21840
|
+
return result;
|
|
21841
|
+
}
|
|
21842
|
+
async function remove(name) {
|
|
21843
|
+
const installDir = getInstallDir();
|
|
21844
|
+
const subdirPath = path46.join(installDir, name);
|
|
21845
|
+
try {
|
|
21846
|
+
await fs42.rm(subdirPath, { recursive: true, force: true });
|
|
21847
|
+
} catch {
|
|
21848
|
+
}
|
|
21849
|
+
const flatPath = path46.join(installDir, `${name}.md`);
|
|
21850
|
+
try {
|
|
21851
|
+
await fs42.rm(flatPath, { force: true });
|
|
21852
|
+
} catch {
|
|
21853
|
+
}
|
|
21854
|
+
return skillLock.removeEntry(name);
|
|
21855
|
+
}
|
|
21856
|
+
async function install(sourceStr) {
|
|
21857
|
+
const source = parseSource(sourceStr);
|
|
21858
|
+
switch (source.type) {
|
|
21859
|
+
case "github":
|
|
21860
|
+
return installFromGitHub(source);
|
|
21861
|
+
case "local":
|
|
21862
|
+
return installFromLocal(source);
|
|
21863
|
+
default:
|
|
21864
|
+
return {
|
|
21865
|
+
installed: [],
|
|
21866
|
+
skipped: [],
|
|
21867
|
+
errors: [`Unsupported source type: ${source.type}`]
|
|
21868
|
+
};
|
|
21869
|
+
}
|
|
21870
|
+
}
|
|
21871
|
+
var exec14, skillInstaller;
|
|
21872
|
+
var init_skill_installer = __esm({
|
|
21873
|
+
"core/services/skill-installer.ts"() {
|
|
21874
|
+
"use strict";
|
|
21875
|
+
init_constants();
|
|
21876
|
+
init_dependency_validator();
|
|
21877
|
+
init_skill_lock();
|
|
21878
|
+
exec14 = promisify15(execCallback7);
|
|
21879
|
+
__name(parseSource, "parseSource");
|
|
21880
|
+
__name(discoverSkills, "discoverSkills");
|
|
21881
|
+
__name(injectSourceMetadata, "injectSourceMetadata");
|
|
21882
|
+
__name(getInstallDir, "getInstallDir");
|
|
21883
|
+
__name(installSkillFile, "installSkillFile");
|
|
21884
|
+
__name(installFromGitHub, "installFromGitHub");
|
|
21885
|
+
__name(installFromLocal, "installFromLocal");
|
|
21886
|
+
__name(remove, "remove");
|
|
21887
|
+
__name(install, "install");
|
|
21888
|
+
skillInstaller = {
|
|
21889
|
+
install,
|
|
21890
|
+
remove,
|
|
21891
|
+
parseSource,
|
|
21892
|
+
getInstallDir
|
|
21893
|
+
};
|
|
21894
|
+
}
|
|
21895
|
+
});
|
|
21896
|
+
|
|
21897
|
+
// core/services/stack-detector.ts
|
|
21898
|
+
import fs43 from "node:fs/promises";
|
|
21899
|
+
import path47 from "node:path";
|
|
21349
21900
|
var StackDetector;
|
|
21350
21901
|
var init_stack_detector = __esm({
|
|
21351
21902
|
"core/services/stack-detector.ts"() {
|
|
@@ -21504,8 +22055,8 @@ var init_stack_detector = __esm({
|
|
|
21504
22055
|
*/
|
|
21505
22056
|
async readPackageJson() {
|
|
21506
22057
|
try {
|
|
21507
|
-
const pkgPath =
|
|
21508
|
-
const content = await
|
|
22058
|
+
const pkgPath = path47.join(this.projectPath, "package.json");
|
|
22059
|
+
const content = await fs43.readFile(pkgPath, "utf-8");
|
|
21509
22060
|
return JSON.parse(content);
|
|
21510
22061
|
} catch {
|
|
21511
22062
|
return null;
|
|
@@ -21516,7 +22067,7 @@ var init_stack_detector = __esm({
|
|
|
21516
22067
|
*/
|
|
21517
22068
|
async fileExists(filename) {
|
|
21518
22069
|
try {
|
|
21519
|
-
await
|
|
22070
|
+
await fs43.access(path47.join(this.projectPath, filename));
|
|
21520
22071
|
return true;
|
|
21521
22072
|
} catch {
|
|
21522
22073
|
return false;
|
|
@@ -21527,16 +22078,16 @@ var init_stack_detector = __esm({
|
|
|
21527
22078
|
});
|
|
21528
22079
|
|
|
21529
22080
|
// core/services/sync-verifier.ts
|
|
21530
|
-
import { exec as
|
|
21531
|
-
import
|
|
21532
|
-
import
|
|
21533
|
-
import { promisify as
|
|
21534
|
-
var
|
|
22081
|
+
import { exec as exec15 } from "node:child_process";
|
|
22082
|
+
import fs44 from "node:fs/promises";
|
|
22083
|
+
import path48 from "node:path";
|
|
22084
|
+
import { promisify as promisify16 } from "node:util";
|
|
22085
|
+
var execAsync10, BUILTIN_CHECKS, SyncVerifier, syncVerifier;
|
|
21535
22086
|
var init_sync_verifier = __esm({
|
|
21536
22087
|
"core/services/sync-verifier.ts"() {
|
|
21537
22088
|
"use strict";
|
|
21538
22089
|
init_fs();
|
|
21539
|
-
|
|
22090
|
+
execAsync10 = promisify16(exec15);
|
|
21540
22091
|
BUILTIN_CHECKS = {
|
|
21541
22092
|
/**
|
|
21542
22093
|
* Verify all expected context files exist after sync
|
|
@@ -21546,9 +22097,9 @@ var init_sync_verifier = __esm({
|
|
|
21546
22097
|
const expected = ["context/CLAUDE.md"];
|
|
21547
22098
|
const missing = [];
|
|
21548
22099
|
for (const file of expected) {
|
|
21549
|
-
const filePath =
|
|
22100
|
+
const filePath = path48.join(globalPath, file);
|
|
21550
22101
|
try {
|
|
21551
|
-
await
|
|
22102
|
+
await fs44.access(filePath);
|
|
21552
22103
|
} catch {
|
|
21553
22104
|
missing.push(file);
|
|
21554
22105
|
}
|
|
@@ -21569,9 +22120,9 @@ var init_sync_verifier = __esm({
|
|
|
21569
22120
|
const jsonFiles = ["storage/state.json"];
|
|
21570
22121
|
const invalid = [];
|
|
21571
22122
|
for (const file of jsonFiles) {
|
|
21572
|
-
const filePath =
|
|
22123
|
+
const filePath = path48.join(globalPath, file);
|
|
21573
22124
|
try {
|
|
21574
|
-
const content = await
|
|
22125
|
+
const content = await fs44.readFile(filePath, "utf-8");
|
|
21575
22126
|
JSON.parse(content);
|
|
21576
22127
|
} catch (error) {
|
|
21577
22128
|
if (!isNotFoundError(error)) {
|
|
@@ -21592,7 +22143,7 @@ var init_sync_verifier = __esm({
|
|
|
21592
22143
|
*/
|
|
21593
22144
|
async noSensitiveData(globalPath) {
|
|
21594
22145
|
const start = Date.now();
|
|
21595
|
-
const contextDir =
|
|
22146
|
+
const contextDir = path48.join(globalPath, "context");
|
|
21596
22147
|
const patterns = [
|
|
21597
22148
|
/(?:api[_-]?key|apikey)\s*[:=]\s*['"][^'"]{10,}/i,
|
|
21598
22149
|
/(?:password|passwd|pwd)\s*[:=]\s*['"][^'"]{4,}/i,
|
|
@@ -21600,10 +22151,10 @@ var init_sync_verifier = __esm({
|
|
|
21600
22151
|
];
|
|
21601
22152
|
const violations = [];
|
|
21602
22153
|
try {
|
|
21603
|
-
const files = await
|
|
22154
|
+
const files = await fs44.readdir(contextDir);
|
|
21604
22155
|
for (const file of files) {
|
|
21605
22156
|
if (!file.endsWith(".md")) continue;
|
|
21606
|
-
const content = await
|
|
22157
|
+
const content = await fs44.readFile(path48.join(contextDir, file), "utf-8");
|
|
21607
22158
|
for (const pattern of patterns) {
|
|
21608
22159
|
if (pattern.test(content)) {
|
|
21609
22160
|
violations.push(`${file}: potential sensitive data detected`);
|
|
@@ -21697,7 +22248,7 @@ var init_sync_verifier = __esm({
|
|
|
21697
22248
|
};
|
|
21698
22249
|
}
|
|
21699
22250
|
try {
|
|
21700
|
-
const { stdout, stderr } = await
|
|
22251
|
+
const { stdout, stderr } = await execAsync10(command, {
|
|
21701
22252
|
cwd: projectPath,
|
|
21702
22253
|
timeout: 3e4
|
|
21703
22254
|
});
|
|
@@ -21723,26 +22274,30 @@ var init_sync_verifier = __esm({
|
|
|
21723
22274
|
});
|
|
21724
22275
|
|
|
21725
22276
|
// core/services/sync-service.ts
|
|
21726
|
-
import { exec as
|
|
21727
|
-
import
|
|
21728
|
-
import
|
|
21729
|
-
import
|
|
21730
|
-
|
|
22277
|
+
import { exec as exec16 } from "node:child_process";
|
|
22278
|
+
import fs45 from "node:fs/promises";
|
|
22279
|
+
import os14 from "node:os";
|
|
22280
|
+
import path49 from "node:path";
|
|
22281
|
+
import { promisify as promisify17 } from "node:util";
|
|
22282
|
+
var execAsync11, SyncService, syncService;
|
|
21731
22283
|
var init_sync_service = __esm({
|
|
21732
22284
|
"core/services/sync-service.ts"() {
|
|
21733
22285
|
"use strict";
|
|
21734
22286
|
init_ai_tools();
|
|
22287
|
+
init_errors();
|
|
21735
22288
|
init_command_installer();
|
|
21736
22289
|
init_config_manager();
|
|
21737
22290
|
init_path_manager();
|
|
21738
22291
|
init_metrics_storage();
|
|
21739
22292
|
init_citations();
|
|
21740
22293
|
init_date_helper();
|
|
22294
|
+
init_logger();
|
|
21741
22295
|
init_context_generator();
|
|
21742
22296
|
init_local_state_generator();
|
|
22297
|
+
init_skill_installer();
|
|
21743
22298
|
init_stack_detector();
|
|
21744
22299
|
init_sync_verifier();
|
|
21745
|
-
|
|
22300
|
+
execAsync11 = promisify17(exec16);
|
|
21746
22301
|
SyncService = class {
|
|
21747
22302
|
static {
|
|
21748
22303
|
__name(this, "SyncService");
|
|
@@ -21787,6 +22342,7 @@ var init_sync_service = __esm({
|
|
|
21787
22342
|
stack: this.emptyStack(),
|
|
21788
22343
|
agents: [],
|
|
21789
22344
|
skills: [],
|
|
22345
|
+
skillsInstalled: [],
|
|
21790
22346
|
contextFiles: [],
|
|
21791
22347
|
aiTools: [],
|
|
21792
22348
|
error: "No prjct project. Run p. init first."
|
|
@@ -21804,6 +22360,7 @@ var init_sync_service = __esm({
|
|
|
21804
22360
|
await ensureDirsPromise;
|
|
21805
22361
|
const agents = await this.generateAgents(stack, stats);
|
|
21806
22362
|
const skills = this.configureSkills(agents);
|
|
22363
|
+
const skillsInstalled = await this.autoInstallSkills(agents);
|
|
21807
22364
|
const sources = this.buildSources(stats, commands);
|
|
21808
22365
|
const contextFiles = await this.generateContextFiles(git, stats, commands, agents, sources);
|
|
21809
22366
|
const projectContext = {
|
|
@@ -21861,6 +22418,7 @@ var init_sync_service = __esm({
|
|
|
21861
22418
|
stack,
|
|
21862
22419
|
agents,
|
|
21863
22420
|
skills,
|
|
22421
|
+
skillsInstalled,
|
|
21864
22422
|
contextFiles,
|
|
21865
22423
|
aiTools: aiToolResults.map((r) => ({
|
|
21866
22424
|
toolId: r.toolId,
|
|
@@ -21881,6 +22439,7 @@ var init_sync_service = __esm({
|
|
|
21881
22439
|
stack: this.emptyStack(),
|
|
21882
22440
|
agents: [],
|
|
21883
22441
|
skills: [],
|
|
22442
|
+
skillsInstalled: [],
|
|
21884
22443
|
contextFiles: [],
|
|
21885
22444
|
aiTools: [],
|
|
21886
22445
|
error: error.message
|
|
@@ -21893,7 +22452,7 @@ var init_sync_service = __esm({
|
|
|
21893
22452
|
async ensureDirectories() {
|
|
21894
22453
|
const dirs = ["storage", "context", "agents", "memory", "analysis", "config", "sync"];
|
|
21895
22454
|
await Promise.all(
|
|
21896
|
-
dirs.map((dir) =>
|
|
22455
|
+
dirs.map((dir) => fs45.mkdir(path49.join(this.globalPath, dir), { recursive: true }))
|
|
21897
22456
|
);
|
|
21898
22457
|
}
|
|
21899
22458
|
// ==========================================================================
|
|
@@ -21912,19 +22471,19 @@ var init_sync_service = __esm({
|
|
|
21912
22471
|
weeklyCommits: 0
|
|
21913
22472
|
};
|
|
21914
22473
|
try {
|
|
21915
|
-
const { stdout: branch } = await
|
|
22474
|
+
const { stdout: branch } = await execAsync11("git branch --show-current", {
|
|
21916
22475
|
cwd: this.projectPath
|
|
21917
22476
|
});
|
|
21918
22477
|
data.branch = branch.trim() || "main";
|
|
21919
|
-
const { stdout: commits } = await
|
|
22478
|
+
const { stdout: commits } = await execAsync11("git rev-list --count HEAD", {
|
|
21920
22479
|
cwd: this.projectPath
|
|
21921
22480
|
});
|
|
21922
22481
|
data.commits = parseInt(commits.trim(), 10) || 0;
|
|
21923
|
-
const { stdout: contributors } = await
|
|
22482
|
+
const { stdout: contributors } = await execAsync11("git shortlog -sn --all | wc -l", {
|
|
21924
22483
|
cwd: this.projectPath
|
|
21925
22484
|
});
|
|
21926
22485
|
data.contributors = parseInt(contributors.trim(), 10) || 0;
|
|
21927
|
-
const { stdout: status } = await
|
|
22486
|
+
const { stdout: status } = await execAsync11("git status --porcelain", {
|
|
21928
22487
|
cwd: this.projectPath
|
|
21929
22488
|
});
|
|
21930
22489
|
const lines = status.trim().split("\n").filter(Boolean);
|
|
@@ -21940,7 +22499,7 @@ var init_sync_service = __esm({
|
|
|
21940
22499
|
data.untrackedFiles.push(file);
|
|
21941
22500
|
}
|
|
21942
22501
|
}
|
|
21943
|
-
const { stdout: log } = await
|
|
22502
|
+
const { stdout: log } = await execAsync11(
|
|
21944
22503
|
'git log --oneline -20 --pretty=format:"%h|%s|%ad" --date=short',
|
|
21945
22504
|
{ cwd: this.projectPath }
|
|
21946
22505
|
);
|
|
@@ -21948,7 +22507,7 @@ var init_sync_service = __esm({
|
|
|
21948
22507
|
const [hash, message, date] = line.split("|");
|
|
21949
22508
|
return { hash, message, date };
|
|
21950
22509
|
});
|
|
21951
|
-
const { stdout: weekly } = await
|
|
22510
|
+
const { stdout: weekly } = await execAsync11('git log --oneline --since="1 week ago" | wc -l', {
|
|
21952
22511
|
cwd: this.projectPath
|
|
21953
22512
|
});
|
|
21954
22513
|
data.weeklyCommits = parseInt(weekly.trim(), 10) || 0;
|
|
@@ -21963,14 +22522,14 @@ var init_sync_service = __esm({
|
|
|
21963
22522
|
const stats = {
|
|
21964
22523
|
fileCount: 0,
|
|
21965
22524
|
version: "0.0.0",
|
|
21966
|
-
name:
|
|
22525
|
+
name: path49.basename(this.projectPath),
|
|
21967
22526
|
ecosystem: "unknown",
|
|
21968
22527
|
projectType: "simple",
|
|
21969
22528
|
languages: [],
|
|
21970
22529
|
frameworks: []
|
|
21971
22530
|
};
|
|
21972
22531
|
try {
|
|
21973
|
-
const { stdout } = await
|
|
22532
|
+
const { stdout } = await execAsync11(
|
|
21974
22533
|
'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',
|
|
21975
22534
|
{ cwd: this.projectPath }
|
|
21976
22535
|
);
|
|
@@ -21979,8 +22538,8 @@ var init_sync_service = __esm({
|
|
|
21979
22538
|
stats.fileCount = 0;
|
|
21980
22539
|
}
|
|
21981
22540
|
try {
|
|
21982
|
-
const pkgPath =
|
|
21983
|
-
const pkg = JSON.parse(await
|
|
22541
|
+
const pkgPath = path49.join(this.projectPath, "package.json");
|
|
22542
|
+
const pkg = JSON.parse(await fs45.readFile(pkgPath, "utf-8"));
|
|
21984
22543
|
stats.version = pkg.version || "0.0.0";
|
|
21985
22544
|
stats.name = pkg.name || stats.name;
|
|
21986
22545
|
stats.ecosystem = "JavaScript";
|
|
@@ -22124,12 +22683,12 @@ var init_sync_service = __esm({
|
|
|
22124
22683
|
// ==========================================================================
|
|
22125
22684
|
async generateAgents(stack, stats) {
|
|
22126
22685
|
const agents = [];
|
|
22127
|
-
const agentsPath =
|
|
22686
|
+
const agentsPath = path49.join(this.globalPath, "agents");
|
|
22128
22687
|
try {
|
|
22129
|
-
const files = await
|
|
22688
|
+
const files = await fs45.readdir(agentsPath);
|
|
22130
22689
|
for (const file of files) {
|
|
22131
22690
|
if (file.endsWith(".md")) {
|
|
22132
|
-
await
|
|
22691
|
+
await fs45.unlink(path49.join(agentsPath, file));
|
|
22133
22692
|
}
|
|
22134
22693
|
}
|
|
22135
22694
|
} catch {
|
|
@@ -22169,7 +22728,7 @@ var init_sync_service = __esm({
|
|
|
22169
22728
|
async generateWorkflowAgent(name, agentsPath) {
|
|
22170
22729
|
let content = "";
|
|
22171
22730
|
try {
|
|
22172
|
-
const templatePath =
|
|
22731
|
+
const templatePath = path49.join(
|
|
22173
22732
|
__dirname,
|
|
22174
22733
|
"..",
|
|
22175
22734
|
"..",
|
|
@@ -22178,16 +22737,16 @@ var init_sync_service = __esm({
|
|
|
22178
22737
|
"workflow",
|
|
22179
22738
|
`${name}.md`
|
|
22180
22739
|
);
|
|
22181
|
-
content = await
|
|
22740
|
+
content = await fs45.readFile(templatePath, "utf-8");
|
|
22182
22741
|
} catch {
|
|
22183
22742
|
content = this.generateMinimalWorkflowAgent(name);
|
|
22184
22743
|
}
|
|
22185
|
-
await
|
|
22744
|
+
await fs45.writeFile(path49.join(agentsPath, `${name}.md`), content, "utf-8");
|
|
22186
22745
|
}
|
|
22187
22746
|
async generateDomainAgent(name, agentsPath, stats, stack) {
|
|
22188
22747
|
let content = "";
|
|
22189
22748
|
try {
|
|
22190
|
-
const templatePath =
|
|
22749
|
+
const templatePath = path49.join(
|
|
22191
22750
|
__dirname,
|
|
22192
22751
|
"..",
|
|
22193
22752
|
"..",
|
|
@@ -22196,14 +22755,14 @@ var init_sync_service = __esm({
|
|
|
22196
22755
|
"domain",
|
|
22197
22756
|
`${name}.md`
|
|
22198
22757
|
);
|
|
22199
|
-
content = await
|
|
22758
|
+
content = await fs45.readFile(templatePath, "utf-8");
|
|
22200
22759
|
content = content.replace("{projectName}", stats.name);
|
|
22201
22760
|
content = content.replace("{frameworks}", stack.frameworks.join(", ") || "None detected");
|
|
22202
22761
|
content = content.replace("{ecosystem}", stats.ecosystem);
|
|
22203
22762
|
} catch {
|
|
22204
22763
|
content = this.generateMinimalDomainAgent(name, stats, stack);
|
|
22205
22764
|
}
|
|
22206
|
-
await
|
|
22765
|
+
await fs45.writeFile(path49.join(agentsPath, `${name}.md`), content, "utf-8");
|
|
22207
22766
|
}
|
|
22208
22767
|
generateMinimalWorkflowAgent(name) {
|
|
22209
22768
|
const descriptions = {
|
|
@@ -22271,8 +22830,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
22271
22830
|
})),
|
|
22272
22831
|
agentSkillMap: Object.fromEntries(skills.map((s) => [s.agent, s.skill]))
|
|
22273
22832
|
};
|
|
22274
|
-
|
|
22275
|
-
|
|
22833
|
+
fs45.writeFile(
|
|
22834
|
+
path49.join(this.globalPath, "config", "skills.json"),
|
|
22276
22835
|
JSON.stringify(skillsConfig, null, 2),
|
|
22277
22836
|
"utf-8"
|
|
22278
22837
|
).catch(() => {
|
|
@@ -22280,6 +22839,85 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
22280
22839
|
return skills;
|
|
22281
22840
|
}
|
|
22282
22841
|
// ==========================================================================
|
|
22842
|
+
// SKILL AUTO-INSTALLATION
|
|
22843
|
+
// ==========================================================================
|
|
22844
|
+
/**
|
|
22845
|
+
* Auto-install skills from skill-mappings.json for generated agents.
|
|
22846
|
+
* Reads the mapping, checks which packages are needed, and installs missing ones.
|
|
22847
|
+
*/
|
|
22848
|
+
async autoInstallSkills(agents) {
|
|
22849
|
+
const results = [];
|
|
22850
|
+
try {
|
|
22851
|
+
const mappingsPath = path49.join(
|
|
22852
|
+
__dirname,
|
|
22853
|
+
"..",
|
|
22854
|
+
"..",
|
|
22855
|
+
"templates",
|
|
22856
|
+
"config",
|
|
22857
|
+
"skill-mappings.json"
|
|
22858
|
+
);
|
|
22859
|
+
const mappingsContent = await fs45.readFile(mappingsPath, "utf-8");
|
|
22860
|
+
const mappings = JSON.parse(mappingsContent);
|
|
22861
|
+
const agentToSkillMap = mappings.agentToSkillMap || {};
|
|
22862
|
+
const packagesToInstall = [];
|
|
22863
|
+
for (const agent of agents) {
|
|
22864
|
+
const mapping = agentToSkillMap[agent.name];
|
|
22865
|
+
if (mapping?.packages) {
|
|
22866
|
+
for (const pkg of mapping.packages) {
|
|
22867
|
+
packagesToInstall.push({ pkg, agent: agent.name });
|
|
22868
|
+
}
|
|
22869
|
+
}
|
|
22870
|
+
}
|
|
22871
|
+
if (packagesToInstall.length === 0) return results;
|
|
22872
|
+
const skillsDir = path49.join(os14.homedir(), ".claude", "skills");
|
|
22873
|
+
for (const { pkg, agent } of packagesToInstall) {
|
|
22874
|
+
const skillName = pkg.split("/").pop() || pkg;
|
|
22875
|
+
const subdirPath = path49.join(skillsDir, skillName, "SKILL.md");
|
|
22876
|
+
const flatPath = path49.join(skillsDir, `${skillName}.md`);
|
|
22877
|
+
let alreadyInstalled = false;
|
|
22878
|
+
try {
|
|
22879
|
+
await fs45.access(subdirPath);
|
|
22880
|
+
alreadyInstalled = true;
|
|
22881
|
+
} catch {
|
|
22882
|
+
try {
|
|
22883
|
+
await fs45.access(flatPath);
|
|
22884
|
+
alreadyInstalled = true;
|
|
22885
|
+
} catch {
|
|
22886
|
+
}
|
|
22887
|
+
}
|
|
22888
|
+
if (alreadyInstalled) {
|
|
22889
|
+
results.push({ name: skillName, agent, status: "skipped" });
|
|
22890
|
+
continue;
|
|
22891
|
+
}
|
|
22892
|
+
try {
|
|
22893
|
+
const parts = pkg.split("/");
|
|
22894
|
+
let installSource;
|
|
22895
|
+
if (parts.length === 3) {
|
|
22896
|
+
installSource = `${parts[0]}/${parts[1]}@${parts[2]}`;
|
|
22897
|
+
} else {
|
|
22898
|
+
installSource = pkg;
|
|
22899
|
+
}
|
|
22900
|
+
const installResult = await skillInstaller.install(installSource);
|
|
22901
|
+
if (installResult.installed.length > 0) {
|
|
22902
|
+
results.push({ name: skillName, agent, status: "installed" });
|
|
22903
|
+
logger_default.info(`Installed skill: ${skillName} for agent: ${agent}`);
|
|
22904
|
+
} else if (installResult.errors.length > 0) {
|
|
22905
|
+
results.push({ name: skillName, agent, status: "error" });
|
|
22906
|
+
logger_default.debug(`Failed to install skill ${skillName}`, { errors: installResult.errors });
|
|
22907
|
+
} else {
|
|
22908
|
+
results.push({ name: skillName, agent, status: "skipped" });
|
|
22909
|
+
}
|
|
22910
|
+
} catch (error) {
|
|
22911
|
+
results.push({ name: skillName, agent, status: "error" });
|
|
22912
|
+
logger_default.debug(`Skill install error for ${skillName}`, { error: getErrorMessage(error) });
|
|
22913
|
+
}
|
|
22914
|
+
}
|
|
22915
|
+
} catch (error) {
|
|
22916
|
+
logger_default.debug("Skill auto-installation failed (non-critical)", { error: getErrorMessage(error) });
|
|
22917
|
+
}
|
|
22918
|
+
return results;
|
|
22919
|
+
}
|
|
22920
|
+
// ==========================================================================
|
|
22283
22921
|
// CONTEXT FILE GENERATION
|
|
22284
22922
|
// ==========================================================================
|
|
22285
22923
|
async generateContextFiles(git, stats, commands, agents, sources) {
|
|
@@ -22300,10 +22938,10 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
22300
22938
|
// PROJECT.JSON UPDATE
|
|
22301
22939
|
// ==========================================================================
|
|
22302
22940
|
async updateProjectJson(git, stats) {
|
|
22303
|
-
const projectJsonPath =
|
|
22941
|
+
const projectJsonPath = path49.join(this.globalPath, "project.json");
|
|
22304
22942
|
let existing = {};
|
|
22305
22943
|
try {
|
|
22306
|
-
existing = JSON.parse(await
|
|
22944
|
+
existing = JSON.parse(await fs45.readFile(projectJsonPath, "utf-8"));
|
|
22307
22945
|
} catch {
|
|
22308
22946
|
}
|
|
22309
22947
|
const updated = {
|
|
@@ -22325,16 +22963,16 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
22325
22963
|
lastSyncCommit: git.recentCommits[0]?.hash || null,
|
|
22326
22964
|
lastSyncBranch: git.branch
|
|
22327
22965
|
};
|
|
22328
|
-
await
|
|
22966
|
+
await fs45.writeFile(projectJsonPath, JSON.stringify(updated, null, 2), "utf-8");
|
|
22329
22967
|
}
|
|
22330
22968
|
// ==========================================================================
|
|
22331
22969
|
// STATE.JSON UPDATE
|
|
22332
22970
|
// ==========================================================================
|
|
22333
22971
|
async updateStateJson(stats, stack) {
|
|
22334
|
-
const statePath =
|
|
22972
|
+
const statePath = path49.join(this.globalPath, "storage", "state.json");
|
|
22335
22973
|
let state = {};
|
|
22336
22974
|
try {
|
|
22337
|
-
state = JSON.parse(await
|
|
22975
|
+
state = JSON.parse(await fs45.readFile(statePath, "utf-8"));
|
|
22338
22976
|
} catch {
|
|
22339
22977
|
}
|
|
22340
22978
|
state.projectId = this.projectId;
|
|
@@ -22361,7 +22999,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
22361
22999
|
lastAction: "Synced project",
|
|
22362
23000
|
nextAction: 'Run `p. task "description"` to start working'
|
|
22363
23001
|
};
|
|
22364
|
-
await
|
|
23002
|
+
await fs45.writeFile(statePath, JSON.stringify(state, null, 2), "utf-8");
|
|
22365
23003
|
try {
|
|
22366
23004
|
await localStateGenerator.generate(
|
|
22367
23005
|
this.projectPath,
|
|
@@ -22374,7 +23012,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
22374
23012
|
// MEMORY LOGGING
|
|
22375
23013
|
// ==========================================================================
|
|
22376
23014
|
async logToMemory(git, stats) {
|
|
22377
|
-
const memoryPath =
|
|
23015
|
+
const memoryPath = path49.join(this.globalPath, "memory", "events.jsonl");
|
|
22378
23016
|
const event = {
|
|
22379
23017
|
ts: date_helper_default.getTimestamp(),
|
|
22380
23018
|
action: "sync",
|
|
@@ -22383,7 +23021,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
22383
23021
|
fileCount: stats.fileCount,
|
|
22384
23022
|
commitCount: git.commits
|
|
22385
23023
|
};
|
|
22386
|
-
await
|
|
23024
|
+
await fs45.appendFile(memoryPath, `${JSON.stringify(event)}
|
|
22387
23025
|
`, "utf-8");
|
|
22388
23026
|
}
|
|
22389
23027
|
// ==========================================================================
|
|
@@ -22403,16 +23041,16 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
22403
23041
|
let filteredChars = 0;
|
|
22404
23042
|
for (const file of contextFiles) {
|
|
22405
23043
|
try {
|
|
22406
|
-
const filePath =
|
|
22407
|
-
const content = await
|
|
23044
|
+
const filePath = path49.join(this.globalPath, file);
|
|
23045
|
+
const content = await fs45.readFile(filePath, "utf-8");
|
|
22408
23046
|
filteredChars += content.length;
|
|
22409
23047
|
} catch {
|
|
22410
23048
|
}
|
|
22411
23049
|
}
|
|
22412
23050
|
for (const agent of agents) {
|
|
22413
23051
|
try {
|
|
22414
|
-
const agentPath =
|
|
22415
|
-
const content = await
|
|
23052
|
+
const agentPath = path49.join(this.globalPath, "agents", `${agent.name}.md`);
|
|
23053
|
+
const content = await fs45.readFile(agentPath, "utf-8");
|
|
22416
23054
|
filteredChars += content.length;
|
|
22417
23055
|
} catch {
|
|
22418
23056
|
}
|
|
@@ -22444,7 +23082,7 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
22444
23082
|
// ==========================================================================
|
|
22445
23083
|
async fileExists(filename) {
|
|
22446
23084
|
try {
|
|
22447
|
-
await
|
|
23085
|
+
await fs45.access(path49.join(this.projectPath, filename));
|
|
22448
23086
|
return true;
|
|
22449
23087
|
} catch {
|
|
22450
23088
|
return false;
|
|
@@ -22452,8 +23090,8 @@ You are the ${name} expert for this project. Apply best practices for the detect
|
|
|
22452
23090
|
}
|
|
22453
23091
|
async getCliVersion() {
|
|
22454
23092
|
try {
|
|
22455
|
-
const pkgPath =
|
|
22456
|
-
const pkg = JSON.parse(await
|
|
23093
|
+
const pkgPath = path49.join(__dirname, "..", "..", "package.json");
|
|
23094
|
+
const pkg = JSON.parse(await fs45.readFile(pkgPath, "utf-8"));
|
|
22457
23095
|
return pkg.version || "0.0.0";
|
|
22458
23096
|
} catch {
|
|
22459
23097
|
return "0.0.0";
|
|
@@ -22613,22 +23251,22 @@ __export(uninstall_exports, {
|
|
|
22613
23251
|
uninstall: () => uninstall
|
|
22614
23252
|
});
|
|
22615
23253
|
import { execSync as execSync3 } from "node:child_process";
|
|
22616
|
-
import
|
|
22617
|
-
import
|
|
22618
|
-
import
|
|
23254
|
+
import fs46 from "node:fs/promises";
|
|
23255
|
+
import os15 from "node:os";
|
|
23256
|
+
import path50 from "node:path";
|
|
22619
23257
|
import readline2 from "node:readline";
|
|
22620
23258
|
import chalk12 from "chalk";
|
|
22621
23259
|
async function getDirectorySize(dirPath) {
|
|
22622
23260
|
let totalSize = 0;
|
|
22623
23261
|
try {
|
|
22624
|
-
const entries = await
|
|
23262
|
+
const entries = await fs46.readdir(dirPath, { withFileTypes: true });
|
|
22625
23263
|
for (const entry of entries) {
|
|
22626
|
-
const entryPath =
|
|
23264
|
+
const entryPath = path50.join(dirPath, entry.name);
|
|
22627
23265
|
if (entry.isDirectory()) {
|
|
22628
23266
|
totalSize += await getDirectorySize(entryPath);
|
|
22629
23267
|
} else {
|
|
22630
23268
|
try {
|
|
22631
|
-
const stats = await
|
|
23269
|
+
const stats = await fs46.stat(entryPath);
|
|
22632
23270
|
totalSize += stats.size;
|
|
22633
23271
|
} catch {
|
|
22634
23272
|
}
|
|
@@ -22647,7 +23285,7 @@ function formatSize(bytes) {
|
|
|
22647
23285
|
}
|
|
22648
23286
|
async function countDirectoryItems(dirPath) {
|
|
22649
23287
|
try {
|
|
22650
|
-
const entries = await
|
|
23288
|
+
const entries = await fs46.readdir(dirPath, { withFileTypes: true });
|
|
22651
23289
|
return entries.filter((e) => e.isDirectory()).length;
|
|
22652
23290
|
} catch {
|
|
22653
23291
|
return 0;
|
|
@@ -22680,7 +23318,7 @@ async function gatherUninstallItems() {
|
|
|
22680
23318
|
const providerPaths = getProviderPaths();
|
|
22681
23319
|
const prjctCliPath = path_manager_default.getGlobalBasePath();
|
|
22682
23320
|
const prjctCliExists = await fileExists(prjctCliPath);
|
|
22683
|
-
const projectCount = prjctCliExists ? await countDirectoryItems(
|
|
23321
|
+
const projectCount = prjctCliExists ? await countDirectoryItems(path50.join(prjctCliPath, "projects")) : 0;
|
|
22684
23322
|
const prjctCliSize = prjctCliExists ? await getDirectorySize(prjctCliPath) : 0;
|
|
22685
23323
|
items.push({
|
|
22686
23324
|
path: prjctCliPath,
|
|
@@ -22690,12 +23328,12 @@ async function gatherUninstallItems() {
|
|
|
22690
23328
|
count: projectCount,
|
|
22691
23329
|
exists: prjctCliExists
|
|
22692
23330
|
});
|
|
22693
|
-
const claudeMdPath =
|
|
23331
|
+
const claudeMdPath = path50.join(providerPaths.claude.config, "CLAUDE.md");
|
|
22694
23332
|
const claudeMdExists = await fileExists(claudeMdPath);
|
|
22695
23333
|
let hasPrjctSection = false;
|
|
22696
23334
|
if (claudeMdExists) {
|
|
22697
23335
|
try {
|
|
22698
|
-
const content = await
|
|
23336
|
+
const content = await fs46.readFile(claudeMdPath, "utf-8");
|
|
22699
23337
|
hasPrjctSection = content.includes(PRJCT_START_MARKER) && content.includes(PRJCT_END_MARKER);
|
|
22700
23338
|
} catch {
|
|
22701
23339
|
}
|
|
@@ -22724,7 +23362,7 @@ async function gatherUninstallItems() {
|
|
|
22724
23362
|
description: "Claude router",
|
|
22725
23363
|
exists: claudeRouterExists
|
|
22726
23364
|
});
|
|
22727
|
-
const statusLinePath =
|
|
23365
|
+
const statusLinePath = path50.join(providerPaths.claude.config, "prjct-statusline.sh");
|
|
22728
23366
|
const statusLineExists = await fileExists(statusLinePath);
|
|
22729
23367
|
items.push({
|
|
22730
23368
|
path: statusLinePath,
|
|
@@ -22740,12 +23378,12 @@ async function gatherUninstallItems() {
|
|
|
22740
23378
|
description: "Gemini router",
|
|
22741
23379
|
exists: geminiRouterExists
|
|
22742
23380
|
});
|
|
22743
|
-
const geminiMdPath =
|
|
23381
|
+
const geminiMdPath = path50.join(providerPaths.gemini.config, "GEMINI.md");
|
|
22744
23382
|
const geminiMdExists = await fileExists(geminiMdPath);
|
|
22745
23383
|
let hasGeminiPrjctSection = false;
|
|
22746
23384
|
if (geminiMdExists) {
|
|
22747
23385
|
try {
|
|
22748
|
-
const content = await
|
|
23386
|
+
const content = await fs46.readFile(geminiMdPath, "utf-8");
|
|
22749
23387
|
hasGeminiPrjctSection = content.includes(PRJCT_START_MARKER) && content.includes(PRJCT_END_MARKER);
|
|
22750
23388
|
} catch {
|
|
22751
23389
|
}
|
|
@@ -22762,7 +23400,7 @@ async function gatherUninstallItems() {
|
|
|
22762
23400
|
}
|
|
22763
23401
|
async function removePrjctSection(filePath) {
|
|
22764
23402
|
try {
|
|
22765
|
-
const content = await
|
|
23403
|
+
const content = await fs46.readFile(filePath, "utf-8");
|
|
22766
23404
|
if (!content.includes(PRJCT_START_MARKER) || !content.includes(PRJCT_END_MARKER)) {
|
|
22767
23405
|
return false;
|
|
22768
23406
|
}
|
|
@@ -22771,9 +23409,9 @@ async function removePrjctSection(filePath) {
|
|
|
22771
23409
|
let newContent = content.substring(0, startIndex) + content.substring(endIndex);
|
|
22772
23410
|
newContent = newContent.replace(/\n{3,}/g, "\n\n").trim();
|
|
22773
23411
|
if (!newContent || newContent.trim().length === 0) {
|
|
22774
|
-
await
|
|
23412
|
+
await fs46.unlink(filePath);
|
|
22775
23413
|
} else {
|
|
22776
|
-
await
|
|
23414
|
+
await fs46.writeFile(filePath, `${newContent}
|
|
22777
23415
|
`, "utf-8");
|
|
22778
23416
|
}
|
|
22779
23417
|
return true;
|
|
@@ -22782,14 +23420,14 @@ async function removePrjctSection(filePath) {
|
|
|
22782
23420
|
}
|
|
22783
23421
|
}
|
|
22784
23422
|
async function createBackup() {
|
|
22785
|
-
const homeDir =
|
|
23423
|
+
const homeDir = os15.homedir();
|
|
22786
23424
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").substring(0, 19);
|
|
22787
|
-
const backupDir =
|
|
23425
|
+
const backupDir = path50.join(homeDir, `.prjct-backup-${timestamp}`);
|
|
22788
23426
|
try {
|
|
22789
|
-
await
|
|
23427
|
+
await fs46.mkdir(backupDir, { recursive: true });
|
|
22790
23428
|
const prjctCliPath = path_manager_default.getGlobalBasePath();
|
|
22791
23429
|
if (await fileExists(prjctCliPath)) {
|
|
22792
|
-
await copyDirectory(prjctCliPath,
|
|
23430
|
+
await copyDirectory(prjctCliPath, path50.join(backupDir, ".prjct-cli"));
|
|
22793
23431
|
}
|
|
22794
23432
|
return backupDir;
|
|
22795
23433
|
} catch {
|
|
@@ -22797,15 +23435,15 @@ async function createBackup() {
|
|
|
22797
23435
|
}
|
|
22798
23436
|
}
|
|
22799
23437
|
async function copyDirectory(src, dest) {
|
|
22800
|
-
await
|
|
22801
|
-
const entries = await
|
|
23438
|
+
await fs46.mkdir(dest, { recursive: true });
|
|
23439
|
+
const entries = await fs46.readdir(src, { withFileTypes: true });
|
|
22802
23440
|
for (const entry of entries) {
|
|
22803
|
-
const srcPath =
|
|
22804
|
-
const destPath =
|
|
23441
|
+
const srcPath = path50.join(src, entry.name);
|
|
23442
|
+
const destPath = path50.join(dest, entry.name);
|
|
22805
23443
|
if (entry.isDirectory()) {
|
|
22806
23444
|
await copyDirectory(srcPath, destPath);
|
|
22807
23445
|
} else {
|
|
22808
|
-
await
|
|
23446
|
+
await fs46.copyFile(srcPath, destPath);
|
|
22809
23447
|
}
|
|
22810
23448
|
}
|
|
22811
23449
|
}
|
|
@@ -22821,10 +23459,10 @@ async function performUninstall(items, installation, options) {
|
|
|
22821
23459
|
deleted.push(item.path);
|
|
22822
23460
|
}
|
|
22823
23461
|
} else if (item.type === "directory") {
|
|
22824
|
-
await
|
|
23462
|
+
await fs46.rm(item.path, { recursive: true, force: true });
|
|
22825
23463
|
deleted.push(item.path);
|
|
22826
23464
|
} else if (item.type === "file") {
|
|
22827
|
-
await
|
|
23465
|
+
await fs46.unlink(item.path);
|
|
22828
23466
|
deleted.push(item.path);
|
|
22829
23467
|
}
|
|
22830
23468
|
} catch (error) {
|
|
@@ -23000,7 +23638,7 @@ __export(watch_service_exports, {
|
|
|
23000
23638
|
WatchService: () => WatchService,
|
|
23001
23639
|
watchService: () => watchService
|
|
23002
23640
|
});
|
|
23003
|
-
import
|
|
23641
|
+
import path51 from "node:path";
|
|
23004
23642
|
import chalk13 from "chalk";
|
|
23005
23643
|
import chokidar from "chokidar";
|
|
23006
23644
|
var TRIGGER_PATTERNS, IGNORE_PATTERNS2, WatchService, watchService;
|
|
@@ -23205,7 +23843,7 @@ ${chalk13.dim(`[${timestamp}]`)} ${chalk13.cyan("\u27F3")} ${filesSummary} chang
|
|
|
23205
23843
|
printStartup() {
|
|
23206
23844
|
console.log("");
|
|
23207
23845
|
console.log(chalk13.cyan("\u{1F441}\uFE0F Watching for changes..."));
|
|
23208
|
-
console.log(chalk13.dim(` Project: ${
|
|
23846
|
+
console.log(chalk13.dim(` Project: ${path51.basename(this.projectPath)}`));
|
|
23209
23847
|
console.log(chalk13.dim(` Debounce: ${this.options.debounceMs}ms`));
|
|
23210
23848
|
console.log(chalk13.dim(` Min interval: ${this.options.minIntervalMs / 1e3}s`));
|
|
23211
23849
|
console.log("");
|
|
@@ -23883,9 +24521,9 @@ __export(setup_exports, {
|
|
|
23883
24521
|
run: () => run
|
|
23884
24522
|
});
|
|
23885
24523
|
import { execSync as execSync4 } from "node:child_process";
|
|
23886
|
-
import
|
|
23887
|
-
import
|
|
23888
|
-
import
|
|
24524
|
+
import fs47 from "node:fs/promises";
|
|
24525
|
+
import os16 from "node:os";
|
|
24526
|
+
import path52 from "node:path";
|
|
23889
24527
|
import chalk15 from "chalk";
|
|
23890
24528
|
async function installAICLI(provider) {
|
|
23891
24529
|
const packageName = provider.name === "claude" ? "@anthropic-ai/claude-code" : "@google/gemini-cli";
|
|
@@ -24024,12 +24662,12 @@ async function run() {
|
|
|
24024
24662
|
}
|
|
24025
24663
|
async function installGeminiRouter() {
|
|
24026
24664
|
try {
|
|
24027
|
-
const geminiCommandsDir =
|
|
24028
|
-
const routerSource =
|
|
24029
|
-
const routerDest =
|
|
24030
|
-
await
|
|
24665
|
+
const geminiCommandsDir = path52.join(os16.homedir(), ".gemini", "commands");
|
|
24666
|
+
const routerSource = path52.join(getPackageRoot(), "templates", "commands", "p.toml");
|
|
24667
|
+
const routerDest = path52.join(geminiCommandsDir, "p.toml");
|
|
24668
|
+
await fs47.mkdir(geminiCommandsDir, { recursive: true });
|
|
24031
24669
|
if (await fileExists(routerSource)) {
|
|
24032
|
-
await
|
|
24670
|
+
await fs47.copyFile(routerSource, routerDest);
|
|
24033
24671
|
return true;
|
|
24034
24672
|
}
|
|
24035
24673
|
return false;
|
|
@@ -24040,15 +24678,15 @@ async function installGeminiRouter() {
|
|
|
24040
24678
|
}
|
|
24041
24679
|
async function installGeminiGlobalConfig() {
|
|
24042
24680
|
try {
|
|
24043
|
-
const geminiDir =
|
|
24044
|
-
const globalConfigPath =
|
|
24045
|
-
const templatePath =
|
|
24046
|
-
await
|
|
24047
|
-
const templateContent = await
|
|
24681
|
+
const geminiDir = path52.join(os16.homedir(), ".gemini");
|
|
24682
|
+
const globalConfigPath = path52.join(geminiDir, "GEMINI.md");
|
|
24683
|
+
const templatePath = path52.join(getPackageRoot(), "templates", "global", "GEMINI.md");
|
|
24684
|
+
await fs47.mkdir(geminiDir, { recursive: true });
|
|
24685
|
+
const templateContent = await fs47.readFile(templatePath, "utf-8");
|
|
24048
24686
|
let existingContent = "";
|
|
24049
24687
|
let configExists = false;
|
|
24050
24688
|
try {
|
|
24051
|
-
existingContent = await
|
|
24689
|
+
existingContent = await fs47.readFile(globalConfigPath, "utf-8");
|
|
24052
24690
|
configExists = true;
|
|
24053
24691
|
} catch (error) {
|
|
24054
24692
|
if (isNotFoundError(error)) {
|
|
@@ -24058,7 +24696,7 @@ async function installGeminiGlobalConfig() {
|
|
|
24058
24696
|
}
|
|
24059
24697
|
}
|
|
24060
24698
|
if (!configExists) {
|
|
24061
|
-
await
|
|
24699
|
+
await fs47.writeFile(globalConfigPath, templateContent, "utf-8");
|
|
24062
24700
|
return { success: true, action: "created" };
|
|
24063
24701
|
}
|
|
24064
24702
|
const startMarker = "<!-- prjct:start - DO NOT REMOVE THIS MARKER -->";
|
|
@@ -24068,7 +24706,7 @@ async function installGeminiGlobalConfig() {
|
|
|
24068
24706
|
const updatedContent2 = `${existingContent}
|
|
24069
24707
|
|
|
24070
24708
|
${templateContent}`;
|
|
24071
|
-
await
|
|
24709
|
+
await fs47.writeFile(globalConfigPath, updatedContent2, "utf-8");
|
|
24072
24710
|
return { success: true, action: "appended" };
|
|
24073
24711
|
}
|
|
24074
24712
|
const beforeMarker = existingContent.substring(0, existingContent.indexOf(startMarker));
|
|
@@ -24080,7 +24718,7 @@ ${templateContent}`;
|
|
|
24080
24718
|
templateContent.indexOf(endMarker) + endMarker.length
|
|
24081
24719
|
);
|
|
24082
24720
|
const updatedContent = beforeMarker + prjctSection + afterMarker;
|
|
24083
|
-
await
|
|
24721
|
+
await fs47.writeFile(globalConfigPath, updatedContent, "utf-8");
|
|
24084
24722
|
return { success: true, action: "updated" };
|
|
24085
24723
|
} catch (error) {
|
|
24086
24724
|
console.error(`Gemini config warning: ${error.message}`);
|
|
@@ -24089,18 +24727,18 @@ ${templateContent}`;
|
|
|
24089
24727
|
}
|
|
24090
24728
|
async function installAntigravitySkill() {
|
|
24091
24729
|
try {
|
|
24092
|
-
const antigravitySkillsDir =
|
|
24093
|
-
const prjctSkillDir =
|
|
24094
|
-
const skillMdPath =
|
|
24095
|
-
const templatePath =
|
|
24096
|
-
await
|
|
24730
|
+
const antigravitySkillsDir = path52.join(os16.homedir(), ".gemini", "antigravity", "skills");
|
|
24731
|
+
const prjctSkillDir = path52.join(antigravitySkillsDir, "prjct");
|
|
24732
|
+
const skillMdPath = path52.join(prjctSkillDir, "SKILL.md");
|
|
24733
|
+
const templatePath = path52.join(getPackageRoot(), "templates", "antigravity", "SKILL.md");
|
|
24734
|
+
await fs47.mkdir(prjctSkillDir, { recursive: true });
|
|
24097
24735
|
const skillExists = await fileExists(skillMdPath);
|
|
24098
24736
|
if (!await fileExists(templatePath)) {
|
|
24099
24737
|
console.error("Antigravity SKILL.md template not found");
|
|
24100
24738
|
return { success: false, action: null };
|
|
24101
24739
|
}
|
|
24102
|
-
const templateContent = await
|
|
24103
|
-
await
|
|
24740
|
+
const templateContent = await fs47.readFile(templatePath, "utf-8");
|
|
24741
|
+
await fs47.writeFile(skillMdPath, templateContent, "utf-8");
|
|
24104
24742
|
return { success: true, action: skillExists ? "updated" : "created" };
|
|
24105
24743
|
} catch (error) {
|
|
24106
24744
|
console.error(`Antigravity skill warning: ${error.message}`);
|
|
@@ -24119,24 +24757,24 @@ async function installCursorProject(projectRoot) {
|
|
|
24119
24757
|
gitignoreUpdated: false
|
|
24120
24758
|
};
|
|
24121
24759
|
try {
|
|
24122
|
-
const cursorDir =
|
|
24123
|
-
const rulesDir =
|
|
24124
|
-
const commandsDir =
|
|
24125
|
-
const routerMdcDest =
|
|
24126
|
-
const routerMdcSource =
|
|
24127
|
-
const cursorCommandsSource =
|
|
24128
|
-
await
|
|
24129
|
-
await
|
|
24760
|
+
const cursorDir = path52.join(projectRoot, ".cursor");
|
|
24761
|
+
const rulesDir = path52.join(cursorDir, "rules");
|
|
24762
|
+
const commandsDir = path52.join(cursorDir, "commands");
|
|
24763
|
+
const routerMdcDest = path52.join(rulesDir, "prjct.mdc");
|
|
24764
|
+
const routerMdcSource = path52.join(getPackageRoot(), "templates", "cursor", "router.mdc");
|
|
24765
|
+
const cursorCommandsSource = path52.join(getPackageRoot(), "templates", "cursor", "commands");
|
|
24766
|
+
await fs47.mkdir(rulesDir, { recursive: true });
|
|
24767
|
+
await fs47.mkdir(commandsDir, { recursive: true });
|
|
24130
24768
|
if (await fileExists(routerMdcSource)) {
|
|
24131
|
-
await
|
|
24769
|
+
await fs47.copyFile(routerMdcSource, routerMdcDest);
|
|
24132
24770
|
result.rulesCreated = true;
|
|
24133
24771
|
}
|
|
24134
24772
|
if (await fileExists(cursorCommandsSource)) {
|
|
24135
|
-
const commandFiles = (await
|
|
24773
|
+
const commandFiles = (await fs47.readdir(cursorCommandsSource)).filter((f) => f.endsWith(".md"));
|
|
24136
24774
|
for (const file of commandFiles) {
|
|
24137
|
-
const src =
|
|
24138
|
-
const dest =
|
|
24139
|
-
await
|
|
24775
|
+
const src = path52.join(cursorCommandsSource, file);
|
|
24776
|
+
const dest = path52.join(commandsDir, file);
|
|
24777
|
+
await fs47.copyFile(src, dest);
|
|
24140
24778
|
}
|
|
24141
24779
|
result.commandsCreated = commandFiles.length > 0;
|
|
24142
24780
|
}
|
|
@@ -24150,7 +24788,7 @@ async function installCursorProject(projectRoot) {
|
|
|
24150
24788
|
}
|
|
24151
24789
|
async function addCursorToGitignore(projectRoot) {
|
|
24152
24790
|
try {
|
|
24153
|
-
const gitignorePath =
|
|
24791
|
+
const gitignorePath = path52.join(projectRoot, ".gitignore");
|
|
24154
24792
|
const entriesToAdd = [
|
|
24155
24793
|
"# prjct Cursor routers (regenerated per-developer)",
|
|
24156
24794
|
".cursor/rules/prjct.mdc",
|
|
@@ -24165,7 +24803,7 @@ async function addCursorToGitignore(projectRoot) {
|
|
|
24165
24803
|
let content = "";
|
|
24166
24804
|
let configExists = false;
|
|
24167
24805
|
try {
|
|
24168
|
-
content = await
|
|
24806
|
+
content = await fs47.readFile(gitignorePath, "utf-8");
|
|
24169
24807
|
configExists = true;
|
|
24170
24808
|
} catch (error) {
|
|
24171
24809
|
if (!isNotFoundError(error)) {
|
|
@@ -24180,7 +24818,7 @@ async function addCursorToGitignore(projectRoot) {
|
|
|
24180
24818
|
${entriesToAdd.join("\n")}
|
|
24181
24819
|
` : `${entriesToAdd.join("\n")}
|
|
24182
24820
|
`;
|
|
24183
|
-
await
|
|
24821
|
+
await fs47.writeFile(gitignorePath, newContent, "utf-8");
|
|
24184
24822
|
return true;
|
|
24185
24823
|
} catch (error) {
|
|
24186
24824
|
console.error(`Gitignore update warning: ${error.message}`);
|
|
@@ -24188,11 +24826,11 @@ ${entriesToAdd.join("\n")}
|
|
|
24188
24826
|
}
|
|
24189
24827
|
}
|
|
24190
24828
|
async function hasCursorProject(projectRoot) {
|
|
24191
|
-
return await fileExists(
|
|
24829
|
+
return await fileExists(path52.join(projectRoot, ".cursor"));
|
|
24192
24830
|
}
|
|
24193
24831
|
async function needsCursorRegeneration(projectRoot) {
|
|
24194
|
-
const cursorDir =
|
|
24195
|
-
const routerPath =
|
|
24832
|
+
const cursorDir = path52.join(projectRoot, ".cursor");
|
|
24833
|
+
const routerPath = path52.join(cursorDir, "rules", "prjct.mdc");
|
|
24196
24834
|
return await fileExists(cursorDir) && !await fileExists(routerPath);
|
|
24197
24835
|
}
|
|
24198
24836
|
async function installWindsurfProject(projectRoot) {
|
|
@@ -24203,31 +24841,31 @@ async function installWindsurfProject(projectRoot) {
|
|
|
24203
24841
|
gitignoreUpdated: false
|
|
24204
24842
|
};
|
|
24205
24843
|
try {
|
|
24206
|
-
const windsurfDir =
|
|
24207
|
-
const rulesDir =
|
|
24208
|
-
const workflowsDir =
|
|
24209
|
-
const routerDest =
|
|
24210
|
-
const routerSource =
|
|
24211
|
-
const windsurfWorkflowsSource =
|
|
24844
|
+
const windsurfDir = path52.join(projectRoot, ".windsurf");
|
|
24845
|
+
const rulesDir = path52.join(windsurfDir, "rules");
|
|
24846
|
+
const workflowsDir = path52.join(windsurfDir, "workflows");
|
|
24847
|
+
const routerDest = path52.join(rulesDir, "prjct.md");
|
|
24848
|
+
const routerSource = path52.join(getPackageRoot(), "templates", "windsurf", "router.md");
|
|
24849
|
+
const windsurfWorkflowsSource = path52.join(
|
|
24212
24850
|
getPackageRoot(),
|
|
24213
24851
|
"templates",
|
|
24214
24852
|
"windsurf",
|
|
24215
24853
|
"workflows"
|
|
24216
24854
|
);
|
|
24217
|
-
await
|
|
24218
|
-
await
|
|
24855
|
+
await fs47.mkdir(rulesDir, { recursive: true });
|
|
24856
|
+
await fs47.mkdir(workflowsDir, { recursive: true });
|
|
24219
24857
|
if (await fileExists(routerSource)) {
|
|
24220
|
-
await
|
|
24858
|
+
await fs47.copyFile(routerSource, routerDest);
|
|
24221
24859
|
result.rulesCreated = true;
|
|
24222
24860
|
}
|
|
24223
24861
|
if (await fileExists(windsurfWorkflowsSource)) {
|
|
24224
|
-
const workflowFiles = (await
|
|
24862
|
+
const workflowFiles = (await fs47.readdir(windsurfWorkflowsSource)).filter(
|
|
24225
24863
|
(f) => f.endsWith(".md")
|
|
24226
24864
|
);
|
|
24227
24865
|
for (const file of workflowFiles) {
|
|
24228
|
-
const src =
|
|
24229
|
-
const dest =
|
|
24230
|
-
await
|
|
24866
|
+
const src = path52.join(windsurfWorkflowsSource, file);
|
|
24867
|
+
const dest = path52.join(workflowsDir, file);
|
|
24868
|
+
await fs47.copyFile(src, dest);
|
|
24231
24869
|
}
|
|
24232
24870
|
result.workflowsCreated = workflowFiles.length > 0;
|
|
24233
24871
|
}
|
|
@@ -24241,7 +24879,7 @@ async function installWindsurfProject(projectRoot) {
|
|
|
24241
24879
|
}
|
|
24242
24880
|
async function addWindsurfToGitignore(projectRoot) {
|
|
24243
24881
|
try {
|
|
24244
|
-
const gitignorePath =
|
|
24882
|
+
const gitignorePath = path52.join(projectRoot, ".gitignore");
|
|
24245
24883
|
const entriesToAdd = [
|
|
24246
24884
|
"# prjct Windsurf routers (regenerated per-developer)",
|
|
24247
24885
|
".windsurf/rules/prjct.md",
|
|
@@ -24256,7 +24894,7 @@ async function addWindsurfToGitignore(projectRoot) {
|
|
|
24256
24894
|
let content = "";
|
|
24257
24895
|
let configExists = false;
|
|
24258
24896
|
try {
|
|
24259
|
-
content = await
|
|
24897
|
+
content = await fs47.readFile(gitignorePath, "utf-8");
|
|
24260
24898
|
configExists = true;
|
|
24261
24899
|
} catch (error) {
|
|
24262
24900
|
if (!isNotFoundError(error)) {
|
|
@@ -24271,7 +24909,7 @@ async function addWindsurfToGitignore(projectRoot) {
|
|
|
24271
24909
|
${entriesToAdd.join("\n")}
|
|
24272
24910
|
` : `${entriesToAdd.join("\n")}
|
|
24273
24911
|
`;
|
|
24274
|
-
await
|
|
24912
|
+
await fs47.writeFile(gitignorePath, newContent, "utf-8");
|
|
24275
24913
|
return true;
|
|
24276
24914
|
} catch (error) {
|
|
24277
24915
|
console.error(`Gitignore update warning: ${error.message}`);
|
|
@@ -24279,32 +24917,32 @@ ${entriesToAdd.join("\n")}
|
|
|
24279
24917
|
}
|
|
24280
24918
|
}
|
|
24281
24919
|
async function hasWindsurfProject(projectRoot) {
|
|
24282
|
-
return await fileExists(
|
|
24920
|
+
return await fileExists(path52.join(projectRoot, ".windsurf"));
|
|
24283
24921
|
}
|
|
24284
24922
|
async function needsWindsurfRegeneration(projectRoot) {
|
|
24285
|
-
const windsurfDir =
|
|
24286
|
-
const routerPath =
|
|
24923
|
+
const windsurfDir = path52.join(projectRoot, ".windsurf");
|
|
24924
|
+
const routerPath = path52.join(windsurfDir, "rules", "prjct.md");
|
|
24287
24925
|
return await fileExists(windsurfDir) && !await fileExists(routerPath);
|
|
24288
24926
|
}
|
|
24289
24927
|
async function migrateProjectsCliVersion() {
|
|
24290
24928
|
try {
|
|
24291
|
-
const projectsDir =
|
|
24929
|
+
const projectsDir = path52.join(os16.homedir(), ".prjct-cli", "projects");
|
|
24292
24930
|
if (!await fileExists(projectsDir)) {
|
|
24293
24931
|
return;
|
|
24294
24932
|
}
|
|
24295
|
-
const projectDirs = (await
|
|
24933
|
+
const projectDirs = (await fs47.readdir(projectsDir, { withFileTypes: true })).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
24296
24934
|
let migrated = 0;
|
|
24297
24935
|
for (const projectId of projectDirs) {
|
|
24298
|
-
const projectJsonPath =
|
|
24936
|
+
const projectJsonPath = path52.join(projectsDir, projectId, "project.json");
|
|
24299
24937
|
if (!await fileExists(projectJsonPath)) {
|
|
24300
24938
|
continue;
|
|
24301
24939
|
}
|
|
24302
24940
|
try {
|
|
24303
|
-
const content = await
|
|
24941
|
+
const content = await fs47.readFile(projectJsonPath, "utf8");
|
|
24304
24942
|
const project = JSON.parse(content);
|
|
24305
24943
|
if (project.cliVersion !== VERSION) {
|
|
24306
24944
|
project.cliVersion = VERSION;
|
|
24307
|
-
await
|
|
24945
|
+
await fs47.writeFile(projectJsonPath, JSON.stringify(project, null, 2));
|
|
24308
24946
|
migrated++;
|
|
24309
24947
|
}
|
|
24310
24948
|
} catch (error) {
|
|
@@ -24326,7 +24964,7 @@ async function ensureStatusLineSettings(settingsPath, statusLinePath) {
|
|
|
24326
24964
|
let settings = {};
|
|
24327
24965
|
if (await fileExists(settingsPath)) {
|
|
24328
24966
|
try {
|
|
24329
|
-
settings = JSON.parse(await
|
|
24967
|
+
settings = JSON.parse(await fs47.readFile(settingsPath, "utf8"));
|
|
24330
24968
|
} catch (error) {
|
|
24331
24969
|
if (!(error instanceof SyntaxError)) {
|
|
24332
24970
|
throw error;
|
|
@@ -24334,42 +24972,42 @@ async function ensureStatusLineSettings(settingsPath, statusLinePath) {
|
|
|
24334
24972
|
}
|
|
24335
24973
|
}
|
|
24336
24974
|
settings.statusLine = { type: "command", command: statusLinePath };
|
|
24337
|
-
await
|
|
24975
|
+
await fs47.writeFile(settingsPath, JSON.stringify(settings, null, 2));
|
|
24338
24976
|
}
|
|
24339
24977
|
async function installStatusLine() {
|
|
24340
24978
|
try {
|
|
24341
|
-
const claudeDir =
|
|
24342
|
-
const settingsPath =
|
|
24343
|
-
const claudeStatusLinePath =
|
|
24344
|
-
const prjctStatusLineDir =
|
|
24345
|
-
const prjctStatusLinePath =
|
|
24346
|
-
const prjctThemesDir =
|
|
24347
|
-
const prjctLibDir =
|
|
24348
|
-
const prjctComponentsDir =
|
|
24349
|
-
const prjctConfigPath =
|
|
24350
|
-
const assetsDir =
|
|
24351
|
-
const sourceScript =
|
|
24352
|
-
const sourceThemeDir =
|
|
24353
|
-
const sourceLibDir =
|
|
24354
|
-
const sourceComponentsDir =
|
|
24355
|
-
const sourceConfigPath =
|
|
24979
|
+
const claudeDir = path52.join(os16.homedir(), ".claude");
|
|
24980
|
+
const settingsPath = path52.join(claudeDir, "settings.json");
|
|
24981
|
+
const claudeStatusLinePath = path52.join(claudeDir, "prjct-statusline.sh");
|
|
24982
|
+
const prjctStatusLineDir = path52.join(os16.homedir(), ".prjct-cli", "statusline");
|
|
24983
|
+
const prjctStatusLinePath = path52.join(prjctStatusLineDir, "statusline.sh");
|
|
24984
|
+
const prjctThemesDir = path52.join(prjctStatusLineDir, "themes");
|
|
24985
|
+
const prjctLibDir = path52.join(prjctStatusLineDir, "lib");
|
|
24986
|
+
const prjctComponentsDir = path52.join(prjctStatusLineDir, "components");
|
|
24987
|
+
const prjctConfigPath = path52.join(prjctStatusLineDir, "config.json");
|
|
24988
|
+
const assetsDir = path52.join(getPackageRoot(), "assets", "statusline");
|
|
24989
|
+
const sourceScript = path52.join(assetsDir, "statusline.sh");
|
|
24990
|
+
const sourceThemeDir = path52.join(assetsDir, "themes");
|
|
24991
|
+
const sourceLibDir = path52.join(assetsDir, "lib");
|
|
24992
|
+
const sourceComponentsDir = path52.join(assetsDir, "components");
|
|
24993
|
+
const sourceConfigPath = path52.join(assetsDir, "default-config.json");
|
|
24356
24994
|
if (!await fileExists(claudeDir)) {
|
|
24357
|
-
await
|
|
24995
|
+
await fs47.mkdir(claudeDir, { recursive: true });
|
|
24358
24996
|
}
|
|
24359
24997
|
if (!await fileExists(prjctStatusLineDir)) {
|
|
24360
|
-
await
|
|
24998
|
+
await fs47.mkdir(prjctStatusLineDir, { recursive: true });
|
|
24361
24999
|
}
|
|
24362
25000
|
if (!await fileExists(prjctThemesDir)) {
|
|
24363
|
-
await
|
|
25001
|
+
await fs47.mkdir(prjctThemesDir, { recursive: true });
|
|
24364
25002
|
}
|
|
24365
25003
|
if (!await fileExists(prjctLibDir)) {
|
|
24366
|
-
await
|
|
25004
|
+
await fs47.mkdir(prjctLibDir, { recursive: true });
|
|
24367
25005
|
}
|
|
24368
25006
|
if (!await fileExists(prjctComponentsDir)) {
|
|
24369
|
-
await
|
|
25007
|
+
await fs47.mkdir(prjctComponentsDir, { recursive: true });
|
|
24370
25008
|
}
|
|
24371
25009
|
if (await fileExists(prjctStatusLinePath)) {
|
|
24372
|
-
const existingContent = await
|
|
25010
|
+
const existingContent = await fs47.readFile(prjctStatusLinePath, "utf8");
|
|
24373
25011
|
if (existingContent.includes("CLI_VERSION=")) {
|
|
24374
25012
|
const versionMatch = existingContent.match(/CLI_VERSION="([^"]*)"/);
|
|
24375
25013
|
if (versionMatch && versionMatch[1] !== VERSION) {
|
|
@@ -24377,7 +25015,7 @@ async function installStatusLine() {
|
|
|
24377
25015
|
/CLI_VERSION="[^"]*"/,
|
|
24378
25016
|
`CLI_VERSION="${VERSION}"`
|
|
24379
25017
|
);
|
|
24380
|
-
await
|
|
25018
|
+
await fs47.writeFile(prjctStatusLinePath, updatedContent, { mode: 493 });
|
|
24381
25019
|
}
|
|
24382
25020
|
await installStatusLineModules(sourceLibDir, prjctLibDir);
|
|
24383
25021
|
await installStatusLineModules(sourceComponentsDir, prjctComponentsDir);
|
|
@@ -24387,21 +25025,21 @@ async function installStatusLine() {
|
|
|
24387
25025
|
}
|
|
24388
25026
|
}
|
|
24389
25027
|
if (await fileExists(sourceScript)) {
|
|
24390
|
-
let scriptContent = await
|
|
25028
|
+
let scriptContent = await fs47.readFile(sourceScript, "utf8");
|
|
24391
25029
|
scriptContent = scriptContent.replace(/CLI_VERSION="[^"]*"/, `CLI_VERSION="${VERSION}"`);
|
|
24392
|
-
await
|
|
25030
|
+
await fs47.writeFile(prjctStatusLinePath, scriptContent, { mode: 493 });
|
|
24393
25031
|
await installStatusLineModules(sourceLibDir, prjctLibDir);
|
|
24394
25032
|
await installStatusLineModules(sourceComponentsDir, prjctComponentsDir);
|
|
24395
25033
|
if (await fileExists(sourceThemeDir)) {
|
|
24396
|
-
const themes = await
|
|
25034
|
+
const themes = await fs47.readdir(sourceThemeDir);
|
|
24397
25035
|
for (const theme of themes) {
|
|
24398
|
-
const src =
|
|
24399
|
-
const dest =
|
|
24400
|
-
await
|
|
25036
|
+
const src = path52.join(sourceThemeDir, theme);
|
|
25037
|
+
const dest = path52.join(prjctThemesDir, theme);
|
|
25038
|
+
await fs47.copyFile(src, dest);
|
|
24401
25039
|
}
|
|
24402
25040
|
}
|
|
24403
25041
|
if (!await fileExists(prjctConfigPath) && await fileExists(sourceConfigPath)) {
|
|
24404
|
-
await
|
|
25042
|
+
await fs47.copyFile(sourceConfigPath, prjctConfigPath);
|
|
24405
25043
|
}
|
|
24406
25044
|
} else {
|
|
24407
25045
|
const scriptContent = `#!/bin/bash
|
|
@@ -24436,7 +25074,7 @@ if [ -f "$CONFIG" ]; then
|
|
|
24436
25074
|
fi
|
|
24437
25075
|
echo "prjct"
|
|
24438
25076
|
`;
|
|
24439
|
-
await
|
|
25077
|
+
await fs47.writeFile(prjctStatusLinePath, scriptContent, { mode: 493 });
|
|
24440
25078
|
}
|
|
24441
25079
|
await ensureStatusLineSymlink(claudeStatusLinePath, prjctStatusLinePath);
|
|
24442
25080
|
await ensureStatusLineSettings(settingsPath, claudeStatusLinePath);
|
|
@@ -24448,10 +25086,10 @@ echo "prjct"
|
|
|
24448
25086
|
}
|
|
24449
25087
|
async function installContext7MCP() {
|
|
24450
25088
|
try {
|
|
24451
|
-
const claudeDir =
|
|
24452
|
-
const mcpConfigPath =
|
|
25089
|
+
const claudeDir = path52.join(os16.homedir(), ".claude");
|
|
25090
|
+
const mcpConfigPath = path52.join(claudeDir, "mcp.json");
|
|
24453
25091
|
if (!await fileExists(claudeDir)) {
|
|
24454
|
-
await
|
|
25092
|
+
await fs47.mkdir(claudeDir, { recursive: true });
|
|
24455
25093
|
}
|
|
24456
25094
|
const context7Config = {
|
|
24457
25095
|
mcpServers: {
|
|
@@ -24462,16 +25100,16 @@ async function installContext7MCP() {
|
|
|
24462
25100
|
}
|
|
24463
25101
|
};
|
|
24464
25102
|
if (await fileExists(mcpConfigPath)) {
|
|
24465
|
-
const existingContent = await
|
|
25103
|
+
const existingContent = await fs47.readFile(mcpConfigPath, "utf-8");
|
|
24466
25104
|
const existingConfig = JSON.parse(existingContent);
|
|
24467
25105
|
if (existingConfig.mcpServers?.context7) {
|
|
24468
25106
|
return;
|
|
24469
25107
|
}
|
|
24470
25108
|
existingConfig.mcpServers = existingConfig.mcpServers || {};
|
|
24471
25109
|
existingConfig.mcpServers.context7 = context7Config.mcpServers.context7;
|
|
24472
|
-
await
|
|
25110
|
+
await fs47.writeFile(mcpConfigPath, JSON.stringify(existingConfig, null, 2), "utf-8");
|
|
24473
25111
|
} else {
|
|
24474
|
-
await
|
|
25112
|
+
await fs47.writeFile(mcpConfigPath, JSON.stringify(context7Config, null, 2), "utf-8");
|
|
24475
25113
|
}
|
|
24476
25114
|
} catch (error) {
|
|
24477
25115
|
console.error(`Context7 MCP setup warning: ${error.message}`);
|
|
@@ -24481,34 +25119,34 @@ async function installStatusLineModules(sourceDir, destDir) {
|
|
|
24481
25119
|
if (!await fileExists(sourceDir)) {
|
|
24482
25120
|
return;
|
|
24483
25121
|
}
|
|
24484
|
-
const files = await
|
|
25122
|
+
const files = await fs47.readdir(sourceDir);
|
|
24485
25123
|
for (const file of files) {
|
|
24486
25124
|
if (file.endsWith(".sh")) {
|
|
24487
|
-
const src =
|
|
24488
|
-
const dest =
|
|
24489
|
-
await
|
|
24490
|
-
await
|
|
25125
|
+
const src = path52.join(sourceDir, file);
|
|
25126
|
+
const dest = path52.join(destDir, file);
|
|
25127
|
+
await fs47.copyFile(src, dest);
|
|
25128
|
+
await fs47.chmod(dest, 493);
|
|
24491
25129
|
}
|
|
24492
25130
|
}
|
|
24493
25131
|
}
|
|
24494
25132
|
async function ensureStatusLineSymlink(linkPath, targetPath) {
|
|
24495
25133
|
try {
|
|
24496
25134
|
if (await fileExists(linkPath)) {
|
|
24497
|
-
const stats = await
|
|
25135
|
+
const stats = await fs47.lstat(linkPath);
|
|
24498
25136
|
if (stats.isSymbolicLink()) {
|
|
24499
|
-
const existingTarget = await
|
|
25137
|
+
const existingTarget = await fs47.readlink(linkPath);
|
|
24500
25138
|
if (existingTarget === targetPath) {
|
|
24501
25139
|
return;
|
|
24502
25140
|
}
|
|
24503
25141
|
}
|
|
24504
|
-
await
|
|
25142
|
+
await fs47.unlink(linkPath);
|
|
24505
25143
|
}
|
|
24506
|
-
await
|
|
25144
|
+
await fs47.symlink(targetPath, linkPath);
|
|
24507
25145
|
} catch (_error) {
|
|
24508
25146
|
try {
|
|
24509
25147
|
if (await fileExists(targetPath)) {
|
|
24510
|
-
await
|
|
24511
|
-
await
|
|
25148
|
+
await fs47.copyFile(targetPath, linkPath);
|
|
25149
|
+
await fs47.chmod(linkPath, 493);
|
|
24512
25150
|
}
|
|
24513
25151
|
} catch (copyError) {
|
|
24514
25152
|
if (!isNotFoundError(copyError)) {
|
|
@@ -24922,7 +25560,7 @@ var init_registry2 = __esm({
|
|
|
24922
25560
|
});
|
|
24923
25561
|
|
|
24924
25562
|
// core/commands/analytics.ts
|
|
24925
|
-
import
|
|
25563
|
+
import path53 from "node:path";
|
|
24926
25564
|
var AnalyticsCommands;
|
|
24927
25565
|
var init_analytics = __esm({
|
|
24928
25566
|
"core/commands/analytics.ts"() {
|
|
@@ -24948,7 +25586,7 @@ var init_analytics = __esm({
|
|
|
24948
25586
|
output_default.failWithHint("NO_PROJECT_ID");
|
|
24949
25587
|
return { success: false, error: "No project ID found" };
|
|
24950
25588
|
}
|
|
24951
|
-
const projectName =
|
|
25589
|
+
const projectName = path53.basename(projectPath);
|
|
24952
25590
|
const currentTask = await stateStorage.getCurrentTask(projectId);
|
|
24953
25591
|
const queueTasks = await queueStorage.getActiveTasks(projectId);
|
|
24954
25592
|
const shipped = await shippedStorage.getRecent(projectId, 5);
|
|
@@ -25200,8 +25838,8 @@ ${"\u2550".repeat(50)}
|
|
|
25200
25838
|
});
|
|
25201
25839
|
|
|
25202
25840
|
// core/commands/context.ts
|
|
25203
|
-
import
|
|
25204
|
-
import
|
|
25841
|
+
import fs48 from "node:fs/promises";
|
|
25842
|
+
import path54 from "node:path";
|
|
25205
25843
|
var ContextCommands, contextCommands;
|
|
25206
25844
|
var init_context = __esm({
|
|
25207
25845
|
"core/commands/context.ts"() {
|
|
@@ -25327,8 +25965,8 @@ var init_context = __esm({
|
|
|
25327
25965
|
*/
|
|
25328
25966
|
async loadRepoAnalysis(globalPath) {
|
|
25329
25967
|
try {
|
|
25330
|
-
const analysisPath =
|
|
25331
|
-
const content = await
|
|
25968
|
+
const analysisPath = path54.join(globalPath, "analysis", "repo-analysis.json");
|
|
25969
|
+
const content = await fs48.readFile(analysisPath, "utf-8");
|
|
25332
25970
|
const data = JSON.parse(content);
|
|
25333
25971
|
return {
|
|
25334
25972
|
ecosystem: data.ecosystem || "unknown",
|
|
@@ -25347,7 +25985,7 @@ var init_context = __esm({
|
|
|
25347
25985
|
});
|
|
25348
25986
|
|
|
25349
25987
|
// core/commands/cleanup.ts
|
|
25350
|
-
import
|
|
25988
|
+
import path55 from "node:path";
|
|
25351
25989
|
async function cleanupMemory(projectPath) {
|
|
25352
25990
|
const projectId = await config_manager_default.getProjectId(projectPath);
|
|
25353
25991
|
const results = { rotated: [], totalSize: 0, freedSpace: 0 };
|
|
@@ -25363,7 +26001,7 @@ async function cleanupMemory(projectPath) {
|
|
|
25363
26001
|
results.totalSize += sizeMB;
|
|
25364
26002
|
const rotated = await jsonl_helper_default.rotateJsonLinesIfNeeded(filePath, 10);
|
|
25365
26003
|
if (rotated) {
|
|
25366
|
-
results.rotated.push(
|
|
26004
|
+
results.rotated.push(path55.basename(filePath));
|
|
25367
26005
|
results.freedSpace += sizeMB;
|
|
25368
26006
|
}
|
|
25369
26007
|
}
|
|
@@ -25470,7 +26108,7 @@ var init_cleanup = __esm({
|
|
|
25470
26108
|
});
|
|
25471
26109
|
|
|
25472
26110
|
// core/commands/design.ts
|
|
25473
|
-
import
|
|
26111
|
+
import path56 from "node:path";
|
|
25474
26112
|
async function design(target = null, options = {}, projectPath = process.cwd()) {
|
|
25475
26113
|
try {
|
|
25476
26114
|
const designType = options.type || "architecture";
|
|
@@ -25482,7 +26120,7 @@ async function design(target = null, options = {}, projectPath = process.cwd())
|
|
|
25482
26120
|
const designTarget = target || "system";
|
|
25483
26121
|
output_default.spin(`designing ${designType}...`);
|
|
25484
26122
|
const projectId = await config_manager_default.getProjectId(projectPath);
|
|
25485
|
-
const designsPath =
|
|
26123
|
+
const designsPath = path56.join(
|
|
25486
26124
|
path_manager_default.getGlobalProjectPath(projectId),
|
|
25487
26125
|
"planning",
|
|
25488
26126
|
"designs"
|
|
@@ -25522,7 +26160,7 @@ async function design(target = null, options = {}, projectPath = process.cwd())
|
|
|
25522
26160
|
break;
|
|
25523
26161
|
}
|
|
25524
26162
|
const designFileName = `${designType}-${designTarget.toLowerCase().replace(/\s+/g, "-")}.md`;
|
|
25525
|
-
const designFilePath =
|
|
26163
|
+
const designFilePath = path56.join(designsPath, designFileName);
|
|
25526
26164
|
await file_helper_exports.writeFile(designFilePath, designContent);
|
|
25527
26165
|
await memoryService.log(projectPath, "design_created", {
|
|
25528
26166
|
type: designType,
|
|
@@ -25546,7 +26184,7 @@ var init_design = __esm({
|
|
|
25546
26184
|
});
|
|
25547
26185
|
|
|
25548
26186
|
// core/commands/snapshots.ts
|
|
25549
|
-
import
|
|
26187
|
+
import path57 from "node:path";
|
|
25550
26188
|
async function recover(projectPath = process.cwd()) {
|
|
25551
26189
|
try {
|
|
25552
26190
|
const projectId = await config_manager_default.getProjectId(projectPath);
|
|
@@ -25598,7 +26236,7 @@ async function undo(projectPath = process.cwd()) {
|
|
|
25598
26236
|
output_default.failWithHint("NO_PROJECT_ID");
|
|
25599
26237
|
return { success: false, error: "No project ID found" };
|
|
25600
26238
|
}
|
|
25601
|
-
const snapshotsPath =
|
|
26239
|
+
const snapshotsPath = path57.join(path_manager_default.getGlobalProjectPath(projectId), "snapshots");
|
|
25602
26240
|
await file_helper_exports.ensureDir(snapshotsPath);
|
|
25603
26241
|
const { execSync: execSync5 } = await import("node:child_process");
|
|
25604
26242
|
try {
|
|
@@ -25616,7 +26254,7 @@ async function undo(projectPath = process.cwd()) {
|
|
|
25616
26254
|
cwd: projectPath,
|
|
25617
26255
|
encoding: "utf-8"
|
|
25618
26256
|
});
|
|
25619
|
-
const snapshotFile =
|
|
26257
|
+
const snapshotFile = path57.join(snapshotsPath, "history.json");
|
|
25620
26258
|
let history2 = { snapshots: [], current: -1 };
|
|
25621
26259
|
try {
|
|
25622
26260
|
const content = await file_helper_exports.readFile(snapshotFile);
|
|
@@ -25656,8 +26294,8 @@ async function redo(projectPath = process.cwd()) {
|
|
|
25656
26294
|
output_default.failWithHint("NO_PROJECT_ID");
|
|
25657
26295
|
return { success: false, error: "No project ID found" };
|
|
25658
26296
|
}
|
|
25659
|
-
const snapshotsPath =
|
|
25660
|
-
const snapshotFile =
|
|
26297
|
+
const snapshotsPath = path57.join(path_manager_default.getGlobalProjectPath(projectId), "snapshots");
|
|
26298
|
+
const snapshotFile = path57.join(snapshotsPath, "history.json");
|
|
25661
26299
|
let history2;
|
|
25662
26300
|
try {
|
|
25663
26301
|
const content = await file_helper_exports.readFile(snapshotFile);
|
|
@@ -25716,8 +26354,8 @@ async function history(projectPath = process.cwd()) {
|
|
|
25716
26354
|
output_default.failWithHint("NO_PROJECT_ID");
|
|
25717
26355
|
return { success: false, error: "No project ID found" };
|
|
25718
26356
|
}
|
|
25719
|
-
const snapshotsPath =
|
|
25720
|
-
const snapshotFile =
|
|
26357
|
+
const snapshotsPath = path57.join(path_manager_default.getGlobalProjectPath(projectId), "snapshots");
|
|
26358
|
+
const snapshotFile = path57.join(snapshotsPath, "history.json");
|
|
25721
26359
|
let snapshotHistory;
|
|
25722
26360
|
try {
|
|
25723
26361
|
const content = await file_helper_exports.readFile(snapshotFile);
|
|
@@ -25824,8 +26462,8 @@ var init_maintenance = __esm({
|
|
|
25824
26462
|
});
|
|
25825
26463
|
|
|
25826
26464
|
// core/commands/setup.ts
|
|
25827
|
-
import
|
|
25828
|
-
import
|
|
26465
|
+
import fs49 from "node:fs/promises";
|
|
26466
|
+
import path58 from "node:path";
|
|
25829
26467
|
import chalk16 from "chalk";
|
|
25830
26468
|
var SetupCommands;
|
|
25831
26469
|
var init_setup2 = __esm({
|
|
@@ -25953,7 +26591,7 @@ Please install it first:
|
|
|
25953
26591
|
try {
|
|
25954
26592
|
const claudeDir = path_manager_default.getClaudeDir();
|
|
25955
26593
|
const settingsPath = path_manager_default.getClaudeSettingsPath();
|
|
25956
|
-
const statusLinePath =
|
|
26594
|
+
const statusLinePath = path58.join(claudeDir, "prjct-statusline.sh");
|
|
25957
26595
|
const scriptContent = `#!/bin/bash
|
|
25958
26596
|
# prjct Status Line for Claude Code
|
|
25959
26597
|
# Shows version update notifications and current task
|
|
@@ -26011,11 +26649,11 @@ fi
|
|
|
26011
26649
|
# Default: show prjct branding
|
|
26012
26650
|
echo "\u26A1 prjct"
|
|
26013
26651
|
`;
|
|
26014
|
-
await
|
|
26652
|
+
await fs49.writeFile(statusLinePath, scriptContent, { mode: 493 });
|
|
26015
26653
|
let settings = {};
|
|
26016
26654
|
if (await fileExists(settingsPath)) {
|
|
26017
26655
|
try {
|
|
26018
|
-
settings = JSON.parse(await
|
|
26656
|
+
settings = JSON.parse(await fs49.readFile(settingsPath, "utf8"));
|
|
26019
26657
|
} catch (_error) {
|
|
26020
26658
|
}
|
|
26021
26659
|
}
|
|
@@ -26023,7 +26661,7 @@ echo "\u26A1 prjct"
|
|
|
26023
26661
|
type: "command",
|
|
26024
26662
|
command: statusLinePath
|
|
26025
26663
|
};
|
|
26026
|
-
await
|
|
26664
|
+
await fs49.writeFile(settingsPath, JSON.stringify(settings, null, 2));
|
|
26027
26665
|
return { success: true };
|
|
26028
26666
|
} catch (error) {
|
|
26029
26667
|
return { success: false, error: error.message };
|
|
@@ -26079,18 +26717,18 @@ echo "\u26A1 prjct"
|
|
|
26079
26717
|
});
|
|
26080
26718
|
|
|
26081
26719
|
// core/utils/project-commands.ts
|
|
26082
|
-
import
|
|
26720
|
+
import path59 from "node:path";
|
|
26083
26721
|
async function detectPackageManager(projectPath, pkg) {
|
|
26084
26722
|
const declared = pkg?.packageManager?.trim().toLowerCase();
|
|
26085
26723
|
if (declared?.startsWith("pnpm@")) return "pnpm";
|
|
26086
26724
|
if (declared?.startsWith("yarn@")) return "yarn";
|
|
26087
26725
|
if (declared?.startsWith("bun@")) return "bun";
|
|
26088
26726
|
if (declared?.startsWith("npm@")) return "npm";
|
|
26089
|
-
if (await fileExists2(
|
|
26090
|
-
if (await fileExists2(
|
|
26091
|
-
if (await fileExists2(
|
|
26092
|
-
if (await fileExists2(
|
|
26093
|
-
if (await fileExists2(
|
|
26727
|
+
if (await fileExists2(path59.join(projectPath, "pnpm-lock.yaml"))) return "pnpm";
|
|
26728
|
+
if (await fileExists2(path59.join(projectPath, "yarn.lock"))) return "yarn";
|
|
26729
|
+
if (await fileExists2(path59.join(projectPath, "bun.lockb"))) return "bun";
|
|
26730
|
+
if (await fileExists2(path59.join(projectPath, "bun.lock"))) return "bun";
|
|
26731
|
+
if (await fileExists2(path59.join(projectPath, "package-lock.json"))) return "npm";
|
|
26094
26732
|
return "npm";
|
|
26095
26733
|
}
|
|
26096
26734
|
function pmRun(pm, scriptName) {
|
|
@@ -26106,7 +26744,7 @@ function pmTest(pm) {
|
|
|
26106
26744
|
return "npm test";
|
|
26107
26745
|
}
|
|
26108
26746
|
async function detectProjectCommands(projectPath) {
|
|
26109
|
-
const pkgPath =
|
|
26747
|
+
const pkgPath = path59.join(projectPath, "package.json");
|
|
26110
26748
|
const pkg = await readJson(pkgPath, null);
|
|
26111
26749
|
if (pkg) {
|
|
26112
26750
|
const pm = await detectPackageManager(projectPath, pkg);
|
|
@@ -26123,27 +26761,27 @@ async function detectProjectCommands(projectPath) {
|
|
|
26123
26761
|
}
|
|
26124
26762
|
return result;
|
|
26125
26763
|
}
|
|
26126
|
-
if (await fileExists2(
|
|
26764
|
+
if (await fileExists2(path59.join(projectPath, "pytest.ini"))) {
|
|
26127
26765
|
return { stack: "python", test: { tool: "pytest", command: "pytest" } };
|
|
26128
26766
|
}
|
|
26129
|
-
const pyproject = await readFile(
|
|
26767
|
+
const pyproject = await readFile(path59.join(projectPath, "pyproject.toml"), "");
|
|
26130
26768
|
if (pyproject.includes("[tool.pytest") || pyproject.includes("pytest")) {
|
|
26131
26769
|
return { stack: "python", test: { tool: "pytest", command: "pytest" } };
|
|
26132
26770
|
}
|
|
26133
|
-
if (await fileExists2(
|
|
26771
|
+
if (await fileExists2(path59.join(projectPath, "Cargo.toml"))) {
|
|
26134
26772
|
return { stack: "rust", test: { tool: "cargo", command: "cargo test" } };
|
|
26135
26773
|
}
|
|
26136
|
-
if (await fileExists2(
|
|
26774
|
+
if (await fileExists2(path59.join(projectPath, "go.mod"))) {
|
|
26137
26775
|
return { stack: "go", test: { tool: "go", command: "go test ./..." } };
|
|
26138
26776
|
}
|
|
26139
26777
|
const files = await listFiles(projectPath);
|
|
26140
26778
|
if (files.some((f) => f.endsWith(".sln") || f.endsWith(".csproj") || f.endsWith(".fsproj"))) {
|
|
26141
26779
|
return { stack: "dotnet", test: { tool: "dotnet", command: "dotnet test" } };
|
|
26142
26780
|
}
|
|
26143
|
-
if (await fileExists2(
|
|
26781
|
+
if (await fileExists2(path59.join(projectPath, "pom.xml"))) {
|
|
26144
26782
|
return { stack: "java", test: { tool: "maven", command: "mvn test" } };
|
|
26145
26783
|
}
|
|
26146
|
-
if (await fileExists2(
|
|
26784
|
+
if (await fileExists2(path59.join(projectPath, "gradlew")) && (await fileExists2(path59.join(projectPath, "build.gradle")) || await fileExists2(path59.join(projectPath, "build.gradle.kts")))) {
|
|
26147
26785
|
return { stack: "java", test: { tool: "gradle", command: "./gradlew test" } };
|
|
26148
26786
|
}
|
|
26149
26787
|
return { stack: "unknown" };
|
|
@@ -26160,8 +26798,8 @@ var init_project_commands = __esm({
|
|
|
26160
26798
|
});
|
|
26161
26799
|
|
|
26162
26800
|
// core/workflow/workflow-preferences.ts
|
|
26163
|
-
import { exec as
|
|
26164
|
-
import { promisify as
|
|
26801
|
+
import { exec as exec17 } from "node:child_process";
|
|
26802
|
+
import { promisify as promisify18 } from "node:util";
|
|
26165
26803
|
import chalk17 from "chalk";
|
|
26166
26804
|
function prefKey(hook, command) {
|
|
26167
26805
|
return `workflow:${hook}_${command}`;
|
|
@@ -26233,7 +26871,7 @@ async function runWorkflowHooks(projectId, phase, command, options = {}) {
|
|
|
26233
26871
|
${chalk17.dim(`Running ${phase}-${command}: ${action}`)}`);
|
|
26234
26872
|
try {
|
|
26235
26873
|
const startTime = Date.now();
|
|
26236
|
-
await
|
|
26874
|
+
await execAsync12(action, {
|
|
26237
26875
|
timeout: 6e4,
|
|
26238
26876
|
cwd: options.projectPath || process.cwd(),
|
|
26239
26877
|
env: { ...process.env }
|
|
@@ -26297,12 +26935,12 @@ Set one: "p. workflow antes de ship corre los tests"`;
|
|
|
26297
26935
|
lines.push(chalk17.dim('Remove: "p. workflow quita el hook de ship"'));
|
|
26298
26936
|
return lines.join("\n");
|
|
26299
26937
|
}
|
|
26300
|
-
var
|
|
26938
|
+
var execAsync12, sessionPreferences, oncePreferences;
|
|
26301
26939
|
var init_workflow_preferences = __esm({
|
|
26302
26940
|
"core/workflow/workflow-preferences.ts"() {
|
|
26303
26941
|
"use strict";
|
|
26304
26942
|
init_memory_system();
|
|
26305
|
-
|
|
26943
|
+
execAsync12 = promisify18(exec17);
|
|
26306
26944
|
sessionPreferences = /* @__PURE__ */ new Map();
|
|
26307
26945
|
oncePreferences = /* @__PURE__ */ new Map();
|
|
26308
26946
|
__name(prefKey, "prefKey");
|
|
@@ -26316,7 +26954,7 @@ var init_workflow_preferences = __esm({
|
|
|
26316
26954
|
});
|
|
26317
26955
|
|
|
26318
26956
|
// core/commands/shipping.ts
|
|
26319
|
-
import
|
|
26957
|
+
import path60 from "node:path";
|
|
26320
26958
|
var ShippingCommands;
|
|
26321
26959
|
var init_shipping = __esm({
|
|
26322
26960
|
"core/commands/shipping.ts"() {
|
|
@@ -26462,7 +27100,7 @@ ${result.stderr}`.trim();
|
|
|
26462
27100
|
*/
|
|
26463
27101
|
async _bumpVersion(projectPath) {
|
|
26464
27102
|
try {
|
|
26465
|
-
const pkgPath =
|
|
27103
|
+
const pkgPath = path60.join(projectPath, "package.json");
|
|
26466
27104
|
const pkg = await file_helper_exports.readJson(pkgPath, { version: "0.0.0" });
|
|
26467
27105
|
const oldVersion = pkg?.version || "0.0.0";
|
|
26468
27106
|
const [major, minor, patch] = oldVersion.split(".").map(Number);
|
|
@@ -26484,7 +27122,7 @@ ${result.stderr}`.trim();
|
|
|
26484
27122
|
*/
|
|
26485
27123
|
async _updateChangelog(feature, version, projectPath) {
|
|
26486
27124
|
try {
|
|
26487
|
-
const changelogPath =
|
|
27125
|
+
const changelogPath = path60.join(projectPath, "CHANGELOG.md");
|
|
26488
27126
|
const changelog = await file_helper_exports.readFile(changelogPath, "# Changelog\n\n");
|
|
26489
27127
|
const entry = `## [${version}] - ${date_helper_default.formatDate(/* @__PURE__ */ new Date())}
|
|
26490
27128
|
|
|
@@ -26583,14 +27221,14 @@ var init_cache2 = __esm({
|
|
|
26583
27221
|
});
|
|
26584
27222
|
|
|
26585
27223
|
// core/utils/keychain.ts
|
|
26586
|
-
import { exec as
|
|
26587
|
-
import { promisify as
|
|
27224
|
+
import { exec as exec18 } from "node:child_process";
|
|
27225
|
+
import { promisify as promisify19 } from "node:util";
|
|
26588
27226
|
async function getCredential(key) {
|
|
26589
27227
|
if (process.platform !== "darwin") {
|
|
26590
27228
|
return getEnvFallback(key);
|
|
26591
27229
|
}
|
|
26592
27230
|
try {
|
|
26593
|
-
const { stdout } = await
|
|
27231
|
+
const { stdout } = await execAsync13(
|
|
26594
27232
|
`security find-generic-password -s "${SERVICE_NAME}" -a "${key}" -w 2>/dev/null`
|
|
26595
27233
|
);
|
|
26596
27234
|
return stdout.trim() || null;
|
|
@@ -26606,11 +27244,11 @@ function getEnvFallback(key) {
|
|
|
26606
27244
|
const envVar = envMap[key];
|
|
26607
27245
|
return process.env[envVar] || null;
|
|
26608
27246
|
}
|
|
26609
|
-
var
|
|
27247
|
+
var execAsync13, SERVICE_NAME;
|
|
26610
27248
|
var init_keychain = __esm({
|
|
26611
27249
|
"core/utils/keychain.ts"() {
|
|
26612
27250
|
"use strict";
|
|
26613
|
-
|
|
27251
|
+
execAsync13 = promisify19(exec18);
|
|
26614
27252
|
SERVICE_NAME = "prjct-cli";
|
|
26615
27253
|
__name(getCredential, "getCredential");
|
|
26616
27254
|
__name(getEnvFallback, "getEnvFallback");
|
|
@@ -27376,11 +28014,11 @@ var init_linear = __esm({
|
|
|
27376
28014
|
});
|
|
27377
28015
|
|
|
27378
28016
|
// core/utils/project-credentials.ts
|
|
27379
|
-
import
|
|
27380
|
-
import
|
|
27381
|
-
import
|
|
28017
|
+
import fs50 from "node:fs/promises";
|
|
28018
|
+
import os17 from "node:os";
|
|
28019
|
+
import path61 from "node:path";
|
|
27382
28020
|
function getCredentialsPath(projectId) {
|
|
27383
|
-
return
|
|
28021
|
+
return path61.join(os17.homedir(), ".prjct-cli", "projects", projectId, "config", "credentials.json");
|
|
27384
28022
|
}
|
|
27385
28023
|
async function getProjectCredentials(projectId) {
|
|
27386
28024
|
const credPath = getCredentialsPath(projectId);
|
|
@@ -27388,7 +28026,7 @@ async function getProjectCredentials(projectId) {
|
|
|
27388
28026
|
return {};
|
|
27389
28027
|
}
|
|
27390
28028
|
try {
|
|
27391
|
-
return JSON.parse(await
|
|
28029
|
+
return JSON.parse(await fs50.readFile(credPath, "utf-8"));
|
|
27392
28030
|
} catch (error) {
|
|
27393
28031
|
console.error("[project-credentials] Failed to read credentials:", error.message);
|
|
27394
28032
|
return {};
|
|
@@ -27966,7 +28604,7 @@ var require_package = __commonJS({
|
|
|
27966
28604
|
"package.json"(exports, module) {
|
|
27967
28605
|
module.exports = {
|
|
27968
28606
|
name: "prjct-cli",
|
|
27969
|
-
version: "1.
|
|
28607
|
+
version: "1.6.1",
|
|
27970
28608
|
description: "Context layer for AI agents. Project context for Claude Code, Gemini CLI, and more.",
|
|
27971
28609
|
main: "core/index.ts",
|
|
27972
28610
|
bin: {
|
|
@@ -28073,8 +28711,8 @@ var require_package = __commonJS({
|
|
|
28073
28711
|
|
|
28074
28712
|
// core/index.ts
|
|
28075
28713
|
var core_exports = {};
|
|
28076
|
-
import
|
|
28077
|
-
import
|
|
28714
|
+
import os18 from "node:os";
|
|
28715
|
+
import path62 from "node:path";
|
|
28078
28716
|
import chalk18 from "chalk";
|
|
28079
28717
|
async function main() {
|
|
28080
28718
|
const [commandName, ...rawArgs] = process.argv.slice(2);
|
|
@@ -28271,13 +28909,13 @@ function parseCommandArgs(_cmd, rawArgs) {
|
|
|
28271
28909
|
}
|
|
28272
28910
|
async function displayVersion(version) {
|
|
28273
28911
|
const detection = await detectAllProviders();
|
|
28274
|
-
const claudeCommandPath =
|
|
28275
|
-
const geminiCommandPath =
|
|
28912
|
+
const claudeCommandPath = path62.join(os18.homedir(), ".claude", "commands", "p.md");
|
|
28913
|
+
const geminiCommandPath = path62.join(os18.homedir(), ".gemini", "commands", "p.toml");
|
|
28276
28914
|
const [claudeConfigured, geminiConfigured, cursorConfigured, cursorExists] = await Promise.all([
|
|
28277
28915
|
fileExists(claudeCommandPath),
|
|
28278
28916
|
fileExists(geminiCommandPath),
|
|
28279
|
-
fileExists(
|
|
28280
|
-
fileExists(
|
|
28917
|
+
fileExists(path62.join(process.cwd(), ".cursor", "commands", "sync.md")),
|
|
28918
|
+
fileExists(path62.join(process.cwd(), ".cursor"))
|
|
28281
28919
|
]);
|
|
28282
28920
|
const antigravityDetection = await detectAntigravity();
|
|
28283
28921
|
console.log(`
|
|
@@ -28413,8 +29051,8 @@ var init_core = __esm({
|
|
|
28413
29051
|
init_ai_provider();
|
|
28414
29052
|
init_config_manager();
|
|
28415
29053
|
init_editors_config();
|
|
28416
|
-
import
|
|
28417
|
-
import
|
|
29054
|
+
import os19 from "node:os";
|
|
29055
|
+
import path63 from "node:path";
|
|
28418
29056
|
import chalk19 from "chalk";
|
|
28419
29057
|
|
|
28420
29058
|
// core/server/server.ts
|
|
@@ -29155,16 +29793,16 @@ __name(startServer, "startServer");
|
|
|
29155
29793
|
init_fs_helpers();
|
|
29156
29794
|
init_version();
|
|
29157
29795
|
async function checkRoutersInstalled() {
|
|
29158
|
-
const home =
|
|
29796
|
+
const home = os19.homedir();
|
|
29159
29797
|
const detection = await detectAllProviders();
|
|
29160
29798
|
if (detection.claude.installed) {
|
|
29161
|
-
const claudeRouter =
|
|
29799
|
+
const claudeRouter = path63.join(home, ".claude", "commands", "p.md");
|
|
29162
29800
|
if (!await fileExists(claudeRouter)) {
|
|
29163
29801
|
return false;
|
|
29164
29802
|
}
|
|
29165
29803
|
}
|
|
29166
29804
|
if (detection.gemini.installed) {
|
|
29167
|
-
const geminiRouter =
|
|
29805
|
+
const geminiRouter = path63.join(home, ".gemini", "commands", "p.toml");
|
|
29168
29806
|
if (!await fileExists(geminiRouter)) {
|
|
29169
29807
|
return false;
|
|
29170
29808
|
}
|
|
@@ -29292,7 +29930,7 @@ if (args[0] === "start" || args[0] === "setup") {
|
|
|
29292
29930
|
console.error('No prjct project found. Run "prjct init" first.');
|
|
29293
29931
|
process.exitCode = 1;
|
|
29294
29932
|
} else {
|
|
29295
|
-
const linearCliPath =
|
|
29933
|
+
const linearCliPath = path63.join(__dirname, "..", "core", "cli", "linear.ts");
|
|
29296
29934
|
const linearArgs = ["--project", projectId, ...args.slice(1)];
|
|
29297
29935
|
const child = spawn("bun", [linearCliPath, ...linearArgs], {
|
|
29298
29936
|
stdio: "inherit",
|
|
@@ -29309,7 +29947,7 @@ if (args[0] === "start" || args[0] === "setup") {
|
|
|
29309
29947
|
process.exitCode = 0;
|
|
29310
29948
|
} else if (args[0] === "version" || args[0] === "-v" || args[0] === "--version") {
|
|
29311
29949
|
const detection = await detectAllProviders();
|
|
29312
|
-
const home =
|
|
29950
|
+
const home = os19.homedir();
|
|
29313
29951
|
const cwd = process.cwd();
|
|
29314
29952
|
const [
|
|
29315
29953
|
claudeConfigured,
|
|
@@ -29319,12 +29957,12 @@ if (args[0] === "start" || args[0] === "setup") {
|
|
|
29319
29957
|
windsurfDetected,
|
|
29320
29958
|
windsurfConfigured
|
|
29321
29959
|
] = await Promise.all([
|
|
29322
|
-
fileExists(
|
|
29323
|
-
fileExists(
|
|
29324
|
-
fileExists(
|
|
29325
|
-
fileExists(
|
|
29326
|
-
fileExists(
|
|
29327
|
-
fileExists(
|
|
29960
|
+
fileExists(path63.join(home, ".claude", "commands", "p.md")),
|
|
29961
|
+
fileExists(path63.join(home, ".gemini", "commands", "p.toml")),
|
|
29962
|
+
fileExists(path63.join(cwd, ".cursor")),
|
|
29963
|
+
fileExists(path63.join(cwd, ".cursor", "rules", "prjct.mdc")),
|
|
29964
|
+
fileExists(path63.join(cwd, ".windsurf")),
|
|
29965
|
+
fileExists(path63.join(cwd, ".windsurf", "rules", "prjct.md"))
|
|
29328
29966
|
]);
|
|
29329
29967
|
console.log(`
|
|
29330
29968
|
${chalk19.cyan("p/")} prjct v${VERSION}
|
|
@@ -29363,7 +30001,7 @@ ${chalk19.dim("Run 'prjct init' to configure (Cursor/Windsurf IDE)")}
|
|
|
29363
30001
|
${chalk19.cyan("https://prjct.app")}
|
|
29364
30002
|
`);
|
|
29365
30003
|
} else {
|
|
29366
|
-
const configPath =
|
|
30004
|
+
const configPath = path63.join(os19.homedir(), ".prjct-cli", "config", "installed-editors.json");
|
|
29367
30005
|
const routersInstalled = await checkRoutersInstalled();
|
|
29368
30006
|
if (!await fileExists(configPath) || !routersInstalled) {
|
|
29369
30007
|
console.log(`
|