@anthropologies/claudestory 0.1.6 → 0.1.8
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/README.md +3 -8
- package/dist/cli.js +116 -33
- package/dist/index.js +84 -10
- package/dist/mcp.js +32 -24
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -95,16 +95,11 @@ The MCP server provides 19 tools for Claude Code integration. It imports the sam
|
|
|
95
95
|
### Setup with Claude Code
|
|
96
96
|
|
|
97
97
|
```bash
|
|
98
|
-
|
|
98
|
+
npm install -g @anthropologies/claudestory
|
|
99
|
+
claude mcp add claudestory -s user -- claudestory --mcp
|
|
99
100
|
```
|
|
100
101
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
For a specific project root (recommended when working across multiple projects):
|
|
104
|
-
|
|
105
|
-
```bash
|
|
106
|
-
claude mcp add claudestory -- env CLAUDESTORY_PROJECT_ROOT=/path/to/project npx -y @anthropologies/claudestory --mcp
|
|
107
|
-
```
|
|
102
|
+
Two commands: install globally, register as MCP server. Works in every project that has a `.story/` directory. The MCP server auto-discovers the project root by walking up from the working directory.
|
|
108
103
|
|
|
109
104
|
### MCP Tools
|
|
110
105
|
|
package/dist/cli.js
CHANGED
|
@@ -3590,50 +3590,58 @@ import { realpathSync, existsSync as existsSync5 } from "fs";
|
|
|
3590
3590
|
import { resolve as resolve7, join as join8, isAbsolute } from "path";
|
|
3591
3591
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3592
3592
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3593
|
-
function
|
|
3593
|
+
function tryDiscoverRoot() {
|
|
3594
3594
|
const envRoot = process.env[ENV_VAR2];
|
|
3595
3595
|
if (envRoot) {
|
|
3596
3596
|
if (!isAbsolute(envRoot)) {
|
|
3597
|
-
process.stderr.write(`
|
|
3597
|
+
process.stderr.write(`Warning: ${ENV_VAR2} must be an absolute path, got: ${envRoot}
|
|
3598
3598
|
`);
|
|
3599
|
-
|
|
3599
|
+
return null;
|
|
3600
3600
|
}
|
|
3601
3601
|
const resolved = resolve7(envRoot);
|
|
3602
|
-
let canonical;
|
|
3603
3602
|
try {
|
|
3604
|
-
canonical = realpathSync(resolved);
|
|
3605
|
-
|
|
3606
|
-
|
|
3603
|
+
const canonical = realpathSync(resolved);
|
|
3604
|
+
if (existsSync5(join8(canonical, CONFIG_PATH2))) {
|
|
3605
|
+
return canonical;
|
|
3606
|
+
}
|
|
3607
|
+
process.stderr.write(`Warning: No .story/config.json at ${canonical}
|
|
3607
3608
|
`);
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
if (!existsSync5(join8(canonical, CONFIG_PATH2))) {
|
|
3611
|
-
process.stderr.write(`Error: No .story/config.json at ${canonical}
|
|
3609
|
+
} catch {
|
|
3610
|
+
process.stderr.write(`Warning: ${ENV_VAR2} path does not exist: ${resolved}
|
|
3612
3611
|
`);
|
|
3613
|
-
process.exit(1);
|
|
3614
3612
|
}
|
|
3615
|
-
return
|
|
3613
|
+
return null;
|
|
3616
3614
|
}
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3615
|
+
try {
|
|
3616
|
+
const root = discoverProjectRoot();
|
|
3617
|
+
return root ? realpathSync(root) : null;
|
|
3618
|
+
} catch {
|
|
3619
|
+
return null;
|
|
3621
3620
|
}
|
|
3622
|
-
return realpathSync(root);
|
|
3623
3621
|
}
|
|
3624
3622
|
async function main() {
|
|
3625
|
-
const root =
|
|
3623
|
+
const root = tryDiscoverRoot();
|
|
3626
3624
|
const server = new McpServer(
|
|
3627
3625
|
{ name: "claudestory", version },
|
|
3628
3626
|
{
|
|
3629
|
-
instructions: "Start with claudestory_status for a project overview, then claudestory_ticket_next for the highest-priority work, then claudestory_handover_latest for session context."
|
|
3627
|
+
instructions: root ? "Start with claudestory_status for a project overview, then claudestory_ticket_next for the highest-priority work, then claudestory_handover_latest for session context." : "No .story/ project found in the current directory. Navigate to a project with a .story/ directory, or set CLAUDESTORY_PROJECT_ROOT."
|
|
3630
3628
|
}
|
|
3631
3629
|
);
|
|
3632
|
-
|
|
3630
|
+
if (root) {
|
|
3631
|
+
registerAllTools(server, root);
|
|
3632
|
+
process.stderr.write(`claudestory MCP server running (root: ${root})
|
|
3633
|
+
`);
|
|
3634
|
+
} else {
|
|
3635
|
+
server.registerTool("claudestory_status", {
|
|
3636
|
+
description: "Project summary \u2014 returns error if no .story/ project found"
|
|
3637
|
+
}, () => Promise.resolve({
|
|
3638
|
+
content: [{ type: "text", text: "No .story/ project found. Navigate to a directory containing .story/ or set CLAUDESTORY_PROJECT_ROOT." }],
|
|
3639
|
+
isError: true
|
|
3640
|
+
}));
|
|
3641
|
+
process.stderr.write("claudestory MCP server running (no project found \u2014 tools will report errors)\n");
|
|
3642
|
+
}
|
|
3633
3643
|
const transport = new StdioServerTransport();
|
|
3634
3644
|
await server.connect(transport);
|
|
3635
|
-
process.stderr.write(`claudestory MCP server running (root: ${root})
|
|
3636
|
-
`);
|
|
3637
3645
|
}
|
|
3638
3646
|
var ENV_VAR2, CONFIG_PATH2, version;
|
|
3639
3647
|
var init_mcp = __esm({
|
|
@@ -3644,7 +3652,7 @@ var init_mcp = __esm({
|
|
|
3644
3652
|
init_tools();
|
|
3645
3653
|
ENV_VAR2 = "CLAUDESTORY_PROJECT_ROOT";
|
|
3646
3654
|
CONFIG_PATH2 = ".story/config.json";
|
|
3647
|
-
version = "0.1.
|
|
3655
|
+
version = "0.1.8";
|
|
3648
3656
|
main().catch((err) => {
|
|
3649
3657
|
process.stderr.write(`Fatal: ${err instanceof Error ? err.message : String(err)}
|
|
3650
3658
|
`);
|
|
@@ -3654,7 +3662,8 @@ var init_mcp = __esm({
|
|
|
3654
3662
|
});
|
|
3655
3663
|
|
|
3656
3664
|
// src/core/init.ts
|
|
3657
|
-
import { mkdir as mkdir3, stat as stat2 } from "fs/promises";
|
|
3665
|
+
import { mkdir as mkdir3, stat as stat2, writeFile as writeFile2 } from "fs/promises";
|
|
3666
|
+
import { existsSync as existsSync6 } from "fs";
|
|
3658
3667
|
import { join as join9, resolve as resolve8 } from "path";
|
|
3659
3668
|
async function initProject(root, options) {
|
|
3660
3669
|
const absRoot = resolve8(root);
|
|
@@ -3681,6 +3690,13 @@ async function initProject(root, options) {
|
|
|
3681
3690
|
await mkdir3(join9(wrapDir, "tickets"), { recursive: true });
|
|
3682
3691
|
await mkdir3(join9(wrapDir, "issues"), { recursive: true });
|
|
3683
3692
|
await mkdir3(join9(wrapDir, "handovers"), { recursive: true });
|
|
3693
|
+
const created = [
|
|
3694
|
+
".story/config.json",
|
|
3695
|
+
".story/roadmap.json",
|
|
3696
|
+
".story/tickets/",
|
|
3697
|
+
".story/issues/",
|
|
3698
|
+
".story/handovers/"
|
|
3699
|
+
];
|
|
3684
3700
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3685
3701
|
const config = {
|
|
3686
3702
|
version: 2,
|
|
@@ -3711,6 +3727,13 @@ async function initProject(root, options) {
|
|
|
3711
3727
|
};
|
|
3712
3728
|
await writeConfig(config, absRoot);
|
|
3713
3729
|
await writeRoadmap(roadmap, absRoot);
|
|
3730
|
+
const skillDir = join9(absRoot, ".claude", "skills", "prime");
|
|
3731
|
+
const skillPath = join9(skillDir, "SKILL.md");
|
|
3732
|
+
if (!existsSync6(skillPath)) {
|
|
3733
|
+
await mkdir3(skillDir, { recursive: true });
|
|
3734
|
+
await writeFile2(skillPath, PRIME_SKILL_CONTENT, "utf-8");
|
|
3735
|
+
created.push(".claude/skills/prime/SKILL.md");
|
|
3736
|
+
}
|
|
3714
3737
|
const warnings = [];
|
|
3715
3738
|
if (options.force && exists) {
|
|
3716
3739
|
try {
|
|
@@ -3725,22 +3748,82 @@ async function initProject(root, options) {
|
|
|
3725
3748
|
}
|
|
3726
3749
|
return {
|
|
3727
3750
|
root: absRoot,
|
|
3728
|
-
created
|
|
3729
|
-
".story/config.json",
|
|
3730
|
-
".story/roadmap.json",
|
|
3731
|
-
".story/tickets/",
|
|
3732
|
-
".story/issues/",
|
|
3733
|
-
".story/handovers/"
|
|
3734
|
-
],
|
|
3751
|
+
created,
|
|
3735
3752
|
warnings
|
|
3736
3753
|
};
|
|
3737
3754
|
}
|
|
3755
|
+
var PRIME_SKILL_CONTENT;
|
|
3738
3756
|
var init_init = __esm({
|
|
3739
3757
|
"src/core/init.ts"() {
|
|
3740
3758
|
"use strict";
|
|
3741
3759
|
init_esm_shims();
|
|
3742
3760
|
init_project_loader();
|
|
3743
3761
|
init_errors();
|
|
3762
|
+
PRIME_SKILL_CONTENT = `---
|
|
3763
|
+
name: prime
|
|
3764
|
+
description: Load full claudestory project context. Use at session start for any project with a .story/ directory.
|
|
3765
|
+
---
|
|
3766
|
+
|
|
3767
|
+
# Prime: Load Project Context
|
|
3768
|
+
|
|
3769
|
+
Get full project context in one command for any project using claudestory.
|
|
3770
|
+
|
|
3771
|
+
## Step 0: Check Setup
|
|
3772
|
+
|
|
3773
|
+
First, check if the claudestory MCP tools are available by looking for \`claudestory_status\` in your available tools.
|
|
3774
|
+
|
|
3775
|
+
**If MCP tools ARE available**, proceed to Step 1.
|
|
3776
|
+
|
|
3777
|
+
**If MCP tools are NOT available**, help the user set up:
|
|
3778
|
+
|
|
3779
|
+
1. Check if the \`claudestory\` CLI is installed by running: \`claudestory --version\`
|
|
3780
|
+
2. If NOT installed, tell the user:
|
|
3781
|
+
\`\`\`
|
|
3782
|
+
claudestory CLI not found. To set up:
|
|
3783
|
+
npm install -g @anthropologies/claudestory
|
|
3784
|
+
claude mcp add claudestory -s user -- claudestory --mcp
|
|
3785
|
+
Then restart Claude Code and run /prime again.
|
|
3786
|
+
\`\`\`
|
|
3787
|
+
3. If CLI IS installed but MCP not registered, offer to register it for them.
|
|
3788
|
+
With user permission, run: \`claude mcp add claudestory -s user -- claudestory --mcp\`
|
|
3789
|
+
Tell the user to restart Claude Code and run /prime again.
|
|
3790
|
+
|
|
3791
|
+
**If MCP tools are unavailable and user doesn't want to set up**, fall back to CLI:
|
|
3792
|
+
- Run \`claudestory status\` via Bash
|
|
3793
|
+
- Run \`claudestory recap\` via Bash
|
|
3794
|
+
- Run \`claudestory handover latest\` via Bash
|
|
3795
|
+
- Then continue to Steps 4-6 below.
|
|
3796
|
+
|
|
3797
|
+
## Step 1: Project Status
|
|
3798
|
+
Call the \`claudestory_status\` MCP tool.
|
|
3799
|
+
|
|
3800
|
+
## Step 2: Session Recap
|
|
3801
|
+
Call the \`claudestory_recap\` MCP tool.
|
|
3802
|
+
|
|
3803
|
+
## Step 3: Latest Handover
|
|
3804
|
+
Call the \`claudestory_handover_latest\` MCP tool.
|
|
3805
|
+
|
|
3806
|
+
## Step 4: Development Rules
|
|
3807
|
+
Read \`RULES.md\` if it exists in the project root.
|
|
3808
|
+
|
|
3809
|
+
## Step 5: Lessons Learned
|
|
3810
|
+
Read \`WORK_STRATEGIES.md\` if it exists in the project root.
|
|
3811
|
+
|
|
3812
|
+
## Step 6: Recent Commits
|
|
3813
|
+
Run \`git log --oneline -10\`.
|
|
3814
|
+
|
|
3815
|
+
## After Loading
|
|
3816
|
+
|
|
3817
|
+
Present a concise summary:
|
|
3818
|
+
- Project progress (X/Y tickets, current phase)
|
|
3819
|
+
- What changed since last snapshot
|
|
3820
|
+
- What the last session accomplished
|
|
3821
|
+
- Next ticket to work on
|
|
3822
|
+
- Any high-severity issues or blockers
|
|
3823
|
+
- Key process rules (if WORK_STRATEGIES.md exists)
|
|
3824
|
+
|
|
3825
|
+
Then ask: "What would you like to work on?"
|
|
3826
|
+
`;
|
|
3744
3827
|
}
|
|
3745
3828
|
});
|
|
3746
3829
|
|
|
@@ -5168,7 +5251,7 @@ async function runCli() {
|
|
|
5168
5251
|
registerRecapCommand: registerRecapCommand2,
|
|
5169
5252
|
registerExportCommand: registerExportCommand2
|
|
5170
5253
|
} = await Promise.resolve().then(() => (init_register(), register_exports));
|
|
5171
|
-
const version2 = "0.1.
|
|
5254
|
+
const version2 = "0.1.8";
|
|
5172
5255
|
class HandledError extends Error {
|
|
5173
5256
|
constructor() {
|
|
5174
5257
|
super("HANDLED_ERROR");
|
package/dist/index.js
CHANGED
|
@@ -1382,7 +1382,8 @@ function dfsBlocked(id, state, visited, inStack, findings) {
|
|
|
1382
1382
|
}
|
|
1383
1383
|
|
|
1384
1384
|
// src/core/init.ts
|
|
1385
|
-
import { mkdir, stat as stat2 } from "fs/promises";
|
|
1385
|
+
import { mkdir, stat as stat2, writeFile as writeFile2 } from "fs/promises";
|
|
1386
|
+
import { existsSync as existsSync4 } from "fs";
|
|
1386
1387
|
import { join as join4, resolve as resolve3 } from "path";
|
|
1387
1388
|
async function initProject(root, options) {
|
|
1388
1389
|
const absRoot = resolve3(root);
|
|
@@ -1409,6 +1410,13 @@ async function initProject(root, options) {
|
|
|
1409
1410
|
await mkdir(join4(wrapDir, "tickets"), { recursive: true });
|
|
1410
1411
|
await mkdir(join4(wrapDir, "issues"), { recursive: true });
|
|
1411
1412
|
await mkdir(join4(wrapDir, "handovers"), { recursive: true });
|
|
1413
|
+
const created = [
|
|
1414
|
+
".story/config.json",
|
|
1415
|
+
".story/roadmap.json",
|
|
1416
|
+
".story/tickets/",
|
|
1417
|
+
".story/issues/",
|
|
1418
|
+
".story/handovers/"
|
|
1419
|
+
];
|
|
1412
1420
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
1413
1421
|
const config = {
|
|
1414
1422
|
version: 2,
|
|
@@ -1439,6 +1447,13 @@ async function initProject(root, options) {
|
|
|
1439
1447
|
};
|
|
1440
1448
|
await writeConfig(config, absRoot);
|
|
1441
1449
|
await writeRoadmap(roadmap, absRoot);
|
|
1450
|
+
const skillDir = join4(absRoot, ".claude", "skills", "prime");
|
|
1451
|
+
const skillPath = join4(skillDir, "SKILL.md");
|
|
1452
|
+
if (!existsSync4(skillPath)) {
|
|
1453
|
+
await mkdir(skillDir, { recursive: true });
|
|
1454
|
+
await writeFile2(skillPath, PRIME_SKILL_CONTENT, "utf-8");
|
|
1455
|
+
created.push(".claude/skills/prime/SKILL.md");
|
|
1456
|
+
}
|
|
1442
1457
|
const warnings = [];
|
|
1443
1458
|
if (options.force && exists) {
|
|
1444
1459
|
try {
|
|
@@ -1453,20 +1468,79 @@ async function initProject(root, options) {
|
|
|
1453
1468
|
}
|
|
1454
1469
|
return {
|
|
1455
1470
|
root: absRoot,
|
|
1456
|
-
created
|
|
1457
|
-
".story/config.json",
|
|
1458
|
-
".story/roadmap.json",
|
|
1459
|
-
".story/tickets/",
|
|
1460
|
-
".story/issues/",
|
|
1461
|
-
".story/handovers/"
|
|
1462
|
-
],
|
|
1471
|
+
created,
|
|
1463
1472
|
warnings
|
|
1464
1473
|
};
|
|
1465
1474
|
}
|
|
1475
|
+
var PRIME_SKILL_CONTENT = `---
|
|
1476
|
+
name: prime
|
|
1477
|
+
description: Load full claudestory project context. Use at session start for any project with a .story/ directory.
|
|
1478
|
+
---
|
|
1479
|
+
|
|
1480
|
+
# Prime: Load Project Context
|
|
1481
|
+
|
|
1482
|
+
Get full project context in one command for any project using claudestory.
|
|
1483
|
+
|
|
1484
|
+
## Step 0: Check Setup
|
|
1485
|
+
|
|
1486
|
+
First, check if the claudestory MCP tools are available by looking for \`claudestory_status\` in your available tools.
|
|
1487
|
+
|
|
1488
|
+
**If MCP tools ARE available**, proceed to Step 1.
|
|
1489
|
+
|
|
1490
|
+
**If MCP tools are NOT available**, help the user set up:
|
|
1491
|
+
|
|
1492
|
+
1. Check if the \`claudestory\` CLI is installed by running: \`claudestory --version\`
|
|
1493
|
+
2. If NOT installed, tell the user:
|
|
1494
|
+
\`\`\`
|
|
1495
|
+
claudestory CLI not found. To set up:
|
|
1496
|
+
npm install -g @anthropologies/claudestory
|
|
1497
|
+
claude mcp add claudestory -s user -- claudestory --mcp
|
|
1498
|
+
Then restart Claude Code and run /prime again.
|
|
1499
|
+
\`\`\`
|
|
1500
|
+
3. If CLI IS installed but MCP not registered, offer to register it for them.
|
|
1501
|
+
With user permission, run: \`claude mcp add claudestory -s user -- claudestory --mcp\`
|
|
1502
|
+
Tell the user to restart Claude Code and run /prime again.
|
|
1503
|
+
|
|
1504
|
+
**If MCP tools are unavailable and user doesn't want to set up**, fall back to CLI:
|
|
1505
|
+
- Run \`claudestory status\` via Bash
|
|
1506
|
+
- Run \`claudestory recap\` via Bash
|
|
1507
|
+
- Run \`claudestory handover latest\` via Bash
|
|
1508
|
+
- Then continue to Steps 4-6 below.
|
|
1509
|
+
|
|
1510
|
+
## Step 1: Project Status
|
|
1511
|
+
Call the \`claudestory_status\` MCP tool.
|
|
1512
|
+
|
|
1513
|
+
## Step 2: Session Recap
|
|
1514
|
+
Call the \`claudestory_recap\` MCP tool.
|
|
1515
|
+
|
|
1516
|
+
## Step 3: Latest Handover
|
|
1517
|
+
Call the \`claudestory_handover_latest\` MCP tool.
|
|
1518
|
+
|
|
1519
|
+
## Step 4: Development Rules
|
|
1520
|
+
Read \`RULES.md\` if it exists in the project root.
|
|
1521
|
+
|
|
1522
|
+
## Step 5: Lessons Learned
|
|
1523
|
+
Read \`WORK_STRATEGIES.md\` if it exists in the project root.
|
|
1524
|
+
|
|
1525
|
+
## Step 6: Recent Commits
|
|
1526
|
+
Run \`git log --oneline -10\`.
|
|
1527
|
+
|
|
1528
|
+
## After Loading
|
|
1529
|
+
|
|
1530
|
+
Present a concise summary:
|
|
1531
|
+
- Project progress (X/Y tickets, current phase)
|
|
1532
|
+
- What changed since last snapshot
|
|
1533
|
+
- What the last session accomplished
|
|
1534
|
+
- Next ticket to work on
|
|
1535
|
+
- Any high-severity issues or blockers
|
|
1536
|
+
- Key process rules (if WORK_STRATEGIES.md exists)
|
|
1537
|
+
|
|
1538
|
+
Then ask: "What would you like to work on?"
|
|
1539
|
+
`;
|
|
1466
1540
|
|
|
1467
1541
|
// src/core/snapshot.ts
|
|
1468
1542
|
import { readdir as readdir3, readFile as readFile3, mkdir as mkdir2, unlink as unlink2 } from "fs/promises";
|
|
1469
|
-
import { existsSync as
|
|
1543
|
+
import { existsSync as existsSync5 } from "fs";
|
|
1470
1544
|
import { join as join5, resolve as resolve4 } from "path";
|
|
1471
1545
|
import { z as z6 } from "zod";
|
|
1472
1546
|
var LoadWarningSchema = z6.object({
|
|
@@ -1519,7 +1593,7 @@ async function saveSnapshot(root, loadResult) {
|
|
|
1519
1593
|
}
|
|
1520
1594
|
async function loadLatestSnapshot(root) {
|
|
1521
1595
|
const snapshotsDir = join5(resolve4(root), ".story", "snapshots");
|
|
1522
|
-
if (!
|
|
1596
|
+
if (!existsSync5(snapshotsDir)) return null;
|
|
1523
1597
|
const files = await listSnapshotFiles(snapshotsDir);
|
|
1524
1598
|
if (files.length === 0) return null;
|
|
1525
1599
|
for (const filename of files) {
|
package/dist/mcp.js
CHANGED
|
@@ -2491,51 +2491,59 @@ function registerAllTools(server, pinnedRoot) {
|
|
|
2491
2491
|
// src/mcp/index.ts
|
|
2492
2492
|
var ENV_VAR2 = "CLAUDESTORY_PROJECT_ROOT";
|
|
2493
2493
|
var CONFIG_PATH2 = ".story/config.json";
|
|
2494
|
-
var version = "0.1.
|
|
2495
|
-
function
|
|
2494
|
+
var version = "0.1.8";
|
|
2495
|
+
function tryDiscoverRoot() {
|
|
2496
2496
|
const envRoot = process.env[ENV_VAR2];
|
|
2497
2497
|
if (envRoot) {
|
|
2498
2498
|
if (!isAbsolute(envRoot)) {
|
|
2499
|
-
process.stderr.write(`
|
|
2499
|
+
process.stderr.write(`Warning: ${ENV_VAR2} must be an absolute path, got: ${envRoot}
|
|
2500
2500
|
`);
|
|
2501
|
-
|
|
2501
|
+
return null;
|
|
2502
2502
|
}
|
|
2503
2503
|
const resolved = resolve7(envRoot);
|
|
2504
|
-
let canonical;
|
|
2505
2504
|
try {
|
|
2506
|
-
canonical = realpathSync(resolved);
|
|
2507
|
-
|
|
2508
|
-
|
|
2505
|
+
const canonical = realpathSync(resolved);
|
|
2506
|
+
if (existsSync5(join8(canonical, CONFIG_PATH2))) {
|
|
2507
|
+
return canonical;
|
|
2508
|
+
}
|
|
2509
|
+
process.stderr.write(`Warning: No .story/config.json at ${canonical}
|
|
2509
2510
|
`);
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
if (!existsSync5(join8(canonical, CONFIG_PATH2))) {
|
|
2513
|
-
process.stderr.write(`Error: No .story/config.json at ${canonical}
|
|
2511
|
+
} catch {
|
|
2512
|
+
process.stderr.write(`Warning: ${ENV_VAR2} path does not exist: ${resolved}
|
|
2514
2513
|
`);
|
|
2515
|
-
process.exit(1);
|
|
2516
2514
|
}
|
|
2517
|
-
return
|
|
2515
|
+
return null;
|
|
2518
2516
|
}
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2517
|
+
try {
|
|
2518
|
+
const root = discoverProjectRoot();
|
|
2519
|
+
return root ? realpathSync(root) : null;
|
|
2520
|
+
} catch {
|
|
2521
|
+
return null;
|
|
2523
2522
|
}
|
|
2524
|
-
return realpathSync(root);
|
|
2525
2523
|
}
|
|
2526
2524
|
async function main() {
|
|
2527
|
-
const root =
|
|
2525
|
+
const root = tryDiscoverRoot();
|
|
2528
2526
|
const server = new McpServer(
|
|
2529
2527
|
{ name: "claudestory", version },
|
|
2530
2528
|
{
|
|
2531
|
-
instructions: "Start with claudestory_status for a project overview, then claudestory_ticket_next for the highest-priority work, then claudestory_handover_latest for session context."
|
|
2529
|
+
instructions: root ? "Start with claudestory_status for a project overview, then claudestory_ticket_next for the highest-priority work, then claudestory_handover_latest for session context." : "No .story/ project found in the current directory. Navigate to a project with a .story/ directory, or set CLAUDESTORY_PROJECT_ROOT."
|
|
2532
2530
|
}
|
|
2533
2531
|
);
|
|
2534
|
-
|
|
2532
|
+
if (root) {
|
|
2533
|
+
registerAllTools(server, root);
|
|
2534
|
+
process.stderr.write(`claudestory MCP server running (root: ${root})
|
|
2535
|
+
`);
|
|
2536
|
+
} else {
|
|
2537
|
+
server.registerTool("claudestory_status", {
|
|
2538
|
+
description: "Project summary \u2014 returns error if no .story/ project found"
|
|
2539
|
+
}, () => Promise.resolve({
|
|
2540
|
+
content: [{ type: "text", text: "No .story/ project found. Navigate to a directory containing .story/ or set CLAUDESTORY_PROJECT_ROOT." }],
|
|
2541
|
+
isError: true
|
|
2542
|
+
}));
|
|
2543
|
+
process.stderr.write("claudestory MCP server running (no project found \u2014 tools will report errors)\n");
|
|
2544
|
+
}
|
|
2535
2545
|
const transport = new StdioServerTransport();
|
|
2536
2546
|
await server.connect(transport);
|
|
2537
|
-
process.stderr.write(`claudestory MCP server running (root: ${root})
|
|
2538
|
-
`);
|
|
2539
2547
|
}
|
|
2540
2548
|
main().catch((err) => {
|
|
2541
2549
|
process.stderr.write(`Fatal: ${err instanceof Error ? err.message : String(err)}
|