lean-spec 0.2.5-dev.20251120070726 → 0.2.5-dev.20251120093243
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.
|
@@ -6984,7 +6984,7 @@ function detectPackageManager(baseDir = process.cwd()) {
|
|
|
6984
6984
|
|
|
6985
6985
|
// src/commands/ui.ts
|
|
6986
6986
|
function uiCommand() {
|
|
6987
|
-
return new Command("ui").description("Start local web UI for spec management").option("-s, --specs <dir>", "Specs directory (auto-detected if not specified)").option("-p, --port <port>", "Port to run on", "3000").option("--no-open", "Don't open browser automatically").option("--dev", "Run in development mode (only works in LeanSpec monorepo)").option("--dry-run", "Show what would run without executing").action(async (options) => {
|
|
6987
|
+
return new Command("ui").description("Start local web UI for spec management").option("-s, --specs <dir>", "Specs directory (auto-detected if not specified)").option("-p, --port <port>", "Port to run on", "3000").option("--no-open", "Don't open browser automatically").option("--multi-project", "Enable multi-project mode").option("--add-project <path>", "Add a project to multi-project registry").option("--discover <path>", "Discover LeanSpec projects in directory tree").option("--dev", "Run in development mode (only works in LeanSpec monorepo)").option("--dry-run", "Show what would run without executing").action(async (options) => {
|
|
6988
6988
|
try {
|
|
6989
6989
|
await startUi(options);
|
|
6990
6990
|
} catch (error) {
|
|
@@ -7000,17 +7000,28 @@ async function startUi(options) {
|
|
|
7000
7000
|
throw new Error(`Invalid port: ${options.port}`);
|
|
7001
7001
|
}
|
|
7002
7002
|
const cwd = process.cwd();
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7003
|
+
const specsMode = options.multiProject ? "multi-project" : "filesystem";
|
|
7004
|
+
let specsDir = "";
|
|
7005
|
+
if (!options.multiProject) {
|
|
7006
|
+
if (options.specs) {
|
|
7007
|
+
specsDir = resolve(cwd, options.specs);
|
|
7008
|
+
} else {
|
|
7009
|
+
const config = await loadConfig(cwd);
|
|
7010
|
+
specsDir = join(cwd, config.specsDir);
|
|
7011
|
+
}
|
|
7012
|
+
if (!existsSync(specsDir)) {
|
|
7013
|
+
console.error(chalk18.red(`\u2717 Specs directory not found: ${specsDir}`));
|
|
7014
|
+
console.log(chalk18.dim("\nRun `lean-spec init` to initialize LeanSpec in this directory."));
|
|
7015
|
+
throw new Error(`Specs directory not found: ${specsDir}`);
|
|
7016
|
+
}
|
|
7006
7017
|
} else {
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
}
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7018
|
+
console.log(chalk18.cyan("\u2192 Multi-project mode enabled"));
|
|
7019
|
+
if (options.addProject) {
|
|
7020
|
+
console.log(chalk18.dim(` Adding project: ${options.addProject}`));
|
|
7021
|
+
}
|
|
7022
|
+
if (options.discover) {
|
|
7023
|
+
console.log(chalk18.dim(` Will discover projects in: ${options.discover}`));
|
|
7024
|
+
}
|
|
7014
7025
|
}
|
|
7015
7026
|
if (options.dev) {
|
|
7016
7027
|
const isLeanSpecMonorepo = checkIsLeanSpecMonorepo(cwd);
|
|
@@ -7020,9 +7031,9 @@ async function startUi(options) {
|
|
|
7020
7031
|
throw new Error("Not in LeanSpec monorepo");
|
|
7021
7032
|
}
|
|
7022
7033
|
const localUiDir = join(cwd, "packages/ui");
|
|
7023
|
-
return runLocalWeb(localUiDir, specsDir, options);
|
|
7034
|
+
return runLocalWeb(localUiDir, specsDir, specsMode, options);
|
|
7024
7035
|
}
|
|
7025
|
-
return runPublishedUI(cwd, specsDir, options);
|
|
7036
|
+
return runPublishedUI(cwd, specsDir, specsMode, options);
|
|
7026
7037
|
}
|
|
7027
7038
|
function checkIsLeanSpecMonorepo(cwd) {
|
|
7028
7039
|
const localUiDir = join(cwd, "packages/ui");
|
|
@@ -7037,14 +7048,14 @@ function checkIsLeanSpecMonorepo(cwd) {
|
|
|
7037
7048
|
return false;
|
|
7038
7049
|
}
|
|
7039
7050
|
}
|
|
7040
|
-
async function runLocalWeb(uiDir, specsDir, options) {
|
|
7051
|
+
async function runLocalWeb(uiDir, specsDir, specsMode, options) {
|
|
7041
7052
|
console.log(chalk18.dim("\u2192 Detected LeanSpec monorepo, using local ui package\n"));
|
|
7042
7053
|
const repoRoot = resolve(uiDir, "..", "..");
|
|
7043
7054
|
const packageManager = detectPackageManager(repoRoot);
|
|
7044
7055
|
if (options.dryRun) {
|
|
7045
7056
|
console.log(chalk18.cyan("Would run:"));
|
|
7046
7057
|
console.log(chalk18.dim(` cd ${uiDir}`));
|
|
7047
|
-
console.log(chalk18.dim(` SPECS_MODE
|
|
7058
|
+
console.log(chalk18.dim(` SPECS_MODE=${specsMode} SPECS_DIR=${specsDir} PORT=${options.port} ${packageManager} run dev`));
|
|
7048
7059
|
if (options.open) {
|
|
7049
7060
|
console.log(chalk18.dim(` open http://localhost:${options.port}`));
|
|
7050
7061
|
}
|
|
@@ -7053,8 +7064,8 @@ async function runLocalWeb(uiDir, specsDir, options) {
|
|
|
7053
7064
|
const spinner = ora("Starting web UI...").start();
|
|
7054
7065
|
const env = {
|
|
7055
7066
|
...process.env,
|
|
7056
|
-
SPECS_MODE:
|
|
7057
|
-
SPECS_DIR: specsDir,
|
|
7067
|
+
SPECS_MODE: specsMode,
|
|
7068
|
+
SPECS_DIR: specsDir || "",
|
|
7058
7069
|
PORT: options.port
|
|
7059
7070
|
};
|
|
7060
7071
|
const child = spawn(packageManager, ["run", "dev"], {
|
|
@@ -7068,7 +7079,55 @@ async function runLocalWeb(uiDir, specsDir, options) {
|
|
|
7068
7079
|
console.log(chalk18.green(`
|
|
7069
7080
|
\u2728 LeanSpec UI: http://localhost:${options.port}
|
|
7070
7081
|
`));
|
|
7071
|
-
|
|
7082
|
+
if (options.multiProject) {
|
|
7083
|
+
console.log(chalk18.cyan("Multi-project mode is active"));
|
|
7084
|
+
if (options.addProject) {
|
|
7085
|
+
try {
|
|
7086
|
+
const res = await fetch(`http://localhost:${options.port}/api/projects`, {
|
|
7087
|
+
method: "POST",
|
|
7088
|
+
headers: { "Content-Type": "application/json" },
|
|
7089
|
+
body: JSON.stringify({ path: options.addProject })
|
|
7090
|
+
});
|
|
7091
|
+
if (res.ok) {
|
|
7092
|
+
console.log(chalk18.green(` \u2713 Added project: ${options.addProject}`));
|
|
7093
|
+
} else {
|
|
7094
|
+
console.error(chalk18.red(` \u2717 Failed to add project: ${options.addProject}`));
|
|
7095
|
+
}
|
|
7096
|
+
} catch (e) {
|
|
7097
|
+
console.error(chalk18.red(` \u2717 Failed to connect to server for adding project`));
|
|
7098
|
+
}
|
|
7099
|
+
}
|
|
7100
|
+
if (options.discover) {
|
|
7101
|
+
console.log(chalk18.dim(` Discovering projects in: ${options.discover}...`));
|
|
7102
|
+
try {
|
|
7103
|
+
const res = await fetch(`http://localhost:${options.port}/api/local-projects/discover`, {
|
|
7104
|
+
method: "POST",
|
|
7105
|
+
headers: { "Content-Type": "application/json" },
|
|
7106
|
+
body: JSON.stringify({ path: options.discover })
|
|
7107
|
+
});
|
|
7108
|
+
if (res.ok) {
|
|
7109
|
+
const data = await res.json();
|
|
7110
|
+
const discovered = data.discovered || [];
|
|
7111
|
+
console.log(chalk18.green(` \u2713 Found ${discovered.length} projects`));
|
|
7112
|
+
for (const p of discovered) {
|
|
7113
|
+
const addRes = await fetch(`http://localhost:${options.port}/api/projects`, {
|
|
7114
|
+
method: "POST",
|
|
7115
|
+
headers: { "Content-Type": "application/json" },
|
|
7116
|
+
body: JSON.stringify({ path: p.path })
|
|
7117
|
+
});
|
|
7118
|
+
if (addRes.ok) {
|
|
7119
|
+
console.log(chalk18.dim(` + Added: ${p.name} (${p.path})`));
|
|
7120
|
+
}
|
|
7121
|
+
}
|
|
7122
|
+
} else {
|
|
7123
|
+
console.error(chalk18.red(` \u2717 Failed to discover projects`));
|
|
7124
|
+
}
|
|
7125
|
+
} catch (e) {
|
|
7126
|
+
console.error(chalk18.red(` \u2717 Failed to connect to server for discovery`));
|
|
7127
|
+
}
|
|
7128
|
+
}
|
|
7129
|
+
}
|
|
7130
|
+
console.log(chalk18.dim("\nPress Ctrl+C to stop\n"));
|
|
7072
7131
|
if (options.open) {
|
|
7073
7132
|
try {
|
|
7074
7133
|
const openModule = await import('open');
|
|
@@ -7115,10 +7174,10 @@ Process exited with code ${code}`));
|
|
|
7115
7174
|
process.exit(0);
|
|
7116
7175
|
});
|
|
7117
7176
|
}
|
|
7118
|
-
async function runPublishedUI(cwd, specsDir, options) {
|
|
7177
|
+
async function runPublishedUI(cwd, specsDir, specsMode, options) {
|
|
7119
7178
|
console.log(chalk18.dim("\u2192 Using published @leanspec/ui package\n"));
|
|
7120
7179
|
const packageManager = detectPackageManager(cwd);
|
|
7121
|
-
const { command, args, preview } = buildUiRunner(packageManager, specsDir, options.port, options.open);
|
|
7180
|
+
const { command, args, preview } = buildUiRunner(packageManager, specsDir, specsMode, options.port, options.open, options.multiProject);
|
|
7122
7181
|
if (options.dryRun) {
|
|
7123
7182
|
console.log(chalk18.cyan("Would run:"));
|
|
7124
7183
|
console.log(chalk18.dim(` ${preview}`));
|
|
@@ -7165,8 +7224,14 @@ async function runPublishedUI(cwd, specsDir, options) {
|
|
|
7165
7224
|
process.exit(1);
|
|
7166
7225
|
});
|
|
7167
7226
|
}
|
|
7168
|
-
function buildUiRunner(packageManager, specsDir, port, openBrowser) {
|
|
7169
|
-
const uiArgs = ["@leanspec/ui"
|
|
7227
|
+
function buildUiRunner(packageManager, specsDir, specsMode, port, openBrowser, multiProject) {
|
|
7228
|
+
const uiArgs = ["@leanspec/ui"];
|
|
7229
|
+
if (!multiProject) {
|
|
7230
|
+
uiArgs.push("--specs", specsDir);
|
|
7231
|
+
} else {
|
|
7232
|
+
uiArgs.push("--multi-project");
|
|
7233
|
+
}
|
|
7234
|
+
uiArgs.push("--port", port);
|
|
7170
7235
|
if (!openBrowser) {
|
|
7171
7236
|
uiArgs.push("--no-open");
|
|
7172
7237
|
}
|
|
@@ -8348,53 +8413,83 @@ function registerResources(server) {
|
|
|
8348
8413
|
server.registerResource(...specResource());
|
|
8349
8414
|
server.registerResource(...statsResource());
|
|
8350
8415
|
}
|
|
8351
|
-
function
|
|
8416
|
+
function planProjectRoadmapPrompt() {
|
|
8352
8417
|
return [
|
|
8353
|
-
"
|
|
8418
|
+
"plan-project-roadmap",
|
|
8354
8419
|
{
|
|
8355
|
-
title: "
|
|
8356
|
-
description: "
|
|
8420
|
+
title: "Plan Project Roadmap",
|
|
8421
|
+
description: "Interactive roadmap planning with phases, tasks, and dependencies",
|
|
8357
8422
|
argsSchema: {
|
|
8358
|
-
|
|
8359
|
-
description: z.string().optional()
|
|
8423
|
+
goal: z.string()
|
|
8360
8424
|
}
|
|
8361
8425
|
},
|
|
8362
|
-
({
|
|
8426
|
+
({ goal }) => ({
|
|
8363
8427
|
messages: [
|
|
8364
8428
|
{
|
|
8365
8429
|
role: "user",
|
|
8366
8430
|
content: {
|
|
8367
8431
|
type: "text",
|
|
8368
|
-
text: `
|
|
8432
|
+
text: `Plan a project roadmap for: ${goal}
|
|
8369
8433
|
|
|
8370
|
-
|
|
8434
|
+
1. **Review Existing Work**: Analyze current specs using \`list\`/\`board\`, identify what's already planned/in-progress, assess how existing work relates to the new goal
|
|
8435
|
+
2. **Break Down Goal**: Decompose the goal into logical phases or milestones
|
|
8436
|
+
3. **Identify Tasks**: List key tasks and work items for each phase
|
|
8437
|
+
4. **Map Dependencies**: Establish dependencies between tasks (what must be done first)
|
|
8438
|
+
5. **Create Specs**: Create specification documents for major work items using the \`create\` tool
|
|
8439
|
+
6. **Set Relationships**: Use \`link\` tool to establish \`depends_on\` and \`related\` relationships
|
|
8440
|
+
7. **Timeline Estimation**: Provide realistic timeline based on task complexity and project velocity
|
|
8441
|
+
8. **Risk Analysis**: Identify risks, unknowns, and mitigation strategies
|
|
8371
8442
|
|
|
8372
|
-
|
|
8443
|
+
Use the following tools to build the roadmap:
|
|
8444
|
+
- \`list\` / \`board\` / \`stats\` - Understand current project state
|
|
8445
|
+
- \`create\` - Create new specs for roadmap items
|
|
8446
|
+
- \`link\` - Establish dependencies between specs
|
|
8447
|
+
- \`update\` - Set priority and metadata
|
|
8448
|
+
|
|
8449
|
+
Provide a clear roadmap with:
|
|
8450
|
+
- Phases/milestones with descriptions
|
|
8451
|
+
- Key specs to create
|
|
8452
|
+
- Dependency relationships
|
|
8453
|
+
- Recommended execution order
|
|
8454
|
+
- Actionable next steps to implement this plan`
|
|
8373
8455
|
}
|
|
8374
8456
|
}
|
|
8375
8457
|
]
|
|
8376
8458
|
})
|
|
8377
8459
|
];
|
|
8378
8460
|
}
|
|
8379
|
-
|
|
8461
|
+
|
|
8462
|
+
// src/mcp/prompts/project-progress-overview.ts
|
|
8463
|
+
function projectProgressOverviewPrompt() {
|
|
8380
8464
|
return [
|
|
8381
|
-
"
|
|
8465
|
+
"project-progress-overview",
|
|
8382
8466
|
{
|
|
8383
|
-
title: "
|
|
8384
|
-
description: "
|
|
8385
|
-
argsSchema: {
|
|
8386
|
-
topic: z.string()
|
|
8387
|
-
}
|
|
8467
|
+
title: "Project Progress Overview",
|
|
8468
|
+
description: "Generate comprehensive project status report combining specs, git history, and metrics"
|
|
8388
8469
|
},
|
|
8389
|
-
(
|
|
8470
|
+
() => ({
|
|
8390
8471
|
messages: [
|
|
8391
8472
|
{
|
|
8392
8473
|
role: "user",
|
|
8393
8474
|
content: {
|
|
8394
8475
|
type: "text",
|
|
8395
|
-
text: `
|
|
8476
|
+
text: `Analyze project progress and provide a comprehensive overview:
|
|
8396
8477
|
|
|
8397
|
-
|
|
8478
|
+
1. **Spec Analysis**: Review all specs using \`board\` and \`stats\`, group by status (planned/in-progress/complete), highlight any blockers or dependencies
|
|
8479
|
+
2. **Recent Activity**: Examine git commit history (last 2 weeks), identify key changes and development patterns
|
|
8480
|
+
3. **Current State**: Assess what's actively being worked on, what's completed, what's planned
|
|
8481
|
+
4. **Velocity Metrics**: Calculate completion rates, average time in each status, and throughput trends
|
|
8482
|
+
5. **Risk Assessment**: Identify stalled specs, missing dependencies, potential bottlenecks
|
|
8483
|
+
6. **Next Steps**: Recommend priority actions based on current project state
|
|
8484
|
+
|
|
8485
|
+
Use the following tools to gather data:
|
|
8486
|
+
- \`board\` - Get Kanban view of specs by status
|
|
8487
|
+
- \`stats\` - Get project metrics
|
|
8488
|
+
- \`list\` - List specs with filters
|
|
8489
|
+
- \`deps\` - Analyze dependencies for critical specs
|
|
8490
|
+
- Terminal git commands - Analyze recent commit history
|
|
8491
|
+
|
|
8492
|
+
Provide a clear, actionable summary that helps understand project health and next steps.`
|
|
8398
8493
|
}
|
|
8399
8494
|
}
|
|
8400
8495
|
]
|
|
@@ -8409,16 +8504,18 @@ function updateSpecStatusPrompt() {
|
|
|
8409
8504
|
description: "Quick workflow to update specification status",
|
|
8410
8505
|
argsSchema: {
|
|
8411
8506
|
specPath: z.string(),
|
|
8412
|
-
|
|
8507
|
+
status: z.enum(["planned", "in-progress", "complete", "archived"])
|
|
8413
8508
|
}
|
|
8414
8509
|
},
|
|
8415
|
-
({ specPath,
|
|
8510
|
+
({ specPath, status }) => ({
|
|
8416
8511
|
messages: [
|
|
8417
8512
|
{
|
|
8418
8513
|
role: "user",
|
|
8419
8514
|
content: {
|
|
8420
8515
|
type: "text",
|
|
8421
|
-
text: `Update the status of spec "${specPath}" to "${
|
|
8516
|
+
text: `Update the status of spec "${specPath}" to "${status}".
|
|
8517
|
+
|
|
8518
|
+
Use the \`update\` tool: \`update <spec> --status ${status}\``
|
|
8422
8519
|
}
|
|
8423
8520
|
}
|
|
8424
8521
|
]
|
|
@@ -8428,8 +8525,8 @@ function updateSpecStatusPrompt() {
|
|
|
8428
8525
|
|
|
8429
8526
|
// src/mcp/prompts/registry.ts
|
|
8430
8527
|
function registerPrompts(server) {
|
|
8431
|
-
server.registerPrompt(...
|
|
8432
|
-
server.registerPrompt(...
|
|
8528
|
+
server.registerPrompt(...projectProgressOverviewPrompt());
|
|
8529
|
+
server.registerPrompt(...planProjectRoadmapPrompt());
|
|
8433
8530
|
server.registerPrompt(...updateSpecStatusPrompt());
|
|
8434
8531
|
}
|
|
8435
8532
|
|
|
@@ -8465,5 +8562,5 @@ if (import.meta.url === `file://${process.argv[1]}`) {
|
|
|
8465
8562
|
}
|
|
8466
8563
|
|
|
8467
8564
|
export { analyzeCommand, archiveCommand, backfillCommand, boardCommand, checkCommand, compactCommand, createCommand, createMcpServer, depsCommand, filesCommand, ganttCommand, initCommand, linkCommand, listCommand, mcpCommand, migrateCommand, openCommand, searchCommand, splitCommand, statsCommand, templatesCommand, timelineCommand, tokensCommand, uiCommand, unlinkCommand, updateCommand, validateCommand, viewCommand };
|
|
8468
|
-
//# sourceMappingURL=chunk-
|
|
8469
|
-
//# sourceMappingURL=chunk-
|
|
8565
|
+
//# sourceMappingURL=chunk-5A7MJSNZ.js.map
|
|
8566
|
+
//# sourceMappingURL=chunk-5A7MJSNZ.js.map
|