@anthropologies/claudestory 0.1.10 → 0.1.11
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/dist/cli.js +648 -159
- package/dist/index.d.ts +24 -16
- package/dist/index.js +29 -12
- package/dist/mcp.js +728 -60
- package/package.json +1 -1
- package/src/skill/SKILL.md +130 -2
- package/src/skill/reference.md +15 -6
package/dist/cli.js
CHANGED
|
@@ -197,15 +197,9 @@ var init_note = __esm({
|
|
|
197
197
|
init_types();
|
|
198
198
|
NoteSchema = z4.object({
|
|
199
199
|
id: NoteIdSchema,
|
|
200
|
-
title: z4.
|
|
200
|
+
title: z4.string().nullable(),
|
|
201
201
|
content: z4.string().refine((v) => v.trim().length > 0, "Content cannot be empty"),
|
|
202
|
-
tags: z4.
|
|
203
|
-
(v) => {
|
|
204
|
-
const raw = Array.isArray(v) ? v : [];
|
|
205
|
-
return raw.filter((t) => typeof t === "string").map((t) => t.trim().toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-").replace(/^-|-$/g, "")).filter((t) => t.length > 0).filter((t, i, a) => a.indexOf(t) === i);
|
|
206
|
-
},
|
|
207
|
-
z4.array(z4.string())
|
|
208
|
-
),
|
|
202
|
+
tags: z4.array(z4.string()),
|
|
209
203
|
status: z4.enum(NOTE_STATUSES),
|
|
210
204
|
createdDate: DateSchema,
|
|
211
205
|
updatedDate: DateSchema
|
|
@@ -677,6 +671,12 @@ async function writeTicketUnlocked(ticket, root) {
|
|
|
677
671
|
const json = serializeJSON(parsed);
|
|
678
672
|
await atomicWrite(targetPath, json);
|
|
679
673
|
}
|
|
674
|
+
async function writeTicket(ticket, root) {
|
|
675
|
+
const wrapDir = resolve2(root, ".story");
|
|
676
|
+
await withLock(wrapDir, async () => {
|
|
677
|
+
await writeTicketUnlocked(ticket, root);
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
680
|
async function writeIssueUnlocked(issue, root) {
|
|
681
681
|
const parsed = IssueSchema.parse(issue);
|
|
682
682
|
if (!ISSUE_ID_REGEX.test(parsed.id)) {
|
|
@@ -691,6 +691,12 @@ async function writeIssueUnlocked(issue, root) {
|
|
|
691
691
|
const json = serializeJSON(parsed);
|
|
692
692
|
await atomicWrite(targetPath, json);
|
|
693
693
|
}
|
|
694
|
+
async function writeIssue(issue, root) {
|
|
695
|
+
const wrapDir = resolve2(root, ".story");
|
|
696
|
+
await withLock(wrapDir, async () => {
|
|
697
|
+
await writeIssueUnlocked(issue, root);
|
|
698
|
+
});
|
|
699
|
+
}
|
|
694
700
|
async function writeRoadmapUnlocked(roadmap, root) {
|
|
695
701
|
const parsed = RoadmapSchema.parse(roadmap);
|
|
696
702
|
const wrapDir = resolve2(root, ".story");
|
|
@@ -798,6 +804,12 @@ async function writeNoteUnlocked(note, root) {
|
|
|
798
804
|
const json = serializeJSON(parsed);
|
|
799
805
|
await atomicWrite(targetPath, json);
|
|
800
806
|
}
|
|
807
|
+
async function writeNote(note, root) {
|
|
808
|
+
const wrapDir = resolve2(root, ".story");
|
|
809
|
+
await withLock(wrapDir, async () => {
|
|
810
|
+
await writeNoteUnlocked(note, root);
|
|
811
|
+
});
|
|
812
|
+
}
|
|
801
813
|
async function deleteNote(id, root) {
|
|
802
814
|
if (!NOTE_ID_REGEX.test(id)) {
|
|
803
815
|
throw new ProjectLoaderError(
|
|
@@ -1519,6 +1531,7 @@ __export(output_formatter_exports, {
|
|
|
1519
1531
|
formatRecap: () => formatRecap,
|
|
1520
1532
|
formatRecommendations: () => formatRecommendations,
|
|
1521
1533
|
formatReference: () => formatReference,
|
|
1534
|
+
formatSelftestResult: () => formatSelftestResult,
|
|
1522
1535
|
formatSnapshotResult: () => formatSnapshotResult,
|
|
1523
1536
|
formatStatus: () => formatStatus,
|
|
1524
1537
|
formatTicket: () => formatTicket,
|
|
@@ -2016,6 +2029,16 @@ function formatRecap(recap, state, format) {
|
|
|
2016
2029
|
lines.push(`- ${escapeMarkdownInline(name)} \u2014 **new**`);
|
|
2017
2030
|
}
|
|
2018
2031
|
}
|
|
2032
|
+
if (changes.handovers && (changes.handovers.added.length > 0 || changes.handovers.removed.length > 0)) {
|
|
2033
|
+
lines.push("");
|
|
2034
|
+
lines.push("## Handovers");
|
|
2035
|
+
for (const h of changes.handovers.added) {
|
|
2036
|
+
lines.push(`- ${h} \u2014 **new**`);
|
|
2037
|
+
}
|
|
2038
|
+
for (const h of changes.handovers.removed) {
|
|
2039
|
+
lines.push(`- ${h} \u2014 removed`);
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2019
2042
|
if (changes.notes && (changes.notes.added.length > 0 || changes.notes.removed.length > 0 || changes.notes.updated.length > 0)) {
|
|
2020
2043
|
lines.push("");
|
|
2021
2044
|
lines.push("## Notes");
|
|
@@ -2237,7 +2260,35 @@ function formatFullExport(state, format) {
|
|
|
2237
2260
|
return lines.join("\n");
|
|
2238
2261
|
}
|
|
2239
2262
|
function hasAnyChanges(diff) {
|
|
2240
|
-
return diff.tickets.added.length > 0 || diff.tickets.removed.length > 0 || diff.tickets.statusChanged.length > 0 || diff.tickets.descriptionChanged.length > 0 || diff.issues.added.length > 0 || diff.issues.resolved.length > 0 || diff.issues.statusChanged.length > 0 || diff.issues.impactChanged.length > 0 || diff.blockers.added.length > 0 || diff.blockers.cleared.length > 0 || diff.phases.added.length > 0 || diff.phases.removed.length > 0 || diff.phases.statusChanged.length > 0 || (diff.notes?.added.length ?? 0) > 0 || (diff.notes?.removed.length ?? 0) > 0 || (diff.notes?.updated.length ?? 0) > 0;
|
|
2263
|
+
return diff.tickets.added.length > 0 || diff.tickets.removed.length > 0 || diff.tickets.statusChanged.length > 0 || diff.tickets.descriptionChanged.length > 0 || diff.issues.added.length > 0 || diff.issues.resolved.length > 0 || diff.issues.statusChanged.length > 0 || diff.issues.impactChanged.length > 0 || diff.blockers.added.length > 0 || diff.blockers.cleared.length > 0 || diff.phases.added.length > 0 || diff.phases.removed.length > 0 || diff.phases.statusChanged.length > 0 || (diff.notes?.added.length ?? 0) > 0 || (diff.notes?.removed.length ?? 0) > 0 || (diff.notes?.updated.length ?? 0) > 0 || (diff.handovers?.added.length ?? 0) > 0 || (diff.handovers?.removed.length ?? 0) > 0;
|
|
2264
|
+
}
|
|
2265
|
+
function formatSelftestResult(result, format) {
|
|
2266
|
+
if (format === "json") {
|
|
2267
|
+
return JSON.stringify(successEnvelope(result), null, 2);
|
|
2268
|
+
}
|
|
2269
|
+
const lines = ["# Self-test Report", ""];
|
|
2270
|
+
const entities = ["ticket", "issue", "note"];
|
|
2271
|
+
for (const entity of entities) {
|
|
2272
|
+
const checks = result.results.filter((r) => r.entity === entity);
|
|
2273
|
+
if (checks.length === 0) continue;
|
|
2274
|
+
lines.push(`## ${entity.charAt(0).toUpperCase() + entity.slice(1)}`);
|
|
2275
|
+
for (const check of checks) {
|
|
2276
|
+
const mark = check.passed ? "[x]" : "[ ]";
|
|
2277
|
+
const suffix = check.passed ? "" : ` \u2014 ${check.detail}`;
|
|
2278
|
+
lines.push(`- ${mark} ${check.step}${suffix}`);
|
|
2279
|
+
}
|
|
2280
|
+
lines.push("");
|
|
2281
|
+
}
|
|
2282
|
+
if (result.cleanupErrors.length > 0) {
|
|
2283
|
+
lines.push("## Cleanup Warnings");
|
|
2284
|
+
lines.push("");
|
|
2285
|
+
for (const err of result.cleanupErrors) {
|
|
2286
|
+
lines.push(`- ${err}`);
|
|
2287
|
+
}
|
|
2288
|
+
lines.push("");
|
|
2289
|
+
}
|
|
2290
|
+
lines.push(`Result: ${result.passed}/${result.total} passed`);
|
|
2291
|
+
return lines.join("\n");
|
|
2241
2292
|
}
|
|
2242
2293
|
function truncate(text, maxLen) {
|
|
2243
2294
|
if (text.length <= maxLen) return text;
|
|
@@ -2814,11 +2865,9 @@ async function handleBlockerClear(name, note, format, root) {
|
|
|
2814
2865
|
const updated = {
|
|
2815
2866
|
...existing,
|
|
2816
2867
|
cleared: true,
|
|
2817
|
-
clearedDate: todayISO()
|
|
2868
|
+
clearedDate: todayISO(),
|
|
2869
|
+
...note !== void 0 && { note }
|
|
2818
2870
|
};
|
|
2819
|
-
if (note !== void 0) {
|
|
2820
|
-
updated.note = note;
|
|
2821
|
-
}
|
|
2822
2871
|
const newBlockers = [...state.roadmap.blockers];
|
|
2823
2872
|
newBlockers[idx] = updated;
|
|
2824
2873
|
const newRoadmap = { ...state.roadmap, blockers: newBlockers };
|
|
@@ -3046,6 +3095,12 @@ async function handleTicketUpdate(id, updates, format, root) {
|
|
|
3046
3095
|
`Unknown ticket status "${updates.status}": must be one of ${TICKET_STATUSES.join(", ")}`
|
|
3047
3096
|
);
|
|
3048
3097
|
}
|
|
3098
|
+
if (updates.type !== void 0 && !TICKET_TYPES.includes(updates.type)) {
|
|
3099
|
+
throw new CliValidationError(
|
|
3100
|
+
"invalid_input",
|
|
3101
|
+
`Unknown ticket type "${updates.type}": must be one of ${TICKET_TYPES.join(", ")}`
|
|
3102
|
+
);
|
|
3103
|
+
}
|
|
3049
3104
|
let updatedTicket;
|
|
3050
3105
|
await withProjectLock(root, { strict: true }, async ({ state }) => {
|
|
3051
3106
|
const existing = state.ticketByID(id);
|
|
@@ -3061,21 +3116,26 @@ async function handleTicketUpdate(id, updates, format, root) {
|
|
|
3061
3116
|
if (updates.parentTicket) {
|
|
3062
3117
|
validateParentTicket(updates.parentTicket, id, state);
|
|
3063
3118
|
}
|
|
3064
|
-
const
|
|
3065
|
-
if (updates.title !== void 0) ticket.title = updates.title;
|
|
3066
|
-
if (updates.description !== void 0) ticket.description = updates.description;
|
|
3067
|
-
if (updates.phase !== void 0) ticket.phase = updates.phase;
|
|
3068
|
-
if (updates.order !== void 0) ticket.order = updates.order;
|
|
3069
|
-
if (updates.blockedBy !== void 0) ticket.blockedBy = updates.blockedBy;
|
|
3070
|
-
if (updates.parentTicket !== void 0) ticket.parentTicket = updates.parentTicket === null ? void 0 : updates.parentTicket;
|
|
3119
|
+
const statusChanges = {};
|
|
3071
3120
|
if (updates.status !== void 0 && updates.status !== existing.status) {
|
|
3072
|
-
|
|
3121
|
+
statusChanges.status = updates.status;
|
|
3073
3122
|
if (updates.status === "complete" && existing.status !== "complete") {
|
|
3074
|
-
|
|
3123
|
+
statusChanges.completedDate = todayISO();
|
|
3075
3124
|
} else if (updates.status !== "complete" && existing.status === "complete") {
|
|
3076
|
-
|
|
3125
|
+
statusChanges.completedDate = null;
|
|
3077
3126
|
}
|
|
3078
3127
|
}
|
|
3128
|
+
const ticket = {
|
|
3129
|
+
...existing,
|
|
3130
|
+
...updates.title !== void 0 && { title: updates.title },
|
|
3131
|
+
...updates.type !== void 0 && { type: updates.type },
|
|
3132
|
+
...updates.description !== void 0 && { description: updates.description },
|
|
3133
|
+
...updates.phase !== void 0 && { phase: updates.phase },
|
|
3134
|
+
...updates.order !== void 0 && { order: updates.order },
|
|
3135
|
+
...updates.blockedBy !== void 0 && { blockedBy: updates.blockedBy },
|
|
3136
|
+
...updates.parentTicket !== void 0 && { parentTicket: updates.parentTicket },
|
|
3137
|
+
...statusChanges
|
|
3138
|
+
};
|
|
3079
3139
|
validatePostWriteState(ticket, state, false);
|
|
3080
3140
|
await writeTicketUnlocked(ticket, root);
|
|
3081
3141
|
updatedTicket = ticket;
|
|
@@ -3191,6 +3251,9 @@ async function handleIssueCreate(args, format, root) {
|
|
|
3191
3251
|
}
|
|
3192
3252
|
let createdIssue;
|
|
3193
3253
|
await withProjectLock(root, { strict: true }, async ({ state }) => {
|
|
3254
|
+
if (args.phase && !state.roadmap.phases.some((p) => p.id === args.phase)) {
|
|
3255
|
+
throw new CliValidationError("invalid_input", `Phase "${args.phase}" not found in roadmap`);
|
|
3256
|
+
}
|
|
3194
3257
|
if (args.relatedTickets.length > 0) {
|
|
3195
3258
|
validateRelatedTickets(args.relatedTickets, state);
|
|
3196
3259
|
}
|
|
@@ -3238,25 +3301,36 @@ async function handleIssueUpdate(id, updates, format, root) {
|
|
|
3238
3301
|
if (!existing) {
|
|
3239
3302
|
throw new CliValidationError("not_found", `Issue ${id} not found`);
|
|
3240
3303
|
}
|
|
3304
|
+
if (updates.phase !== void 0 && updates.phase !== null) {
|
|
3305
|
+
if (!state.roadmap.phases.some((p) => p.id === updates.phase)) {
|
|
3306
|
+
throw new CliValidationError("invalid_input", `Phase "${updates.phase}" not found in roadmap`);
|
|
3307
|
+
}
|
|
3308
|
+
}
|
|
3241
3309
|
if (updates.relatedTickets) {
|
|
3242
3310
|
validateRelatedTickets(updates.relatedTickets, state);
|
|
3243
3311
|
}
|
|
3244
|
-
const
|
|
3245
|
-
if (updates.title !== void 0) issue.title = updates.title;
|
|
3246
|
-
if (updates.severity !== void 0) issue.severity = updates.severity;
|
|
3247
|
-
if (updates.impact !== void 0) issue.impact = updates.impact;
|
|
3248
|
-
if (updates.resolution !== void 0) issue.resolution = updates.resolution;
|
|
3249
|
-
if (updates.components !== void 0) issue.components = updates.components;
|
|
3250
|
-
if (updates.relatedTickets !== void 0) issue.relatedTickets = updates.relatedTickets;
|
|
3251
|
-
if (updates.location !== void 0) issue.location = updates.location;
|
|
3312
|
+
const statusChanges = {};
|
|
3252
3313
|
if (updates.status !== void 0 && updates.status !== existing.status) {
|
|
3253
|
-
|
|
3314
|
+
statusChanges.status = updates.status;
|
|
3254
3315
|
if (updates.status === "resolved" && existing.status !== "resolved") {
|
|
3255
|
-
|
|
3316
|
+
statusChanges.resolvedDate = todayISO();
|
|
3256
3317
|
} else if (updates.status !== "resolved" && existing.status === "resolved") {
|
|
3257
|
-
|
|
3318
|
+
statusChanges.resolvedDate = null;
|
|
3258
3319
|
}
|
|
3259
3320
|
}
|
|
3321
|
+
const issue = {
|
|
3322
|
+
...existing,
|
|
3323
|
+
...updates.title !== void 0 && { title: updates.title },
|
|
3324
|
+
...updates.severity !== void 0 && { severity: updates.severity },
|
|
3325
|
+
...updates.impact !== void 0 && { impact: updates.impact },
|
|
3326
|
+
...updates.resolution !== void 0 && { resolution: updates.resolution },
|
|
3327
|
+
...updates.components !== void 0 && { components: updates.components },
|
|
3328
|
+
...updates.relatedTickets !== void 0 && { relatedTickets: updates.relatedTickets },
|
|
3329
|
+
...updates.location !== void 0 && { location: updates.location },
|
|
3330
|
+
...updates.order !== void 0 && { order: updates.order },
|
|
3331
|
+
...updates.phase !== void 0 && { phase: updates.phase },
|
|
3332
|
+
...statusChanges
|
|
3333
|
+
};
|
|
3260
3334
|
validatePostWriteIssueState(issue, state, false);
|
|
3261
3335
|
await writeIssueUnlocked(issue, root);
|
|
3262
3336
|
updatedIssue = issue;
|
|
@@ -3309,6 +3383,7 @@ async function saveSnapshot(root, loadResult) {
|
|
|
3309
3383
|
tickets: [...state.tickets],
|
|
3310
3384
|
issues: [...state.issues],
|
|
3311
3385
|
notes: [...state.notes],
|
|
3386
|
+
handoverFilenames: [...state.handoverFilenames],
|
|
3312
3387
|
...warnings.length > 0 ? {
|
|
3313
3388
|
warnings: warnings.map((w) => ({
|
|
3314
3389
|
type: w.type,
|
|
@@ -3461,12 +3536,23 @@ function diffStates(snapshotState, currentState) {
|
|
|
3461
3536
|
notesRemoved.push({ id, title: snap.title });
|
|
3462
3537
|
}
|
|
3463
3538
|
}
|
|
3539
|
+
const snapHandovers = new Set(snapshotState.handoverFilenames);
|
|
3540
|
+
const curHandovers = new Set(currentState.handoverFilenames);
|
|
3541
|
+
const handoversAdded = [];
|
|
3542
|
+
const handoversRemoved = [];
|
|
3543
|
+
for (const h of curHandovers) {
|
|
3544
|
+
if (!snapHandovers.has(h)) handoversAdded.push(h);
|
|
3545
|
+
}
|
|
3546
|
+
for (const h of snapHandovers) {
|
|
3547
|
+
if (!curHandovers.has(h)) handoversRemoved.push(h);
|
|
3548
|
+
}
|
|
3464
3549
|
return {
|
|
3465
3550
|
tickets: { added: ticketsAdded, removed: ticketsRemoved, statusChanged: ticketsStatusChanged, descriptionChanged: ticketsDescriptionChanged },
|
|
3466
3551
|
issues: { added: issuesAdded, resolved: issuesResolved, statusChanged: issuesStatusChanged, impactChanged: issuesImpactChanged },
|
|
3467
3552
|
blockers: { added: blockersAdded, cleared: blockersCleared },
|
|
3468
3553
|
phases: { added: phasesAdded, removed: phasesRemoved, statusChanged: phasesStatusChanged },
|
|
3469
|
-
notes: { added: notesAdded, removed: notesRemoved, updated: notesUpdated }
|
|
3554
|
+
notes: { added: notesAdded, removed: notesRemoved, updated: notesUpdated },
|
|
3555
|
+
handovers: { added: handoversAdded, removed: handoversRemoved }
|
|
3470
3556
|
};
|
|
3471
3557
|
}
|
|
3472
3558
|
function buildRecap(currentState, snapshotInfo) {
|
|
@@ -3494,7 +3580,7 @@ function buildRecap(currentState, snapshotInfo) {
|
|
|
3494
3580
|
notes: snapshot.notes ?? [],
|
|
3495
3581
|
roadmap: snapshot.roadmap,
|
|
3496
3582
|
config: snapshot.config,
|
|
3497
|
-
handoverFilenames: []
|
|
3583
|
+
handoverFilenames: snapshot.handoverFilenames ?? []
|
|
3498
3584
|
});
|
|
3499
3585
|
const changes = diffStates(snapshotState, currentState);
|
|
3500
3586
|
const recentlyClearedBlockers = changes.blockers.cleared;
|
|
@@ -3566,6 +3652,7 @@ var init_snapshot = __esm({
|
|
|
3566
3652
|
tickets: z7.array(TicketSchema),
|
|
3567
3653
|
issues: z7.array(IssueSchema),
|
|
3568
3654
|
notes: z7.array(NoteSchema).optional().default([]),
|
|
3655
|
+
handoverFilenames: z7.array(z7.string()).optional().default([]),
|
|
3569
3656
|
warnings: z7.array(LoadWarningSchema).optional()
|
|
3570
3657
|
});
|
|
3571
3658
|
MAX_SNAPSHOTS = 20;
|
|
@@ -3666,23 +3753,22 @@ async function handleNoteUpdate(id, updates, format, root) {
|
|
|
3666
3753
|
if (!existing) {
|
|
3667
3754
|
throw new CliValidationError("not_found", `Note ${id} not found`);
|
|
3668
3755
|
}
|
|
3669
|
-
const
|
|
3670
|
-
if (updates.content !== void 0) {
|
|
3671
|
-
note.content = updates.content;
|
|
3672
|
-
}
|
|
3673
|
-
if (updates.title !== void 0) {
|
|
3674
|
-
const trimmed = updates.title?.trim();
|
|
3675
|
-
note.title = !trimmed ? null : updates.title;
|
|
3676
|
-
}
|
|
3756
|
+
const tagsUpdate = {};
|
|
3677
3757
|
if (updates.clearTags) {
|
|
3678
|
-
|
|
3758
|
+
tagsUpdate.tags = [];
|
|
3679
3759
|
} else if (updates.tags !== void 0) {
|
|
3680
|
-
|
|
3681
|
-
}
|
|
3682
|
-
if (updates.status !== void 0) {
|
|
3683
|
-
note.status = updates.status;
|
|
3760
|
+
tagsUpdate.tags = normalizeTags(updates.tags);
|
|
3684
3761
|
}
|
|
3685
|
-
note
|
|
3762
|
+
const note = {
|
|
3763
|
+
...existing,
|
|
3764
|
+
...updates.content !== void 0 && { content: updates.content },
|
|
3765
|
+
...updates.title !== void 0 && {
|
|
3766
|
+
title: !updates.title?.trim() ? null : updates.title
|
|
3767
|
+
},
|
|
3768
|
+
...tagsUpdate,
|
|
3769
|
+
...updates.status !== void 0 && { status: updates.status },
|
|
3770
|
+
updatedDate: todayISO()
|
|
3771
|
+
};
|
|
3686
3772
|
await writeNoteUnlocked(note, root);
|
|
3687
3773
|
updatedNote = note;
|
|
3688
3774
|
});
|
|
@@ -4005,6 +4091,256 @@ var init_export = __esm({
|
|
|
4005
4091
|
}
|
|
4006
4092
|
});
|
|
4007
4093
|
|
|
4094
|
+
// src/cli/commands/selftest.ts
|
|
4095
|
+
async function handleSelftest(root, format, failAfter) {
|
|
4096
|
+
const results = [];
|
|
4097
|
+
const createdIds = [];
|
|
4098
|
+
const cleanupErrors = [];
|
|
4099
|
+
function record(entity, step, passed2, detail) {
|
|
4100
|
+
results.push({ entity, step, passed: passed2, detail });
|
|
4101
|
+
if (failAfter !== void 0 && results.filter((r) => r.passed).length >= failAfter) {
|
|
4102
|
+
throw new Error(`failAfter(${failAfter}): induced failure for testing`);
|
|
4103
|
+
}
|
|
4104
|
+
}
|
|
4105
|
+
try {
|
|
4106
|
+
let ticketId;
|
|
4107
|
+
try {
|
|
4108
|
+
const { state } = await loadProject(root);
|
|
4109
|
+
ticketId = nextTicketID(state.tickets);
|
|
4110
|
+
const today = todayISO();
|
|
4111
|
+
const ticket = {
|
|
4112
|
+
id: ticketId,
|
|
4113
|
+
title: "selftest ticket",
|
|
4114
|
+
type: "chore",
|
|
4115
|
+
status: "open",
|
|
4116
|
+
phase: null,
|
|
4117
|
+
order: 0,
|
|
4118
|
+
description: "Integration smoke test \u2014 will be deleted.",
|
|
4119
|
+
createdDate: today,
|
|
4120
|
+
completedDate: null,
|
|
4121
|
+
blockedBy: [],
|
|
4122
|
+
parentTicket: null
|
|
4123
|
+
};
|
|
4124
|
+
await writeTicket(ticket, root);
|
|
4125
|
+
createdIds.push({ type: "ticket", id: ticketId });
|
|
4126
|
+
record("ticket", "create", true, `Created ${ticketId}`);
|
|
4127
|
+
} catch (err) {
|
|
4128
|
+
record("ticket", "create", false, errMsg(err));
|
|
4129
|
+
}
|
|
4130
|
+
if (ticketId) {
|
|
4131
|
+
try {
|
|
4132
|
+
const { state } = await loadProject(root);
|
|
4133
|
+
const found = state.ticketByID(ticketId);
|
|
4134
|
+
if (!found) throw new Error(`${ticketId} not found after create`);
|
|
4135
|
+
record("ticket", "get", true, `Found ${ticketId}`);
|
|
4136
|
+
} catch (err) {
|
|
4137
|
+
record("ticket", "get", false, errMsg(err));
|
|
4138
|
+
}
|
|
4139
|
+
try {
|
|
4140
|
+
const { state } = await loadProject(root);
|
|
4141
|
+
const existing = state.ticketByID(ticketId);
|
|
4142
|
+
if (!existing) throw new Error(`${ticketId} not found for update`);
|
|
4143
|
+
const updated = { ...existing, status: "inprogress" };
|
|
4144
|
+
await writeTicket(updated, root);
|
|
4145
|
+
record("ticket", "update", true, `Updated ${ticketId} status \u2192 inprogress`);
|
|
4146
|
+
} catch (err) {
|
|
4147
|
+
record("ticket", "update", false, errMsg(err));
|
|
4148
|
+
}
|
|
4149
|
+
try {
|
|
4150
|
+
const { state } = await loadProject(root);
|
|
4151
|
+
const found = state.ticketByID(ticketId);
|
|
4152
|
+
if (!found) throw new Error(`${ticketId} not found for verify`);
|
|
4153
|
+
if (found.status !== "inprogress") throw new Error(`Expected inprogress, got ${found.status}`);
|
|
4154
|
+
record("ticket", "verify update", true, `Verified ${ticketId} status = inprogress`);
|
|
4155
|
+
} catch (err) {
|
|
4156
|
+
record("ticket", "verify update", false, errMsg(err));
|
|
4157
|
+
}
|
|
4158
|
+
try {
|
|
4159
|
+
await deleteTicket(ticketId, root, { force: true });
|
|
4160
|
+
createdIds.splice(createdIds.findIndex((c) => c.id === ticketId), 1);
|
|
4161
|
+
record("ticket", "delete", true, `Deleted ${ticketId}`);
|
|
4162
|
+
} catch (err) {
|
|
4163
|
+
record("ticket", "delete", false, errMsg(err));
|
|
4164
|
+
}
|
|
4165
|
+
try {
|
|
4166
|
+
const { state } = await loadProject(root);
|
|
4167
|
+
const found = state.ticketByID(ticketId);
|
|
4168
|
+
if (found) throw new Error(`${ticketId} still exists after delete`);
|
|
4169
|
+
record("ticket", "verify delete", true, `Confirmed ${ticketId} absent`);
|
|
4170
|
+
} catch (err) {
|
|
4171
|
+
record("ticket", "verify delete", false, errMsg(err));
|
|
4172
|
+
}
|
|
4173
|
+
}
|
|
4174
|
+
let issueId;
|
|
4175
|
+
try {
|
|
4176
|
+
const { state } = await loadProject(root);
|
|
4177
|
+
issueId = nextIssueID(state.issues);
|
|
4178
|
+
const today = todayISO();
|
|
4179
|
+
const issue = {
|
|
4180
|
+
id: issueId,
|
|
4181
|
+
title: "selftest issue",
|
|
4182
|
+
status: "open",
|
|
4183
|
+
severity: "low",
|
|
4184
|
+
components: [],
|
|
4185
|
+
impact: "Integration smoke test \u2014 will be deleted.",
|
|
4186
|
+
resolution: null,
|
|
4187
|
+
location: [],
|
|
4188
|
+
discoveredDate: today,
|
|
4189
|
+
resolvedDate: null,
|
|
4190
|
+
relatedTickets: [],
|
|
4191
|
+
order: 0,
|
|
4192
|
+
phase: null
|
|
4193
|
+
};
|
|
4194
|
+
await writeIssue(issue, root);
|
|
4195
|
+
createdIds.push({ type: "issue", id: issueId });
|
|
4196
|
+
record("issue", "create", true, `Created ${issueId}`);
|
|
4197
|
+
} catch (err) {
|
|
4198
|
+
record("issue", "create", false, errMsg(err));
|
|
4199
|
+
}
|
|
4200
|
+
if (issueId) {
|
|
4201
|
+
try {
|
|
4202
|
+
const { state } = await loadProject(root);
|
|
4203
|
+
const found = state.issueByID(issueId);
|
|
4204
|
+
if (!found) throw new Error(`${issueId} not found after create`);
|
|
4205
|
+
record("issue", "get", true, `Found ${issueId}`);
|
|
4206
|
+
} catch (err) {
|
|
4207
|
+
record("issue", "get", false, errMsg(err));
|
|
4208
|
+
}
|
|
4209
|
+
try {
|
|
4210
|
+
const { state } = await loadProject(root);
|
|
4211
|
+
const existing = state.issueByID(issueId);
|
|
4212
|
+
if (!existing) throw new Error(`${issueId} not found for update`);
|
|
4213
|
+
const updated = { ...existing, status: "inprogress" };
|
|
4214
|
+
await writeIssue(updated, root);
|
|
4215
|
+
record("issue", "update", true, `Updated ${issueId} status \u2192 inprogress`);
|
|
4216
|
+
} catch (err) {
|
|
4217
|
+
record("issue", "update", false, errMsg(err));
|
|
4218
|
+
}
|
|
4219
|
+
try {
|
|
4220
|
+
const { state } = await loadProject(root);
|
|
4221
|
+
const found = state.issueByID(issueId);
|
|
4222
|
+
if (!found) throw new Error(`${issueId} not found for verify`);
|
|
4223
|
+
if (found.status !== "inprogress") throw new Error(`Expected inprogress, got ${found.status}`);
|
|
4224
|
+
record("issue", "verify update", true, `Verified ${issueId} status = inprogress`);
|
|
4225
|
+
} catch (err) {
|
|
4226
|
+
record("issue", "verify update", false, errMsg(err));
|
|
4227
|
+
}
|
|
4228
|
+
try {
|
|
4229
|
+
await deleteIssue(issueId, root);
|
|
4230
|
+
createdIds.splice(createdIds.findIndex((c) => c.id === issueId), 1);
|
|
4231
|
+
record("issue", "delete", true, `Deleted ${issueId}`);
|
|
4232
|
+
} catch (err) {
|
|
4233
|
+
record("issue", "delete", false, errMsg(err));
|
|
4234
|
+
}
|
|
4235
|
+
try {
|
|
4236
|
+
const { state } = await loadProject(root);
|
|
4237
|
+
const found = state.issueByID(issueId);
|
|
4238
|
+
if (found) throw new Error(`${issueId} still exists after delete`);
|
|
4239
|
+
record("issue", "verify delete", true, `Confirmed ${issueId} absent`);
|
|
4240
|
+
} catch (err) {
|
|
4241
|
+
record("issue", "verify delete", false, errMsg(err));
|
|
4242
|
+
}
|
|
4243
|
+
}
|
|
4244
|
+
let noteId;
|
|
4245
|
+
try {
|
|
4246
|
+
const { state } = await loadProject(root);
|
|
4247
|
+
noteId = nextNoteID(state.notes);
|
|
4248
|
+
const today = todayISO();
|
|
4249
|
+
const note = {
|
|
4250
|
+
id: noteId,
|
|
4251
|
+
title: "selftest note",
|
|
4252
|
+
content: "Integration smoke test \u2014 will be deleted.",
|
|
4253
|
+
tags: [],
|
|
4254
|
+
status: "active",
|
|
4255
|
+
createdDate: today,
|
|
4256
|
+
updatedDate: today
|
|
4257
|
+
};
|
|
4258
|
+
await writeNote(note, root);
|
|
4259
|
+
createdIds.push({ type: "note", id: noteId });
|
|
4260
|
+
record("note", "create", true, `Created ${noteId}`);
|
|
4261
|
+
} catch (err) {
|
|
4262
|
+
record("note", "create", false, errMsg(err));
|
|
4263
|
+
}
|
|
4264
|
+
if (noteId) {
|
|
4265
|
+
try {
|
|
4266
|
+
const { state } = await loadProject(root);
|
|
4267
|
+
const found = state.noteByID(noteId);
|
|
4268
|
+
if (!found) throw new Error(`${noteId} not found after create`);
|
|
4269
|
+
record("note", "get", true, `Found ${noteId}`);
|
|
4270
|
+
} catch (err) {
|
|
4271
|
+
record("note", "get", false, errMsg(err));
|
|
4272
|
+
}
|
|
4273
|
+
try {
|
|
4274
|
+
const { state } = await loadProject(root);
|
|
4275
|
+
const existing = state.noteByID(noteId);
|
|
4276
|
+
if (!existing) throw new Error(`${noteId} not found for update`);
|
|
4277
|
+
const updated = { ...existing, status: "archived", updatedDate: todayISO() };
|
|
4278
|
+
await writeNote(updated, root);
|
|
4279
|
+
record("note", "update", true, `Updated ${noteId} status \u2192 archived`);
|
|
4280
|
+
} catch (err) {
|
|
4281
|
+
record("note", "update", false, errMsg(err));
|
|
4282
|
+
}
|
|
4283
|
+
try {
|
|
4284
|
+
const { state } = await loadProject(root);
|
|
4285
|
+
const found = state.noteByID(noteId);
|
|
4286
|
+
if (!found) throw new Error(`${noteId} not found for verify`);
|
|
4287
|
+
if (found.status !== "archived") throw new Error(`Expected archived, got ${found.status}`);
|
|
4288
|
+
record("note", "verify update", true, `Verified ${noteId} status = archived`);
|
|
4289
|
+
} catch (err) {
|
|
4290
|
+
record("note", "verify update", false, errMsg(err));
|
|
4291
|
+
}
|
|
4292
|
+
try {
|
|
4293
|
+
await deleteNote(noteId, root);
|
|
4294
|
+
createdIds.splice(createdIds.findIndex((c) => c.id === noteId), 1);
|
|
4295
|
+
record("note", "delete", true, `Deleted ${noteId}`);
|
|
4296
|
+
} catch (err) {
|
|
4297
|
+
record("note", "delete", false, errMsg(err));
|
|
4298
|
+
}
|
|
4299
|
+
try {
|
|
4300
|
+
const { state } = await loadProject(root);
|
|
4301
|
+
const found = state.noteByID(noteId);
|
|
4302
|
+
if (found) throw new Error(`${noteId} still exists after delete`);
|
|
4303
|
+
record("note", "verify delete", true, `Confirmed ${noteId} absent`);
|
|
4304
|
+
} catch (err) {
|
|
4305
|
+
record("note", "verify delete", false, errMsg(err));
|
|
4306
|
+
}
|
|
4307
|
+
}
|
|
4308
|
+
} finally {
|
|
4309
|
+
for (const { type, id } of createdIds.reverse()) {
|
|
4310
|
+
try {
|
|
4311
|
+
if (type === "ticket") await deleteTicket(id, root, { force: true });
|
|
4312
|
+
else if (type === "issue") await deleteIssue(id, root);
|
|
4313
|
+
else await deleteNote(id, root);
|
|
4314
|
+
} catch (err) {
|
|
4315
|
+
cleanupErrors.push(`Failed to delete ${type} ${id}: ${errMsg(err)}`);
|
|
4316
|
+
}
|
|
4317
|
+
}
|
|
4318
|
+
}
|
|
4319
|
+
const passed = results.filter((r) => r.passed).length;
|
|
4320
|
+
const failed = results.filter((r) => !r.passed).length;
|
|
4321
|
+
const result = {
|
|
4322
|
+
passed,
|
|
4323
|
+
failed,
|
|
4324
|
+
total: results.length,
|
|
4325
|
+
results,
|
|
4326
|
+
cleanupErrors
|
|
4327
|
+
};
|
|
4328
|
+
return { output: formatSelftestResult(result, format) };
|
|
4329
|
+
}
|
|
4330
|
+
function errMsg(err) {
|
|
4331
|
+
return err instanceof Error ? err.message : String(err);
|
|
4332
|
+
}
|
|
4333
|
+
var init_selftest = __esm({
|
|
4334
|
+
"src/cli/commands/selftest.ts"() {
|
|
4335
|
+
"use strict";
|
|
4336
|
+
init_esm_shims();
|
|
4337
|
+
init_project_loader();
|
|
4338
|
+
init_id_allocation();
|
|
4339
|
+
init_output_formatter();
|
|
4340
|
+
init_helpers();
|
|
4341
|
+
}
|
|
4342
|
+
});
|
|
4343
|
+
|
|
4008
4344
|
// src/cli/commands/phase.ts
|
|
4009
4345
|
import { join as join6, resolve as resolve6 } from "path";
|
|
4010
4346
|
function validatePhaseId(id) {
|
|
@@ -4077,11 +4413,9 @@ async function handlePhaseCreate(args, format, root) {
|
|
|
4077
4413
|
id: args.id,
|
|
4078
4414
|
label: args.label,
|
|
4079
4415
|
name: args.name,
|
|
4080
|
-
description: args.description
|
|
4416
|
+
description: args.description,
|
|
4417
|
+
...args.summary !== void 0 && { summary: args.summary }
|
|
4081
4418
|
};
|
|
4082
|
-
if (args.summary !== void 0) {
|
|
4083
|
-
phase.summary = args.summary;
|
|
4084
|
-
}
|
|
4085
4419
|
const newPhases = [...state.roadmap.phases];
|
|
4086
4420
|
if (args.atStart) {
|
|
4087
4421
|
newPhases.unshift(phase);
|
|
@@ -4110,11 +4444,13 @@ async function handlePhaseRename(id, updates, format, root) {
|
|
|
4110
4444
|
throw new CliValidationError("not_found", `Phase "${id}" not found`);
|
|
4111
4445
|
}
|
|
4112
4446
|
const existing = state.roadmap.phases[idx];
|
|
4113
|
-
const phase = {
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4447
|
+
const phase = {
|
|
4448
|
+
...existing,
|
|
4449
|
+
...updates.name !== void 0 && { name: updates.name },
|
|
4450
|
+
...updates.label !== void 0 && { label: updates.label },
|
|
4451
|
+
...updates.description !== void 0 && { description: updates.description },
|
|
4452
|
+
...updates.summary !== void 0 && { summary: updates.summary }
|
|
4453
|
+
};
|
|
4118
4454
|
const newPhases = [...state.roadmap.phases];
|
|
4119
4455
|
newPhases[idx] = phase;
|
|
4120
4456
|
const newRoadmap = { ...state.roadmap, phases: newPhases };
|
|
@@ -4495,7 +4831,8 @@ function registerAllTools(server, pinnedRoot) {
|
|
|
4495
4831
|
id: z8.string().regex(TICKET_ID_REGEX).describe("Ticket ID (e.g. T-001)"),
|
|
4496
4832
|
status: z8.enum(TICKET_STATUSES).optional().describe("New status: open, inprogress, complete"),
|
|
4497
4833
|
title: z8.string().optional().describe("New title"),
|
|
4498
|
-
|
|
4834
|
+
type: z8.enum(TICKET_TYPES).optional().describe("New type: task, feature, chore"),
|
|
4835
|
+
order: z8.number().int().optional().describe("New sort order"),
|
|
4499
4836
|
description: z8.string().optional().describe("New description"),
|
|
4500
4837
|
phase: z8.string().nullable().optional().describe("New phase ID (null to clear)"),
|
|
4501
4838
|
parentTicket: z8.string().regex(TICKET_ID_REGEX).nullable().optional().describe("Parent ticket ID (null to clear)"),
|
|
@@ -4508,6 +4845,7 @@ function registerAllTools(server, pinnedRoot) {
|
|
|
4508
4845
|
{
|
|
4509
4846
|
status: args.status,
|
|
4510
4847
|
title: args.title,
|
|
4848
|
+
type: args.type,
|
|
4511
4849
|
order: args.order,
|
|
4512
4850
|
description: args.description,
|
|
4513
4851
|
phase: args.phase,
|
|
@@ -4556,7 +4894,9 @@ function registerAllTools(server, pinnedRoot) {
|
|
|
4556
4894
|
resolution: z8.string().nullable().optional().describe("Resolution description (null to clear)"),
|
|
4557
4895
|
components: z8.array(z8.string()).optional().describe("Affected components"),
|
|
4558
4896
|
relatedTickets: z8.array(z8.string().regex(TICKET_ID_REGEX)).optional().describe("Related ticket IDs"),
|
|
4559
|
-
location: z8.array(z8.string()).optional().describe("File locations")
|
|
4897
|
+
location: z8.array(z8.string()).optional().describe("File locations"),
|
|
4898
|
+
order: z8.number().int().optional().describe("New sort order"),
|
|
4899
|
+
phase: z8.string().nullable().optional().describe("New phase ID (null to clear)")
|
|
4560
4900
|
}
|
|
4561
4901
|
}, (args) => runMcpWriteTool(
|
|
4562
4902
|
pinnedRoot,
|
|
@@ -4570,7 +4910,9 @@ function registerAllTools(server, pinnedRoot) {
|
|
|
4570
4910
|
resolution: args.resolution,
|
|
4571
4911
|
components: args.components,
|
|
4572
4912
|
relatedTickets: args.relatedTickets,
|
|
4573
|
-
location: args.location
|
|
4913
|
+
location: args.location,
|
|
4914
|
+
order: args.order,
|
|
4915
|
+
phase: args.phase
|
|
4574
4916
|
},
|
|
4575
4917
|
format,
|
|
4576
4918
|
root
|
|
@@ -4635,6 +4977,39 @@ function registerAllTools(server, pinnedRoot) {
|
|
|
4635
4977
|
root
|
|
4636
4978
|
)
|
|
4637
4979
|
));
|
|
4980
|
+
server.registerTool("claudestory_phase_create", {
|
|
4981
|
+
description: "Create a new phase in the roadmap. Exactly one of after or atStart is required for positioning.",
|
|
4982
|
+
inputSchema: {
|
|
4983
|
+
id: z8.string().describe("Phase ID \u2014 lowercase alphanumeric with hyphens (e.g. 'my-phase')"),
|
|
4984
|
+
name: z8.string().describe("Phase display name"),
|
|
4985
|
+
label: z8.string().describe("Phase label (e.g. 'PHASE 1')"),
|
|
4986
|
+
description: z8.string().describe("Phase description"),
|
|
4987
|
+
summary: z8.string().optional().describe("One-line summary for compact display"),
|
|
4988
|
+
after: z8.string().optional().describe("Insert after this phase ID"),
|
|
4989
|
+
atStart: z8.boolean().optional().describe("Insert at beginning of roadmap")
|
|
4990
|
+
}
|
|
4991
|
+
}, (args) => runMcpWriteTool(
|
|
4992
|
+
pinnedRoot,
|
|
4993
|
+
(root, format) => handlePhaseCreate(
|
|
4994
|
+
{
|
|
4995
|
+
id: args.id,
|
|
4996
|
+
name: args.name,
|
|
4997
|
+
label: args.label,
|
|
4998
|
+
description: args.description,
|
|
4999
|
+
summary: args.summary,
|
|
5000
|
+
after: args.after,
|
|
5001
|
+
atStart: args.atStart ?? false
|
|
5002
|
+
},
|
|
5003
|
+
format,
|
|
5004
|
+
root
|
|
5005
|
+
)
|
|
5006
|
+
));
|
|
5007
|
+
server.registerTool("claudestory_selftest", {
|
|
5008
|
+
description: "Integration smoke test \u2014 creates, updates, and deletes test entities to verify the full pipeline"
|
|
5009
|
+
}, () => runMcpWriteTool(
|
|
5010
|
+
pinnedRoot,
|
|
5011
|
+
(root, format) => handleSelftest(root, format)
|
|
5012
|
+
));
|
|
4638
5013
|
}
|
|
4639
5014
|
var INFRASTRUCTURE_ERROR_CODES;
|
|
4640
5015
|
var init_tools = __esm({
|
|
@@ -4656,6 +5031,7 @@ var init_tools = __esm({
|
|
|
4656
5031
|
init_recommend2();
|
|
4657
5032
|
init_snapshot2();
|
|
4658
5033
|
init_export();
|
|
5034
|
+
init_selftest();
|
|
4659
5035
|
init_handover();
|
|
4660
5036
|
init_phase();
|
|
4661
5037
|
INFRASTRUCTURE_ERROR_CODES = [
|
|
@@ -4666,89 +5042,12 @@ var init_tools = __esm({
|
|
|
4666
5042
|
}
|
|
4667
5043
|
});
|
|
4668
5044
|
|
|
4669
|
-
// src/mcp/index.ts
|
|
4670
|
-
var mcp_exports = {};
|
|
4671
|
-
import { realpathSync, existsSync as existsSync6 } from "fs";
|
|
4672
|
-
import { resolve as resolve7, join as join8, isAbsolute } from "path";
|
|
4673
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4674
|
-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4675
|
-
function tryDiscoverRoot() {
|
|
4676
|
-
const envRoot = process.env[ENV_VAR2];
|
|
4677
|
-
if (envRoot) {
|
|
4678
|
-
if (!isAbsolute(envRoot)) {
|
|
4679
|
-
process.stderr.write(`Warning: ${ENV_VAR2} must be an absolute path, got: ${envRoot}
|
|
4680
|
-
`);
|
|
4681
|
-
return null;
|
|
4682
|
-
}
|
|
4683
|
-
const resolved = resolve7(envRoot);
|
|
4684
|
-
try {
|
|
4685
|
-
const canonical = realpathSync(resolved);
|
|
4686
|
-
if (existsSync6(join8(canonical, CONFIG_PATH2))) {
|
|
4687
|
-
return canonical;
|
|
4688
|
-
}
|
|
4689
|
-
process.stderr.write(`Warning: No .story/config.json at ${canonical}
|
|
4690
|
-
`);
|
|
4691
|
-
} catch {
|
|
4692
|
-
process.stderr.write(`Warning: ${ENV_VAR2} path does not exist: ${resolved}
|
|
4693
|
-
`);
|
|
4694
|
-
}
|
|
4695
|
-
return null;
|
|
4696
|
-
}
|
|
4697
|
-
try {
|
|
4698
|
-
const root = discoverProjectRoot();
|
|
4699
|
-
return root ? realpathSync(root) : null;
|
|
4700
|
-
} catch {
|
|
4701
|
-
return null;
|
|
4702
|
-
}
|
|
4703
|
-
}
|
|
4704
|
-
async function main() {
|
|
4705
|
-
const root = tryDiscoverRoot();
|
|
4706
|
-
const server = new McpServer(
|
|
4707
|
-
{ name: "claudestory", version },
|
|
4708
|
-
{
|
|
4709
|
-
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."
|
|
4710
|
-
}
|
|
4711
|
-
);
|
|
4712
|
-
if (root) {
|
|
4713
|
-
registerAllTools(server, root);
|
|
4714
|
-
process.stderr.write(`claudestory MCP server running (root: ${root})
|
|
4715
|
-
`);
|
|
4716
|
-
} else {
|
|
4717
|
-
server.registerTool("claudestory_status", {
|
|
4718
|
-
description: "Project summary \u2014 returns error if no .story/ project found"
|
|
4719
|
-
}, () => Promise.resolve({
|
|
4720
|
-
content: [{ type: "text", text: "No .story/ project found. Navigate to a directory containing .story/ or set CLAUDESTORY_PROJECT_ROOT." }],
|
|
4721
|
-
isError: true
|
|
4722
|
-
}));
|
|
4723
|
-
process.stderr.write("claudestory MCP server running (no project found \u2014 tools will report errors)\n");
|
|
4724
|
-
}
|
|
4725
|
-
const transport = new StdioServerTransport();
|
|
4726
|
-
await server.connect(transport);
|
|
4727
|
-
}
|
|
4728
|
-
var ENV_VAR2, CONFIG_PATH2, version;
|
|
4729
|
-
var init_mcp = __esm({
|
|
4730
|
-
"src/mcp/index.ts"() {
|
|
4731
|
-
"use strict";
|
|
4732
|
-
init_esm_shims();
|
|
4733
|
-
init_project_root_discovery();
|
|
4734
|
-
init_tools();
|
|
4735
|
-
ENV_VAR2 = "CLAUDESTORY_PROJECT_ROOT";
|
|
4736
|
-
CONFIG_PATH2 = ".story/config.json";
|
|
4737
|
-
version = "0.1.10";
|
|
4738
|
-
main().catch((err) => {
|
|
4739
|
-
process.stderr.write(`Fatal: ${err instanceof Error ? err.message : String(err)}
|
|
4740
|
-
`);
|
|
4741
|
-
process.exit(1);
|
|
4742
|
-
});
|
|
4743
|
-
}
|
|
4744
|
-
});
|
|
4745
|
-
|
|
4746
5045
|
// src/core/init.ts
|
|
4747
5046
|
import { mkdir as mkdir4, stat as stat2 } from "fs/promises";
|
|
4748
|
-
import { join as
|
|
5047
|
+
import { join as join8, resolve as resolve7 } from "path";
|
|
4749
5048
|
async function initProject(root, options) {
|
|
4750
|
-
const absRoot =
|
|
4751
|
-
const wrapDir =
|
|
5049
|
+
const absRoot = resolve7(root);
|
|
5050
|
+
const wrapDir = join8(absRoot, ".story");
|
|
4752
5051
|
let exists = false;
|
|
4753
5052
|
try {
|
|
4754
5053
|
const s = await stat2(wrapDir);
|
|
@@ -4768,10 +5067,10 @@ async function initProject(root, options) {
|
|
|
4768
5067
|
".story/ already exists. Use --force to overwrite config and roadmap."
|
|
4769
5068
|
);
|
|
4770
5069
|
}
|
|
4771
|
-
await mkdir4(
|
|
4772
|
-
await mkdir4(
|
|
4773
|
-
await mkdir4(
|
|
4774
|
-
await mkdir4(
|
|
5070
|
+
await mkdir4(join8(wrapDir, "tickets"), { recursive: true });
|
|
5071
|
+
await mkdir4(join8(wrapDir, "issues"), { recursive: true });
|
|
5072
|
+
await mkdir4(join8(wrapDir, "handovers"), { recursive: true });
|
|
5073
|
+
await mkdir4(join8(wrapDir, "notes"), { recursive: true });
|
|
4775
5074
|
const created = [
|
|
4776
5075
|
".story/config.json",
|
|
4777
5076
|
".story/roadmap.json",
|
|
@@ -4798,7 +5097,7 @@ async function initProject(root, options) {
|
|
|
4798
5097
|
const roadmap = {
|
|
4799
5098
|
title: options.name,
|
|
4800
5099
|
date: today,
|
|
4801
|
-
phases: [
|
|
5100
|
+
phases: options.phases ?? [
|
|
4802
5101
|
{
|
|
4803
5102
|
id: "p0",
|
|
4804
5103
|
label: "PHASE 0",
|
|
@@ -4837,6 +5136,136 @@ var init_init = __esm({
|
|
|
4837
5136
|
}
|
|
4838
5137
|
});
|
|
4839
5138
|
|
|
5139
|
+
// src/mcp/index.ts
|
|
5140
|
+
var mcp_exports = {};
|
|
5141
|
+
import { realpathSync, existsSync as existsSync6 } from "fs";
|
|
5142
|
+
import { resolve as resolve8, join as join9, isAbsolute } from "path";
|
|
5143
|
+
import { z as z9 } from "zod";
|
|
5144
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5145
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5146
|
+
function tryDiscoverRoot() {
|
|
5147
|
+
const envRoot = process.env[ENV_VAR2];
|
|
5148
|
+
if (envRoot) {
|
|
5149
|
+
if (!isAbsolute(envRoot)) {
|
|
5150
|
+
process.stderr.write(`Warning: ${ENV_VAR2} must be an absolute path, got: ${envRoot}
|
|
5151
|
+
`);
|
|
5152
|
+
return null;
|
|
5153
|
+
}
|
|
5154
|
+
const resolved = resolve8(envRoot);
|
|
5155
|
+
try {
|
|
5156
|
+
const canonical = realpathSync(resolved);
|
|
5157
|
+
if (existsSync6(join9(canonical, CONFIG_PATH2))) {
|
|
5158
|
+
return canonical;
|
|
5159
|
+
}
|
|
5160
|
+
process.stderr.write(`Warning: No .story/config.json at ${canonical}
|
|
5161
|
+
`);
|
|
5162
|
+
} catch {
|
|
5163
|
+
process.stderr.write(`Warning: ${ENV_VAR2} path does not exist: ${resolved}
|
|
5164
|
+
`);
|
|
5165
|
+
}
|
|
5166
|
+
return null;
|
|
5167
|
+
}
|
|
5168
|
+
try {
|
|
5169
|
+
const root = discoverProjectRoot();
|
|
5170
|
+
return root ? realpathSync(root) : null;
|
|
5171
|
+
} catch {
|
|
5172
|
+
return null;
|
|
5173
|
+
}
|
|
5174
|
+
}
|
|
5175
|
+
function registerDegradedTools(server) {
|
|
5176
|
+
const degradedStatus = server.registerTool("claudestory_status", {
|
|
5177
|
+
description: "Project summary \u2014 returns guidance if no .story/ project found"
|
|
5178
|
+
}, () => Promise.resolve({
|
|
5179
|
+
content: [{ type: "text", text: "No .story/ project found. Use claudestory_init to create one, or navigate to a directory with .story/." }],
|
|
5180
|
+
isError: true
|
|
5181
|
+
}));
|
|
5182
|
+
const degradedInit = server.registerTool("claudestory_init", {
|
|
5183
|
+
description: "Initialize a new .story/ project in the current directory",
|
|
5184
|
+
inputSchema: {
|
|
5185
|
+
name: z9.string().describe("Project name"),
|
|
5186
|
+
type: z9.string().optional().describe("Project type (e.g. npm, macapp, cargo, generic)"),
|
|
5187
|
+
language: z9.string().optional().describe("Primary language (e.g. typescript, swift, rust)")
|
|
5188
|
+
}
|
|
5189
|
+
}, async (args) => {
|
|
5190
|
+
let result;
|
|
5191
|
+
try {
|
|
5192
|
+
const projectRoot = realpathSync(process.cwd());
|
|
5193
|
+
result = await initProject(projectRoot, {
|
|
5194
|
+
name: args.name,
|
|
5195
|
+
type: args.type,
|
|
5196
|
+
language: args.language,
|
|
5197
|
+
phases: []
|
|
5198
|
+
});
|
|
5199
|
+
} catch (err) {
|
|
5200
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
5201
|
+
return { content: [{ type: "text", text: `[init_error] ${msg}` }], isError: true };
|
|
5202
|
+
}
|
|
5203
|
+
try {
|
|
5204
|
+
degradedStatus.remove();
|
|
5205
|
+
degradedInit.remove();
|
|
5206
|
+
registerAllTools(server, result.root);
|
|
5207
|
+
} catch (swapErr) {
|
|
5208
|
+
process.stderr.write(`claudestory: tool-swap failed after init: ${swapErr instanceof Error ? swapErr.message : String(swapErr)}
|
|
5209
|
+
`);
|
|
5210
|
+
try {
|
|
5211
|
+
registerDegradedTools(server);
|
|
5212
|
+
} catch {
|
|
5213
|
+
}
|
|
5214
|
+
return { content: [{ type: "text", text: `Initialized .story/ project "${args.name}" at ${result.root}
|
|
5215
|
+
|
|
5216
|
+
Warning: tool registration failed. Restart the MCP server for full tool access.` }] };
|
|
5217
|
+
}
|
|
5218
|
+
process.stderr.write(`claudestory: initialized at ${result.root}
|
|
5219
|
+
`);
|
|
5220
|
+
const lines = [
|
|
5221
|
+
`Initialized .story/ project "${args.name}" at ${result.root}`,
|
|
5222
|
+
`Created: ${result.created.join(", ")}`
|
|
5223
|
+
];
|
|
5224
|
+
if (result.warnings.length > 0) {
|
|
5225
|
+
lines.push(`Warnings: ${result.warnings.join("; ")}`);
|
|
5226
|
+
}
|
|
5227
|
+
lines.push("", "All claudestory tools are now available. Use claudestory_phase_create to add phases and claudestory_ticket_create to add tickets.");
|
|
5228
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
5229
|
+
});
|
|
5230
|
+
}
|
|
5231
|
+
async function main() {
|
|
5232
|
+
const root = tryDiscoverRoot();
|
|
5233
|
+
const server = new McpServer(
|
|
5234
|
+
{ name: "claudestory", version },
|
|
5235
|
+
{
|
|
5236
|
+
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. Use claudestory_init to initialize a new project, or navigate to a directory with .story/."
|
|
5237
|
+
}
|
|
5238
|
+
);
|
|
5239
|
+
if (root) {
|
|
5240
|
+
registerAllTools(server, root);
|
|
5241
|
+
process.stderr.write(`claudestory MCP server running (root: ${root})
|
|
5242
|
+
`);
|
|
5243
|
+
} else {
|
|
5244
|
+
registerDegradedTools(server);
|
|
5245
|
+
process.stderr.write("claudestory MCP server running (no project \u2014 claudestory_init available)\n");
|
|
5246
|
+
}
|
|
5247
|
+
const transport = new StdioServerTransport();
|
|
5248
|
+
await server.connect(transport);
|
|
5249
|
+
}
|
|
5250
|
+
var ENV_VAR2, CONFIG_PATH2, version;
|
|
5251
|
+
var init_mcp = __esm({
|
|
5252
|
+
"src/mcp/index.ts"() {
|
|
5253
|
+
"use strict";
|
|
5254
|
+
init_esm_shims();
|
|
5255
|
+
init_project_root_discovery();
|
|
5256
|
+
init_tools();
|
|
5257
|
+
init_init();
|
|
5258
|
+
ENV_VAR2 = "CLAUDESTORY_PROJECT_ROOT";
|
|
5259
|
+
CONFIG_PATH2 = ".story/config.json";
|
|
5260
|
+
version = "0.1.10";
|
|
5261
|
+
main().catch((err) => {
|
|
5262
|
+
process.stderr.write(`Fatal: ${err instanceof Error ? err.message : String(err)}
|
|
5263
|
+
`);
|
|
5264
|
+
process.exit(1);
|
|
5265
|
+
});
|
|
5266
|
+
}
|
|
5267
|
+
});
|
|
5268
|
+
|
|
4840
5269
|
// src/core/index.ts
|
|
4841
5270
|
var init_core = __esm({
|
|
4842
5271
|
"src/core/index.ts"() {
|
|
@@ -5106,8 +5535,8 @@ var init_reference = __esm({
|
|
|
5106
5535
|
{
|
|
5107
5536
|
name: "ticket update",
|
|
5108
5537
|
description: "Update a ticket",
|
|
5109
|
-
usage: "claudestory ticket update <id> [--status <s>] [--title <t>] [--phase <p>] [--order <n>] [--description <d>] [--blocked-by <ids>] [--parent-ticket <id>] [--format json|md]",
|
|
5110
|
-
flags: ["--status", "--title", "--phase", "--order", "--description", "--blocked-by", "--parent-ticket"]
|
|
5538
|
+
usage: "claudestory ticket update <id> [--status <s>] [--title <t>] [--type <type>] [--phase <p>] [--order <n>] [--description <d>] [--blocked-by <ids>] [--parent-ticket <id>] [--format json|md]",
|
|
5539
|
+
flags: ["--status", "--title", "--type", "--phase", "--order", "--description", "--blocked-by", "--parent-ticket"]
|
|
5111
5540
|
},
|
|
5112
5541
|
{
|
|
5113
5542
|
name: "ticket delete",
|
|
@@ -5129,14 +5558,14 @@ var init_reference = __esm({
|
|
|
5129
5558
|
{
|
|
5130
5559
|
name: "issue create",
|
|
5131
5560
|
description: "Create a new issue",
|
|
5132
|
-
usage: "claudestory issue create --title <t> --severity <s> --impact <i> [--components <c>] [--related-tickets <ids>] [--location <locs>] [--format json|md]",
|
|
5133
|
-
flags: ["--title", "--severity", "--impact", "--components", "--related-tickets", "--location"]
|
|
5561
|
+
usage: "claudestory issue create --title <t> --severity <s> --impact <i> [--components <c>] [--related-tickets <ids>] [--location <locs>] [--phase <p>] [--format json|md]",
|
|
5562
|
+
flags: ["--title", "--severity", "--impact", "--components", "--related-tickets", "--location", "--phase"]
|
|
5134
5563
|
},
|
|
5135
5564
|
{
|
|
5136
5565
|
name: "issue update",
|
|
5137
5566
|
description: "Update an issue",
|
|
5138
|
-
usage: "claudestory issue update <id> [--status <s>] [--title <t>] [--severity <sev>] [--impact <i>] [--resolution <r>] [--components <c>] [--related-tickets <ids>] [--location <locs>] [--format json|md]",
|
|
5139
|
-
flags: ["--status", "--title", "--severity", "--impact", "--resolution", "--components", "--related-tickets", "--location"]
|
|
5567
|
+
usage: "claudestory issue update <id> [--status <s>] [--title <t>] [--severity <sev>] [--impact <i>] [--resolution <r>] [--components <c>] [--related-tickets <ids>] [--location <locs>] [--order <n>] [--phase <p>] [--format json|md]",
|
|
5568
|
+
flags: ["--status", "--title", "--severity", "--impact", "--resolution", "--components", "--related-tickets", "--location", "--order", "--phase"]
|
|
5140
5569
|
},
|
|
5141
5570
|
{
|
|
5142
5571
|
name: "issue delete",
|
|
@@ -5281,6 +5710,11 @@ var init_reference = __esm({
|
|
|
5281
5710
|
description: "Print CLI command and MCP tool reference",
|
|
5282
5711
|
usage: "claudestory reference [--format json|md]"
|
|
5283
5712
|
},
|
|
5713
|
+
{
|
|
5714
|
+
name: "selftest",
|
|
5715
|
+
description: "Run integration smoke test \u2014 create/update/delete cycle across all entity types",
|
|
5716
|
+
usage: "claudestory selftest [--format json|md]"
|
|
5717
|
+
},
|
|
5284
5718
|
{
|
|
5285
5719
|
name: "setup-skill",
|
|
5286
5720
|
description: "Install the /story skill globally for Claude Code",
|
|
@@ -5296,7 +5730,7 @@ var init_reference = __esm({
|
|
|
5296
5730
|
{ name: "claudestory_ticket_get", description: "Get a ticket by ID", params: ["id"] },
|
|
5297
5731
|
{ name: "claudestory_ticket_next", description: "Highest-priority unblocked ticket(s)", params: ["count?"] },
|
|
5298
5732
|
{ name: "claudestory_ticket_blocked", description: "All blocked tickets with dependencies" },
|
|
5299
|
-
{ name: "claudestory_issue_list", description: "List issues with optional filters", params: ["status?", "severity?"] },
|
|
5733
|
+
{ name: "claudestory_issue_list", description: "List issues with optional filters", params: ["status?", "severity?", "component?"] },
|
|
5300
5734
|
{ name: "claudestory_issue_get", description: "Get an issue by ID", params: ["id"] },
|
|
5301
5735
|
{ name: "claudestory_handover_list", description: "List handover filenames (newest first)" },
|
|
5302
5736
|
{ name: "claudestory_handover_latest", description: "Content of most recent handover" },
|
|
@@ -5313,9 +5747,11 @@ var init_reference = __esm({
|
|
|
5313
5747
|
{ name: "claudestory_note_create", description: "Create note", params: ["content", "title?", "tags?"] },
|
|
5314
5748
|
{ name: "claudestory_note_update", description: "Update note", params: ["id", "content?", "title?", "tags?", "status?"] },
|
|
5315
5749
|
{ name: "claudestory_ticket_create", description: "Create ticket", params: ["title", "type", "phase?", "description?", "blockedBy?", "parentTicket?"] },
|
|
5316
|
-
{ name: "claudestory_ticket_update", description: "Update ticket", params: ["id", "status?", "title?", "order?", "description?", "phase?", "parentTicket?"] },
|
|
5750
|
+
{ name: "claudestory_ticket_update", description: "Update ticket", params: ["id", "status?", "title?", "type?", "order?", "description?", "phase?", "parentTicket?", "blockedBy?"] },
|
|
5317
5751
|
{ name: "claudestory_issue_create", description: "Create issue", params: ["title", "severity", "impact", "components?", "relatedTickets?", "location?", "phase?"] },
|
|
5318
|
-
{ name: "claudestory_issue_update", description: "Update issue", params: ["id", "status?", "title?", "severity?", "impact?", "resolution?", "components?", "relatedTickets?", "location?"] }
|
|
5752
|
+
{ name: "claudestory_issue_update", description: "Update issue", params: ["id", "status?", "title?", "severity?", "impact?", "resolution?", "components?", "relatedTickets?", "location?", "order?", "phase?"] },
|
|
5753
|
+
{ name: "claudestory_phase_create", description: "Create phase in roadmap", params: ["id", "name", "label", "description", "summary?", "after?", "atStart?"] },
|
|
5754
|
+
{ name: "claudestory_selftest", description: "Integration smoke test \u2014 create/update/delete cycle" }
|
|
5319
5755
|
];
|
|
5320
5756
|
}
|
|
5321
5757
|
});
|
|
@@ -5559,6 +5995,7 @@ __export(register_exports, {
|
|
|
5559
5995
|
registerRecapCommand: () => registerRecapCommand,
|
|
5560
5996
|
registerRecommendCommand: () => registerRecommendCommand,
|
|
5561
5997
|
registerReferenceCommand: () => registerReferenceCommand,
|
|
5998
|
+
registerSelftestCommand: () => registerSelftestCommand,
|
|
5562
5999
|
registerSetupSkillCommand: () => registerSetupSkillCommand,
|
|
5563
6000
|
registerSnapshotCommand: () => registerSnapshotCommand,
|
|
5564
6001
|
registerStatusCommand: () => registerStatusCommand,
|
|
@@ -6007,6 +6444,9 @@ function registerTicketCommand(yargs) {
|
|
|
6007
6444
|
}).option("title", {
|
|
6008
6445
|
type: "string",
|
|
6009
6446
|
describe: "New title"
|
|
6447
|
+
}).option("type", {
|
|
6448
|
+
type: "string",
|
|
6449
|
+
describe: "New type"
|
|
6010
6450
|
}).option("phase", {
|
|
6011
6451
|
type: "string",
|
|
6012
6452
|
describe: "New phase ID"
|
|
@@ -6053,6 +6493,7 @@ function registerTicketCommand(yargs) {
|
|
|
6053
6493
|
{
|
|
6054
6494
|
status: argv.status,
|
|
6055
6495
|
title: argv.title,
|
|
6496
|
+
type: argv.type,
|
|
6056
6497
|
phase: argv.phase === "" ? null : argv.phase,
|
|
6057
6498
|
order: argv.order,
|
|
6058
6499
|
description,
|
|
@@ -6234,7 +6675,7 @@ function registerIssueCommand(yargs) {
|
|
|
6234
6675
|
location: normalizeArrayOption(
|
|
6235
6676
|
argv.location
|
|
6236
6677
|
),
|
|
6237
|
-
phase: argv.phase
|
|
6678
|
+
phase: argv.phase === "" ? void 0 : argv.phase
|
|
6238
6679
|
},
|
|
6239
6680
|
format,
|
|
6240
6681
|
root
|
|
@@ -6296,6 +6737,12 @@ function registerIssueCommand(yargs) {
|
|
|
6296
6737
|
type: "string",
|
|
6297
6738
|
array: true,
|
|
6298
6739
|
describe: "File locations"
|
|
6740
|
+
}).option("order", {
|
|
6741
|
+
type: "number",
|
|
6742
|
+
describe: "New sort order"
|
|
6743
|
+
}).option("phase", {
|
|
6744
|
+
type: "string",
|
|
6745
|
+
describe: "New phase ID"
|
|
6299
6746
|
}).conflicts("impact", "stdin")
|
|
6300
6747
|
),
|
|
6301
6748
|
async (argv) => {
|
|
@@ -6328,7 +6775,9 @@ function registerIssueCommand(yargs) {
|
|
|
6328
6775
|
resolution: argv.resolution === "" ? null : argv.resolution,
|
|
6329
6776
|
components: argv.components ? normalizeArrayOption(argv.components) : void 0,
|
|
6330
6777
|
relatedTickets: argv["related-tickets"] ? normalizeArrayOption(argv["related-tickets"]) : void 0,
|
|
6331
|
-
location: argv.location ? normalizeArrayOption(argv.location) : void 0
|
|
6778
|
+
location: argv.location ? normalizeArrayOption(argv.location) : void 0,
|
|
6779
|
+
order: argv.order,
|
|
6780
|
+
phase: argv.phase === "" ? null : argv.phase
|
|
6332
6781
|
},
|
|
6333
6782
|
format,
|
|
6334
6783
|
root
|
|
@@ -6921,7 +7370,6 @@ function registerNoteCommand(yargs) {
|
|
|
6921
7370
|
describe: "New tags (replaces existing)"
|
|
6922
7371
|
}).option("clear-tags", {
|
|
6923
7372
|
type: "boolean",
|
|
6924
|
-
default: false,
|
|
6925
7373
|
describe: "Clear all tags"
|
|
6926
7374
|
}).option("status", {
|
|
6927
7375
|
type: "string",
|
|
@@ -7037,6 +7485,44 @@ function registerRecommendCommand(yargs) {
|
|
|
7037
7485
|
}
|
|
7038
7486
|
);
|
|
7039
7487
|
}
|
|
7488
|
+
function registerSelftestCommand(yargs) {
|
|
7489
|
+
return yargs.command(
|
|
7490
|
+
"selftest",
|
|
7491
|
+
"Run integration smoke test \u2014 create/update/delete cycle across all entity types",
|
|
7492
|
+
(y) => addFormatOption(y),
|
|
7493
|
+
async (argv) => {
|
|
7494
|
+
const format = parseOutputFormat(argv.format);
|
|
7495
|
+
const root = (await Promise.resolve().then(() => (init_project_root_discovery(), project_root_discovery_exports))).discoverProjectRoot();
|
|
7496
|
+
if (!root) {
|
|
7497
|
+
writeOutput(
|
|
7498
|
+
formatError("not_found", "No .story/ project found.", format)
|
|
7499
|
+
);
|
|
7500
|
+
process.exitCode = ExitCode.USER_ERROR;
|
|
7501
|
+
return;
|
|
7502
|
+
}
|
|
7503
|
+
try {
|
|
7504
|
+
const result = await handleSelftest(root, format);
|
|
7505
|
+
writeOutput(result.output);
|
|
7506
|
+
process.exitCode = result.exitCode ?? ExitCode.OK;
|
|
7507
|
+
} catch (err) {
|
|
7508
|
+
if (err instanceof CliValidationError) {
|
|
7509
|
+
writeOutput(formatError(err.code, err.message, format));
|
|
7510
|
+
process.exitCode = ExitCode.USER_ERROR;
|
|
7511
|
+
return;
|
|
7512
|
+
}
|
|
7513
|
+
const { ProjectLoaderError: ProjectLoaderError2 } = await Promise.resolve().then(() => (init_errors(), errors_exports));
|
|
7514
|
+
if (err instanceof ProjectLoaderError2) {
|
|
7515
|
+
writeOutput(formatError(err.code, err.message, format));
|
|
7516
|
+
process.exitCode = ExitCode.USER_ERROR;
|
|
7517
|
+
return;
|
|
7518
|
+
}
|
|
7519
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
7520
|
+
writeOutput(formatError("io_error", message, format));
|
|
7521
|
+
process.exitCode = ExitCode.USER_ERROR;
|
|
7522
|
+
}
|
|
7523
|
+
}
|
|
7524
|
+
);
|
|
7525
|
+
}
|
|
7040
7526
|
function registerSetupSkillCommand(yargs) {
|
|
7041
7527
|
return yargs.command(
|
|
7042
7528
|
"setup-skill",
|
|
@@ -7073,6 +7559,7 @@ var init_register = __esm({
|
|
|
7073
7559
|
init_export();
|
|
7074
7560
|
init_snapshot2();
|
|
7075
7561
|
init_reference();
|
|
7562
|
+
init_selftest();
|
|
7076
7563
|
}
|
|
7077
7564
|
});
|
|
7078
7565
|
|
|
@@ -7103,6 +7590,7 @@ async function runCli() {
|
|
|
7103
7590
|
registerNoteCommand: registerNoteCommand2,
|
|
7104
7591
|
registerRecommendCommand: registerRecommendCommand2,
|
|
7105
7592
|
registerReferenceCommand: registerReferenceCommand2,
|
|
7593
|
+
registerSelftestCommand: registerSelftestCommand2,
|
|
7106
7594
|
registerSetupSkillCommand: registerSetupSkillCommand2
|
|
7107
7595
|
} = await Promise.resolve().then(() => (init_register(), register_exports));
|
|
7108
7596
|
const version2 = "0.1.10";
|
|
@@ -7141,6 +7629,7 @@ async function runCli() {
|
|
|
7141
7629
|
cli = registerExportCommand2(cli);
|
|
7142
7630
|
cli = registerRecommendCommand2(cli);
|
|
7143
7631
|
cli = registerReferenceCommand2(cli);
|
|
7632
|
+
cli = registerSelftestCommand2(cli);
|
|
7144
7633
|
cli = registerSetupSkillCommand2(cli);
|
|
7145
7634
|
function handleUnexpectedError(err) {
|
|
7146
7635
|
if (err instanceof HandledError) return;
|