@anthropologies/claudestory 0.1.0 → 0.1.2
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 +2 -2
- package/dist/cli.js +54 -14
- package/dist/index.d.ts +4 -0
- package/dist/index.js +38 -8
- package/dist/mcp.js +12 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ Cross-session context persistence for AI coding assistants. Tracks tickets, issu
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install -g claudestory
|
|
8
|
+
npm install -g @anthropologies/claudestory
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
Requires Node.js 20+.
|
|
@@ -140,7 +140,7 @@ This gives the AI full project context from the first message.
|
|
|
140
140
|
## Library Usage
|
|
141
141
|
|
|
142
142
|
```typescript
|
|
143
|
-
import { loadProject, ProjectState } from "claudestory";
|
|
143
|
+
import { loadProject, ProjectState } from "@anthropologies/claudestory";
|
|
144
144
|
|
|
145
145
|
const { state, warnings } = await loadProject("/path/to/project");
|
|
146
146
|
console.log(state.tickets.length); // all tickets
|
package/dist/cli.js
CHANGED
|
@@ -224,9 +224,9 @@ function formatStatus(state, format) {
|
|
|
224
224
|
const phases = phasesWithStatus(state);
|
|
225
225
|
const data = {
|
|
226
226
|
project: state.config.project,
|
|
227
|
-
totalTickets: state.
|
|
228
|
-
completeTickets: state.
|
|
229
|
-
openTickets: state.
|
|
227
|
+
totalTickets: state.leafTicketCount,
|
|
228
|
+
completeTickets: state.completeLeafTicketCount,
|
|
229
|
+
openTickets: state.leafTicketCount - state.completeLeafTicketCount,
|
|
230
230
|
blockedTickets: state.blockedCount,
|
|
231
231
|
openIssues: state.openIssueCount,
|
|
232
232
|
handovers: state.handoverFilenames.length,
|
|
@@ -243,7 +243,7 @@ function formatStatus(state, format) {
|
|
|
243
243
|
const lines = [
|
|
244
244
|
`# ${escapeMarkdownInline(state.config.project)}`,
|
|
245
245
|
"",
|
|
246
|
-
`Tickets: ${state.
|
|
246
|
+
`Tickets: ${state.completeLeafTicketCount}/${state.leafTicketCount} complete, ${state.blockedCount} blocked`,
|
|
247
247
|
`Issues: ${state.openIssueCount} open`,
|
|
248
248
|
`Handovers: ${state.handoverFilenames.length}`,
|
|
249
249
|
"",
|
|
@@ -465,7 +465,11 @@ function formatInitResult(result, format) {
|
|
|
465
465
|
if (format === "json") {
|
|
466
466
|
return JSON.stringify(successEnvelope(result), null, 2);
|
|
467
467
|
}
|
|
468
|
-
|
|
468
|
+
const lines = [`Initialized .story/ at ${escapeMarkdownInline(result.root)}`, "", ...result.created.map((f) => ` ${f}`)];
|
|
469
|
+
if (result.warnings.length > 0) {
|
|
470
|
+
lines.push("", `Warning: ${result.warnings.length} corrupt file(s) found. Run \`claudestory validate\` to inspect.`);
|
|
471
|
+
}
|
|
472
|
+
return lines.join("\n");
|
|
469
473
|
}
|
|
470
474
|
function formatHandoverList(filenames, format) {
|
|
471
475
|
if (format === "json") {
|
|
@@ -509,6 +513,8 @@ var ProjectState = class _ProjectState {
|
|
|
509
513
|
// --- Derived (public readonly) ---
|
|
510
514
|
umbrellaIDs;
|
|
511
515
|
leafTickets;
|
|
516
|
+
leafTicketCount;
|
|
517
|
+
completeLeafTicketCount;
|
|
512
518
|
// --- Derived (private) ---
|
|
513
519
|
leafTicketsByPhase;
|
|
514
520
|
childrenByParent;
|
|
@@ -535,6 +541,10 @@ var ProjectState = class _ProjectState {
|
|
|
535
541
|
}
|
|
536
542
|
this.umbrellaIDs = parentIDs;
|
|
537
543
|
this.leafTickets = input.tickets.filter((t) => !parentIDs.has(t.id));
|
|
544
|
+
this.leafTicketCount = this.leafTickets.length;
|
|
545
|
+
this.completeLeafTicketCount = this.leafTickets.filter(
|
|
546
|
+
(t) => t.status === "complete"
|
|
547
|
+
).length;
|
|
538
548
|
const byPhase = /* @__PURE__ */ new Map();
|
|
539
549
|
for (const t of this.leafTickets) {
|
|
540
550
|
const phase = t.phase;
|
|
@@ -640,7 +650,7 @@ var ProjectState = class _ProjectState {
|
|
|
640
650
|
});
|
|
641
651
|
}
|
|
642
652
|
get blockedCount() {
|
|
643
|
-
return this.
|
|
653
|
+
return this.leafTickets.filter((t) => t.status !== "complete" && this.isBlocked(t)).length;
|
|
644
654
|
}
|
|
645
655
|
ticketByID(id) {
|
|
646
656
|
return this.ticketsByID.get(id);
|
|
@@ -1699,7 +1709,7 @@ function dfsBlocked(id, state, visited, inStack, findings) {
|
|
|
1699
1709
|
|
|
1700
1710
|
// src/core/init.ts
|
|
1701
1711
|
init_esm_shims();
|
|
1702
|
-
import { mkdir, stat as stat2 } from "fs/promises";
|
|
1712
|
+
import { mkdir, stat as stat2, readdir as readdir3, readFile as readFile3 } from "fs/promises";
|
|
1703
1713
|
import { join as join4, resolve as resolve3 } from "path";
|
|
1704
1714
|
init_errors();
|
|
1705
1715
|
async function initProject(root, options) {
|
|
@@ -1757,6 +1767,25 @@ async function initProject(root, options) {
|
|
|
1757
1767
|
};
|
|
1758
1768
|
await writeConfig(config, absRoot);
|
|
1759
1769
|
await writeRoadmap(roadmap, absRoot);
|
|
1770
|
+
const warnings = [];
|
|
1771
|
+
if (options.force && exists) {
|
|
1772
|
+
for (const subdir of ["tickets", "issues"]) {
|
|
1773
|
+
const dir = join4(wrapDir, subdir);
|
|
1774
|
+
try {
|
|
1775
|
+
const files = await readdir3(dir);
|
|
1776
|
+
for (const f of files) {
|
|
1777
|
+
if (!f.endsWith(".json")) continue;
|
|
1778
|
+
try {
|
|
1779
|
+
const content = await readFile3(join4(dir, f), "utf-8");
|
|
1780
|
+
JSON.parse(content);
|
|
1781
|
+
} catch {
|
|
1782
|
+
warnings.push(`.story/${subdir}/${f}`);
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
} catch {
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1760
1789
|
return {
|
|
1761
1790
|
root: absRoot,
|
|
1762
1791
|
created: [
|
|
@@ -1765,7 +1794,8 @@ async function initProject(root, options) {
|
|
|
1765
1794
|
".story/tickets/",
|
|
1766
1795
|
".story/issues/",
|
|
1767
1796
|
".story/handovers/"
|
|
1768
|
-
]
|
|
1797
|
+
],
|
|
1798
|
+
warnings
|
|
1769
1799
|
};
|
|
1770
1800
|
}
|
|
1771
1801
|
|
|
@@ -3759,8 +3789,13 @@ function registerPhaseCommand(yargs2) {
|
|
|
3759
3789
|
}
|
|
3760
3790
|
|
|
3761
3791
|
// src/cli/index.ts
|
|
3762
|
-
var version = "0.1.
|
|
3763
|
-
var
|
|
3792
|
+
var version = "0.1.2";
|
|
3793
|
+
var HandledError = class extends Error {
|
|
3794
|
+
constructor() {
|
|
3795
|
+
super("HANDLED_ERROR");
|
|
3796
|
+
this.name = "HandledError";
|
|
3797
|
+
}
|
|
3798
|
+
};
|
|
3764
3799
|
var rawArgs = hideBin(process.argv);
|
|
3765
3800
|
function sniffFormat(args) {
|
|
3766
3801
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -3774,7 +3809,7 @@ var cli = yargs(rawArgs).scriptName("claudestory").version(version).strict().dem
|
|
|
3774
3809
|
if (err) throw err;
|
|
3775
3810
|
writeOutput(formatError("invalid_input", msg ?? "Unknown error", errorFormat));
|
|
3776
3811
|
process.exitCode = ExitCode.USER_ERROR;
|
|
3777
|
-
throw
|
|
3812
|
+
throw new HandledError();
|
|
3778
3813
|
});
|
|
3779
3814
|
cli = registerInitCommand(cli);
|
|
3780
3815
|
cli = registerStatusCommand(cli);
|
|
@@ -3784,9 +3819,14 @@ cli = registerIssueCommand(cli);
|
|
|
3784
3819
|
cli = registerHandoverCommand(cli);
|
|
3785
3820
|
cli = registerBlockerCommand(cli);
|
|
3786
3821
|
cli = registerValidateCommand(cli);
|
|
3787
|
-
|
|
3788
|
-
if (err
|
|
3822
|
+
function handleUnexpectedError(err) {
|
|
3823
|
+
if (err instanceof HandledError) return;
|
|
3789
3824
|
const message = err instanceof Error ? err.message : String(err);
|
|
3790
3825
|
writeOutput(formatError("io_error", message, errorFormat));
|
|
3791
3826
|
process.exitCode = ExitCode.USER_ERROR;
|
|
3792
|
-
}
|
|
3827
|
+
}
|
|
3828
|
+
try {
|
|
3829
|
+
await cli.parseAsync().catch(handleUnexpectedError);
|
|
3830
|
+
} catch (err) {
|
|
3831
|
+
handleUnexpectedError(err);
|
|
3832
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -400,6 +400,8 @@ declare class ProjectState {
|
|
|
400
400
|
readonly handoverFilenames: readonly string[];
|
|
401
401
|
readonly umbrellaIDs: ReadonlySet<string>;
|
|
402
402
|
readonly leafTickets: readonly Ticket[];
|
|
403
|
+
readonly leafTicketCount: number;
|
|
404
|
+
readonly completeLeafTicketCount: number;
|
|
403
405
|
private readonly leafTicketsByPhase;
|
|
404
406
|
private readonly childrenByParent;
|
|
405
407
|
private readonly reverseBlocksMap;
|
|
@@ -697,6 +699,7 @@ interface InitOptions {
|
|
|
697
699
|
interface InitResult {
|
|
698
700
|
readonly root: string;
|
|
699
701
|
readonly created: readonly string[];
|
|
702
|
+
readonly warnings: readonly string[];
|
|
700
703
|
}
|
|
701
704
|
/**
|
|
702
705
|
* Scaffolds a new .story/ directory structure.
|
|
@@ -762,6 +765,7 @@ declare function formatError(code: ErrorCode, message: string, format: OutputFor
|
|
|
762
765
|
declare function formatInitResult(result: {
|
|
763
766
|
root: string;
|
|
764
767
|
created: readonly string[];
|
|
768
|
+
warnings: readonly string[];
|
|
765
769
|
}, format: OutputFormat): string;
|
|
766
770
|
declare function formatHandoverList(filenames: readonly string[], format: OutputFormat): string;
|
|
767
771
|
declare function formatHandoverContent(filename: string, content: string, format: OutputFormat): string;
|
package/dist/index.js
CHANGED
|
@@ -127,6 +127,8 @@ var ProjectState = class _ProjectState {
|
|
|
127
127
|
// --- Derived (public readonly) ---
|
|
128
128
|
umbrellaIDs;
|
|
129
129
|
leafTickets;
|
|
130
|
+
leafTicketCount;
|
|
131
|
+
completeLeafTicketCount;
|
|
130
132
|
// --- Derived (private) ---
|
|
131
133
|
leafTicketsByPhase;
|
|
132
134
|
childrenByParent;
|
|
@@ -153,6 +155,10 @@ var ProjectState = class _ProjectState {
|
|
|
153
155
|
}
|
|
154
156
|
this.umbrellaIDs = parentIDs;
|
|
155
157
|
this.leafTickets = input.tickets.filter((t) => !parentIDs.has(t.id));
|
|
158
|
+
this.leafTicketCount = this.leafTickets.length;
|
|
159
|
+
this.completeLeafTicketCount = this.leafTickets.filter(
|
|
160
|
+
(t) => t.status === "complete"
|
|
161
|
+
).length;
|
|
156
162
|
const byPhase = /* @__PURE__ */ new Map();
|
|
157
163
|
for (const t of this.leafTickets) {
|
|
158
164
|
const phase = t.phase;
|
|
@@ -258,7 +264,7 @@ var ProjectState = class _ProjectState {
|
|
|
258
264
|
});
|
|
259
265
|
}
|
|
260
266
|
get blockedCount() {
|
|
261
|
-
return this.
|
|
267
|
+
return this.leafTickets.filter((t) => t.status !== "complete" && this.isBlocked(t)).length;
|
|
262
268
|
}
|
|
263
269
|
ticketByID(id) {
|
|
264
270
|
return this.ticketsByID.get(id);
|
|
@@ -1353,7 +1359,7 @@ function dfsBlocked(id, state, visited, inStack, findings) {
|
|
|
1353
1359
|
}
|
|
1354
1360
|
|
|
1355
1361
|
// src/core/init.ts
|
|
1356
|
-
import { mkdir, stat as stat2 } from "fs/promises";
|
|
1362
|
+
import { mkdir, stat as stat2, readdir as readdir3, readFile as readFile3 } from "fs/promises";
|
|
1357
1363
|
import { join as join4, resolve as resolve3 } from "path";
|
|
1358
1364
|
async function initProject(root, options) {
|
|
1359
1365
|
const absRoot = resolve3(root);
|
|
@@ -1410,6 +1416,25 @@ async function initProject(root, options) {
|
|
|
1410
1416
|
};
|
|
1411
1417
|
await writeConfig(config, absRoot);
|
|
1412
1418
|
await writeRoadmap(roadmap, absRoot);
|
|
1419
|
+
const warnings = [];
|
|
1420
|
+
if (options.force && exists) {
|
|
1421
|
+
for (const subdir of ["tickets", "issues"]) {
|
|
1422
|
+
const dir = join4(wrapDir, subdir);
|
|
1423
|
+
try {
|
|
1424
|
+
const files = await readdir3(dir);
|
|
1425
|
+
for (const f of files) {
|
|
1426
|
+
if (!f.endsWith(".json")) continue;
|
|
1427
|
+
try {
|
|
1428
|
+
const content = await readFile3(join4(dir, f), "utf-8");
|
|
1429
|
+
JSON.parse(content);
|
|
1430
|
+
} catch {
|
|
1431
|
+
warnings.push(`.story/${subdir}/${f}`);
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
} catch {
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1413
1438
|
return {
|
|
1414
1439
|
root: absRoot,
|
|
1415
1440
|
created: [
|
|
@@ -1418,7 +1443,8 @@ async function initProject(root, options) {
|
|
|
1418
1443
|
".story/tickets/",
|
|
1419
1444
|
".story/issues/",
|
|
1420
1445
|
".story/handovers/"
|
|
1421
|
-
]
|
|
1446
|
+
],
|
|
1447
|
+
warnings
|
|
1422
1448
|
};
|
|
1423
1449
|
}
|
|
1424
1450
|
|
|
@@ -1467,9 +1493,9 @@ function formatStatus(state, format) {
|
|
|
1467
1493
|
const phases = phasesWithStatus(state);
|
|
1468
1494
|
const data = {
|
|
1469
1495
|
project: state.config.project,
|
|
1470
|
-
totalTickets: state.
|
|
1471
|
-
completeTickets: state.
|
|
1472
|
-
openTickets: state.
|
|
1496
|
+
totalTickets: state.leafTicketCount,
|
|
1497
|
+
completeTickets: state.completeLeafTicketCount,
|
|
1498
|
+
openTickets: state.leafTicketCount - state.completeLeafTicketCount,
|
|
1473
1499
|
blockedTickets: state.blockedCount,
|
|
1474
1500
|
openIssues: state.openIssueCount,
|
|
1475
1501
|
handovers: state.handoverFilenames.length,
|
|
@@ -1486,7 +1512,7 @@ function formatStatus(state, format) {
|
|
|
1486
1512
|
const lines = [
|
|
1487
1513
|
`# ${escapeMarkdownInline(state.config.project)}`,
|
|
1488
1514
|
"",
|
|
1489
|
-
`Tickets: ${state.
|
|
1515
|
+
`Tickets: ${state.completeLeafTicketCount}/${state.leafTicketCount} complete, ${state.blockedCount} blocked`,
|
|
1490
1516
|
`Issues: ${state.openIssueCount} open`,
|
|
1491
1517
|
`Handovers: ${state.handoverFilenames.length}`,
|
|
1492
1518
|
"",
|
|
@@ -1708,7 +1734,11 @@ function formatInitResult(result, format) {
|
|
|
1708
1734
|
if (format === "json") {
|
|
1709
1735
|
return JSON.stringify(successEnvelope(result), null, 2);
|
|
1710
1736
|
}
|
|
1711
|
-
|
|
1737
|
+
const lines = [`Initialized .story/ at ${escapeMarkdownInline(result.root)}`, "", ...result.created.map((f) => ` ${f}`)];
|
|
1738
|
+
if (result.warnings.length > 0) {
|
|
1739
|
+
lines.push("", `Warning: ${result.warnings.length} corrupt file(s) found. Run \`claudestory validate\` to inspect.`);
|
|
1740
|
+
}
|
|
1741
|
+
return lines.join("\n");
|
|
1712
1742
|
}
|
|
1713
1743
|
function formatHandoverList(filenames, format) {
|
|
1714
1744
|
if (format === "json") {
|
package/dist/mcp.js
CHANGED
|
@@ -171,6 +171,8 @@ var ProjectState = class _ProjectState {
|
|
|
171
171
|
// --- Derived (public readonly) ---
|
|
172
172
|
umbrellaIDs;
|
|
173
173
|
leafTickets;
|
|
174
|
+
leafTicketCount;
|
|
175
|
+
completeLeafTicketCount;
|
|
174
176
|
// --- Derived (private) ---
|
|
175
177
|
leafTicketsByPhase;
|
|
176
178
|
childrenByParent;
|
|
@@ -197,6 +199,10 @@ var ProjectState = class _ProjectState {
|
|
|
197
199
|
}
|
|
198
200
|
this.umbrellaIDs = parentIDs;
|
|
199
201
|
this.leafTickets = input.tickets.filter((t) => !parentIDs.has(t.id));
|
|
202
|
+
this.leafTicketCount = this.leafTickets.length;
|
|
203
|
+
this.completeLeafTicketCount = this.leafTickets.filter(
|
|
204
|
+
(t) => t.status === "complete"
|
|
205
|
+
).length;
|
|
200
206
|
const byPhase = /* @__PURE__ */ new Map();
|
|
201
207
|
for (const t of this.leafTickets) {
|
|
202
208
|
const phase = t.phase;
|
|
@@ -302,7 +308,7 @@ var ProjectState = class _ProjectState {
|
|
|
302
308
|
});
|
|
303
309
|
}
|
|
304
310
|
get blockedCount() {
|
|
305
|
-
return this.
|
|
311
|
+
return this.leafTickets.filter((t) => t.status !== "complete" && this.isBlocked(t)).length;
|
|
306
312
|
}
|
|
307
313
|
ticketByID(id) {
|
|
308
314
|
return this.ticketsByID.get(id);
|
|
@@ -853,9 +859,9 @@ function formatStatus(state, format) {
|
|
|
853
859
|
const phases = phasesWithStatus(state);
|
|
854
860
|
const data = {
|
|
855
861
|
project: state.config.project,
|
|
856
|
-
totalTickets: state.
|
|
857
|
-
completeTickets: state.
|
|
858
|
-
openTickets: state.
|
|
862
|
+
totalTickets: state.leafTicketCount,
|
|
863
|
+
completeTickets: state.completeLeafTicketCount,
|
|
864
|
+
openTickets: state.leafTicketCount - state.completeLeafTicketCount,
|
|
859
865
|
blockedTickets: state.blockedCount,
|
|
860
866
|
openIssues: state.openIssueCount,
|
|
861
867
|
handovers: state.handoverFilenames.length,
|
|
@@ -872,7 +878,7 @@ function formatStatus(state, format) {
|
|
|
872
878
|
const lines = [
|
|
873
879
|
`# ${escapeMarkdownInline(state.config.project)}`,
|
|
874
880
|
"",
|
|
875
|
-
`Tickets: ${state.
|
|
881
|
+
`Tickets: ${state.completeLeafTicketCount}/${state.leafTicketCount} complete, ${state.blockedCount} blocked`,
|
|
876
882
|
`Issues: ${state.openIssueCount} open`,
|
|
877
883
|
`Handovers: ${state.handoverFilenames.length}`,
|
|
878
884
|
"",
|
|
@@ -1702,7 +1708,7 @@ function registerAllTools(server, pinnedRoot) {
|
|
|
1702
1708
|
// src/mcp/index.ts
|
|
1703
1709
|
var ENV_VAR2 = "CLAUDESTORY_PROJECT_ROOT";
|
|
1704
1710
|
var CONFIG_PATH2 = ".story/config.json";
|
|
1705
|
-
var version = "0.1.
|
|
1711
|
+
var version = "0.1.2";
|
|
1706
1712
|
function pinProjectRoot() {
|
|
1707
1713
|
const envRoot = process.env[ENV_VAR2];
|
|
1708
1714
|
if (envRoot) {
|