@anthropologies/claudestory 0.1.28 → 0.1.30
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 +34 -12
- package/dist/index.d.ts +7 -2
- package/dist/index.js +24 -2
- package/dist/mcp.js +32 -11
- package/package.json +1 -1
- package/src/skill/SKILL.md +8 -0
package/dist/cli.js
CHANGED
|
@@ -491,6 +491,15 @@ var init_project_state = __esm({
|
|
|
491
491
|
get blockedCount() {
|
|
492
492
|
return this.leafTickets.filter((t) => t.status !== "complete" && this.isBlocked(t)).length;
|
|
493
493
|
}
|
|
494
|
+
/** True when the project has been initialized but not yet populated with tickets/issues/handovers. */
|
|
495
|
+
get isEmptyScaffold() {
|
|
496
|
+
return this.tickets.length === 0 && this.issues.length === 0 && this.handoverFilenames.length === 0 && this.isDefaultScaffoldPhases;
|
|
497
|
+
}
|
|
498
|
+
get isDefaultScaffoldPhases() {
|
|
499
|
+
const { phases } = this.roadmap;
|
|
500
|
+
if (phases.length === 0) return true;
|
|
501
|
+
return phases.length === 1 && phases[0].id === "p0";
|
|
502
|
+
}
|
|
494
503
|
ticketByID(id) {
|
|
495
504
|
return this.ticketsByID.get(id);
|
|
496
505
|
}
|
|
@@ -1673,6 +1682,7 @@ var init_queries = __esm({
|
|
|
1673
1682
|
// src/core/output-formatter.ts
|
|
1674
1683
|
var output_formatter_exports = {};
|
|
1675
1684
|
__export(output_formatter_exports, {
|
|
1685
|
+
EMPTY_SCAFFOLD_HEADING: () => EMPTY_SCAFFOLD_HEADING,
|
|
1676
1686
|
ExitCode: () => ExitCode,
|
|
1677
1687
|
errorEnvelope: () => errorEnvelope,
|
|
1678
1688
|
escapeMarkdownInline: () => escapeMarkdownInline,
|
|
@@ -1763,6 +1773,7 @@ function formatStatus(state, format) {
|
|
|
1763
1773
|
activeLessons: state.activeLessonCount,
|
|
1764
1774
|
deprecatedLessons: state.deprecatedLessonCount,
|
|
1765
1775
|
handovers: state.handoverFilenames.length,
|
|
1776
|
+
isEmptyScaffold: state.isEmptyScaffold,
|
|
1766
1777
|
phases: phases.map((p) => ({
|
|
1767
1778
|
id: p.phase.id,
|
|
1768
1779
|
name: p.phase.name,
|
|
@@ -1790,6 +1801,13 @@ function formatStatus(state, format) {
|
|
|
1790
1801
|
const summary = p.phase.summary ?? truncate(p.phase.description, 80);
|
|
1791
1802
|
lines.push(`${indicator} **${escapeMarkdownInline(p.phase.name)}** (${p.leafCount} tickets) \u2014 ${escapeMarkdownInline(summary)}`);
|
|
1792
1803
|
}
|
|
1804
|
+
if (state.isEmptyScaffold) {
|
|
1805
|
+
lines.push("");
|
|
1806
|
+
lines.push(EMPTY_SCAFFOLD_HEADING);
|
|
1807
|
+
lines.push("");
|
|
1808
|
+
lines.push("This project has been initialized but has no tickets, issues, or handovers yet.");
|
|
1809
|
+
lines.push("Run the /story setup flow to analyze your project and create an initial roadmap.");
|
|
1810
|
+
}
|
|
1793
1811
|
return lines.join("\n");
|
|
1794
1812
|
}
|
|
1795
1813
|
function formatPhaseList(state, format) {
|
|
@@ -2629,11 +2647,14 @@ function formatReference(commands, mcpTools, format) {
|
|
|
2629
2647
|
lines.push("- **/story not available:** Run `claudestory setup-skill` to install the skill");
|
|
2630
2648
|
return lines.join("\n");
|
|
2631
2649
|
}
|
|
2632
|
-
function formatRecommendations(result, format) {
|
|
2650
|
+
function formatRecommendations(result, state, format) {
|
|
2633
2651
|
if (format === "json") {
|
|
2634
|
-
return JSON.stringify(successEnvelope(result), null, 2);
|
|
2652
|
+
return JSON.stringify(successEnvelope({ ...result, isEmptyScaffold: state.isEmptyScaffold }), null, 2);
|
|
2635
2653
|
}
|
|
2636
2654
|
if (result.recommendations.length === 0) {
|
|
2655
|
+
if (state.isEmptyScaffold) {
|
|
2656
|
+
return "No recommendations yet \u2014 this project needs tickets and phases. Run the /story setup flow to get started.";
|
|
2657
|
+
}
|
|
2637
2658
|
return "No recommendations \u2014 all work is complete or blocked.";
|
|
2638
2659
|
}
|
|
2639
2660
|
const lines = ["# Recommendations", ""];
|
|
@@ -2652,12 +2673,13 @@ function formatRecommendations(result, format) {
|
|
|
2652
2673
|
}
|
|
2653
2674
|
return lines.join("\n");
|
|
2654
2675
|
}
|
|
2655
|
-
var ExitCode;
|
|
2676
|
+
var EMPTY_SCAFFOLD_HEADING, ExitCode;
|
|
2656
2677
|
var init_output_formatter = __esm({
|
|
2657
2678
|
"src/core/output-formatter.ts"() {
|
|
2658
2679
|
"use strict";
|
|
2659
2680
|
init_esm_shims();
|
|
2660
2681
|
init_queries();
|
|
2682
|
+
EMPTY_SCAFFOLD_HEADING = "## Getting Started";
|
|
2661
2683
|
ExitCode = {
|
|
2662
2684
|
OK: 0,
|
|
2663
2685
|
USER_ERROR: 1,
|
|
@@ -4667,7 +4689,7 @@ var init_recommend = __esm({
|
|
|
4667
4689
|
// src/cli/commands/recommend.ts
|
|
4668
4690
|
function handleRecommend(ctx, count) {
|
|
4669
4691
|
const result = recommend(ctx.state, count);
|
|
4670
|
-
return { output: formatRecommendations(result, ctx.format) };
|
|
4692
|
+
return { output: formatRecommendations(result, ctx.state, ctx.format) };
|
|
4671
4693
|
}
|
|
4672
4694
|
var init_recommend2 = __esm({
|
|
4673
4695
|
"src/cli/commands/recommend.ts"() {
|
|
@@ -5153,11 +5175,11 @@ var init_session_types = __esm({
|
|
|
5153
5175
|
stealReason: z9.string().optional(),
|
|
5154
5176
|
// Recipe overrides (maxTicketsPerSession: 0 = no limit)
|
|
5155
5177
|
config: z9.object({
|
|
5156
|
-
maxTicketsPerSession: z9.number().min(0).default(
|
|
5157
|
-
handoverInterval: z9.number().min(0).default(
|
|
5178
|
+
maxTicketsPerSession: z9.number().min(0).default(5),
|
|
5179
|
+
handoverInterval: z9.number().min(0).default(3),
|
|
5158
5180
|
compactThreshold: z9.string().default("high"),
|
|
5159
5181
|
reviewBackends: z9.array(z9.string()).default(["codex", "agent"])
|
|
5160
|
-
}).default({ maxTicketsPerSession:
|
|
5182
|
+
}).default({ maxTicketsPerSession: 5, compactThreshold: "high", reviewBackends: ["codex", "agent"], handoverInterval: 3 }),
|
|
5161
5183
|
// T-123: Issue sweep tracking
|
|
5162
5184
|
issueSweepState: z9.object({
|
|
5163
5185
|
remaining: z9.array(z9.string()),
|
|
@@ -5278,10 +5300,10 @@ function createSession(root, recipe, workspaceId, configOverrides) {
|
|
|
5278
5300
|
startedAt: now,
|
|
5279
5301
|
guideCallCount: 0,
|
|
5280
5302
|
config: {
|
|
5281
|
-
maxTicketsPerSession: configOverrides?.maxTicketsPerSession ??
|
|
5303
|
+
maxTicketsPerSession: configOverrides?.maxTicketsPerSession ?? 5,
|
|
5282
5304
|
compactThreshold: configOverrides?.compactThreshold ?? "high",
|
|
5283
5305
|
reviewBackends: configOverrides?.reviewBackends ?? ["codex", "agent"],
|
|
5284
|
-
handoverInterval: configOverrides?.handoverInterval ??
|
|
5306
|
+
handoverInterval: configOverrides?.handoverInterval ?? 3
|
|
5285
5307
|
}
|
|
5286
5308
|
};
|
|
5287
5309
|
writeSessionSync(dir, state);
|
|
@@ -8253,7 +8275,7 @@ ${ticket.description}` : "",
|
|
|
8253
8275
|
});
|
|
8254
8276
|
const topCandidate = nextResult.kind === "found" ? nextResult.candidates[0] : null;
|
|
8255
8277
|
const maxTickets = updated.config.maxTicketsPerSession;
|
|
8256
|
-
const interval = updated.config.handoverInterval ??
|
|
8278
|
+
const interval = updated.config.handoverInterval ?? 3;
|
|
8257
8279
|
const sessionDesc = maxTickets > 0 ? `Work continuously until all tickets are done or you reach ${maxTickets} tickets.` : "Work continuously until all tickets are done.";
|
|
8258
8280
|
const checkpointDesc = interval > 0 ? ` A checkpoint handover will be saved every ${interval} tickets.` : "";
|
|
8259
8281
|
const instruction = [
|
|
@@ -10217,7 +10239,7 @@ var init_mcp = __esm({
|
|
|
10217
10239
|
init_init();
|
|
10218
10240
|
ENV_VAR2 = "CLAUDESTORY_PROJECT_ROOT";
|
|
10219
10241
|
CONFIG_PATH2 = ".story/config.json";
|
|
10220
|
-
version = "0.1.
|
|
10242
|
+
version = "0.1.30";
|
|
10221
10243
|
main().catch((err) => {
|
|
10222
10244
|
process.stderr.write(`Fatal: ${err instanceof Error ? err.message : String(err)}
|
|
10223
10245
|
`);
|
|
@@ -13495,7 +13517,7 @@ async function runCli() {
|
|
|
13495
13517
|
registerConfigCommand: registerConfigCommand2,
|
|
13496
13518
|
registerSessionCommand: registerSessionCommand2
|
|
13497
13519
|
} = await Promise.resolve().then(() => (init_register(), register_exports));
|
|
13498
|
-
const version2 = "0.1.
|
|
13520
|
+
const version2 = "0.1.30";
|
|
13499
13521
|
class HandledError extends Error {
|
|
13500
13522
|
constructor() {
|
|
13501
13523
|
super("HANDLED_ERROR");
|
package/dist/index.d.ts
CHANGED
|
@@ -561,6 +561,9 @@ declare class ProjectState {
|
|
|
561
561
|
*/
|
|
562
562
|
isBlocked(ticket: Ticket): boolean;
|
|
563
563
|
get blockedCount(): number;
|
|
564
|
+
/** True when the project has been initialized but not yet populated with tickets/issues/handovers. */
|
|
565
|
+
get isEmptyScaffold(): boolean;
|
|
566
|
+
private get isDefaultScaffoldPhases();
|
|
564
567
|
ticketByID(id: string): Ticket | undefined;
|
|
565
568
|
issueByID(id: string): Issue | undefined;
|
|
566
569
|
noteByID(id: string): Note | undefined;
|
|
@@ -1722,6 +1725,8 @@ declare function buildRecap(currentState: ProjectState, snapshotInfo: {
|
|
|
1722
1725
|
filename: string;
|
|
1723
1726
|
} | null): RecapResult;
|
|
1724
1727
|
|
|
1728
|
+
/** SKILL PROTOCOL: SKILL.md Step 2b matches this literal string. Do not change without updating SKILL.md. */
|
|
1729
|
+
declare const EMPTY_SCAFFOLD_HEADING = "## Getting Started";
|
|
1725
1730
|
declare const ExitCode: {
|
|
1726
1731
|
readonly OK: 0;
|
|
1727
1732
|
readonly USER_ERROR: 1;
|
|
@@ -1792,6 +1797,6 @@ declare function formatSnapshotResult(result: {
|
|
|
1792
1797
|
}, format: OutputFormat): string;
|
|
1793
1798
|
declare function formatRecap(recap: RecapResult, state: ProjectState, format: OutputFormat): string;
|
|
1794
1799
|
declare function formatExport(state: ProjectState, mode: "all" | "phase", phaseId: string | null, format: OutputFormat): string;
|
|
1795
|
-
declare function formatRecommendations(result: RecommendResult, format: OutputFormat): string;
|
|
1800
|
+
declare function formatRecommendations(result: RecommendResult, state: ProjectState, format: OutputFormat): string;
|
|
1796
1801
|
|
|
1797
|
-
export { type Blocker, BlockerSchema, CURRENT_SCHEMA_VERSION, type Config, ConfigSchema, DATE_REGEX, DateSchema, ERROR_CODES, type ErrorCode, type ErrorEnvelope, ExitCode, type ExitCodeValue, type Features, FeaturesSchema, INTEGRITY_WARNING_TYPES, ISSUE_ID_REGEX, ISSUE_SEVERITIES, ISSUE_STATUSES, type InitOptions, type InitResult, type Issue, IssueIdSchema, IssueSchema, type IssueSeverity, type IssueStatus, type LoadOptions, type LoadResult, type LoadWarning, type LoadWarningType, NOTE_ID_REGEX, NOTE_STATUSES, type NextTicketAllBlocked, type NextTicketAllComplete, type NextTicketEmpty, type NextTicketOutcome, type NextTicketResult, type Note, NoteIdSchema, NoteSchema, type NoteStatus, OUTPUT_FORMATS, type OutputFormat, type PartialEnvelope, type Phase, PhaseSchema, type PhaseStatus, type PhaseWithStatus, ProjectLoaderError, ProjectState, type RecapResult, type RecommendCategory, type RecommendItemKind, type RecommendResult, type Recommendation, type Roadmap, RoadmapSchema, type SnapshotDiff, type SnapshotV1, SnapshotV1Schema, type SuccessEnvelope, TICKET_ID_REGEX, TICKET_STATUSES, TICKET_TYPES, type Ticket, TicketIdSchema, TicketSchema, type TicketStatus, type TicketType, type UmbrellaProgress, type UnblockImpact, type ValidationFinding, type ValidationLevel, type ValidationResult, type WithProjectLockOptions, atomicWrite, blockedTickets, buildRecap, currentPhase, deleteIssue, deleteNote, deleteTicket, descendantLeaves, diffStates, discoverProjectRoot, errorEnvelope, escapeMarkdownInline, extractHandoverDate, fencedBlock, formatBlockedTickets, formatBlockerList, formatError, formatExport, formatHandoverContent, formatHandoverCreateResult, formatHandoverList, formatInitResult, formatIssue, formatIssueList, formatNextTicketOutcome, formatPhaseList, formatPhaseTickets, formatRecap, formatRecommendations, formatSnapshotResult, formatStatus, formatTicket, formatTicketList, formatValidation, guardPath, initProject, isBlockerCleared, listHandovers, loadLatestSnapshot, loadProject, mergeValidation, nextIssueID, nextNoteID, nextOrder, nextTicket, nextTicketID, nextTickets, partialEnvelope, phasesWithStatus, readHandover, recommend, runTransaction, runTransactionUnlocked, saveSnapshot, serializeJSON, sortKeysDeep, successEnvelope, ticketsUnblockedBy, umbrellaProgress, validateProject, withProjectLock, writeConfig, writeIssue, writeIssueUnlocked, writeNote, writeNoteUnlocked, writeRoadmap, writeRoadmapUnlocked, writeTicket, writeTicketUnlocked };
|
|
1802
|
+
export { type Blocker, BlockerSchema, CURRENT_SCHEMA_VERSION, type Config, ConfigSchema, DATE_REGEX, DateSchema, EMPTY_SCAFFOLD_HEADING, ERROR_CODES, type ErrorCode, type ErrorEnvelope, ExitCode, type ExitCodeValue, type Features, FeaturesSchema, INTEGRITY_WARNING_TYPES, ISSUE_ID_REGEX, ISSUE_SEVERITIES, ISSUE_STATUSES, type InitOptions, type InitResult, type Issue, IssueIdSchema, IssueSchema, type IssueSeverity, type IssueStatus, type LoadOptions, type LoadResult, type LoadWarning, type LoadWarningType, NOTE_ID_REGEX, NOTE_STATUSES, type NextTicketAllBlocked, type NextTicketAllComplete, type NextTicketEmpty, type NextTicketOutcome, type NextTicketResult, type Note, NoteIdSchema, NoteSchema, type NoteStatus, OUTPUT_FORMATS, type OutputFormat, type PartialEnvelope, type Phase, PhaseSchema, type PhaseStatus, type PhaseWithStatus, ProjectLoaderError, ProjectState, type RecapResult, type RecommendCategory, type RecommendItemKind, type RecommendResult, type Recommendation, type Roadmap, RoadmapSchema, type SnapshotDiff, type SnapshotV1, SnapshotV1Schema, type SuccessEnvelope, TICKET_ID_REGEX, TICKET_STATUSES, TICKET_TYPES, type Ticket, TicketIdSchema, TicketSchema, type TicketStatus, type TicketType, type UmbrellaProgress, type UnblockImpact, type ValidationFinding, type ValidationLevel, type ValidationResult, type WithProjectLockOptions, atomicWrite, blockedTickets, buildRecap, currentPhase, deleteIssue, deleteNote, deleteTicket, descendantLeaves, diffStates, discoverProjectRoot, errorEnvelope, escapeMarkdownInline, extractHandoverDate, fencedBlock, formatBlockedTickets, formatBlockerList, formatError, formatExport, formatHandoverContent, formatHandoverCreateResult, formatHandoverList, formatInitResult, formatIssue, formatIssueList, formatNextTicketOutcome, formatPhaseList, formatPhaseTickets, formatRecap, formatRecommendations, formatSnapshotResult, formatStatus, formatTicket, formatTicketList, formatValidation, guardPath, initProject, isBlockerCleared, listHandovers, loadLatestSnapshot, loadProject, mergeValidation, nextIssueID, nextNoteID, nextOrder, nextTicket, nextTicketID, nextTickets, partialEnvelope, phasesWithStatus, readHandover, recommend, runTransaction, runTransactionUnlocked, saveSnapshot, serializeJSON, sortKeysDeep, successEnvelope, ticketsUnblockedBy, umbrellaProgress, validateProject, withProjectLock, writeConfig, writeIssue, writeIssueUnlocked, writeNote, writeNoteUnlocked, writeRoadmap, writeRoadmapUnlocked, writeTicket, writeTicketUnlocked };
|
package/dist/index.js
CHANGED
|
@@ -326,6 +326,15 @@ var ProjectState = class _ProjectState {
|
|
|
326
326
|
get blockedCount() {
|
|
327
327
|
return this.leafTickets.filter((t) => t.status !== "complete" && this.isBlocked(t)).length;
|
|
328
328
|
}
|
|
329
|
+
/** True when the project has been initialized but not yet populated with tickets/issues/handovers. */
|
|
330
|
+
get isEmptyScaffold() {
|
|
331
|
+
return this.tickets.length === 0 && this.issues.length === 0 && this.handoverFilenames.length === 0 && this.isDefaultScaffoldPhases;
|
|
332
|
+
}
|
|
333
|
+
get isDefaultScaffoldPhases() {
|
|
334
|
+
const { phases } = this.roadmap;
|
|
335
|
+
if (phases.length === 0) return true;
|
|
336
|
+
return phases.length === 1 && phases[0].id === "p0";
|
|
337
|
+
}
|
|
329
338
|
ticketByID(id) {
|
|
330
339
|
return this.ticketsByID.get(id);
|
|
331
340
|
}
|
|
@@ -2289,6 +2298,7 @@ async function pruneSnapshots(dir) {
|
|
|
2289
2298
|
}
|
|
2290
2299
|
|
|
2291
2300
|
// src/core/output-formatter.ts
|
|
2301
|
+
var EMPTY_SCAFFOLD_HEADING = "## Getting Started";
|
|
2292
2302
|
var ExitCode = {
|
|
2293
2303
|
OK: 0,
|
|
2294
2304
|
USER_ERROR: 1,
|
|
@@ -2343,6 +2353,7 @@ function formatStatus(state, format) {
|
|
|
2343
2353
|
activeLessons: state.activeLessonCount,
|
|
2344
2354
|
deprecatedLessons: state.deprecatedLessonCount,
|
|
2345
2355
|
handovers: state.handoverFilenames.length,
|
|
2356
|
+
isEmptyScaffold: state.isEmptyScaffold,
|
|
2346
2357
|
phases: phases.map((p) => ({
|
|
2347
2358
|
id: p.phase.id,
|
|
2348
2359
|
name: p.phase.name,
|
|
@@ -2370,6 +2381,13 @@ function formatStatus(state, format) {
|
|
|
2370
2381
|
const summary = p.phase.summary ?? truncate(p.phase.description, 80);
|
|
2371
2382
|
lines.push(`${indicator} **${escapeMarkdownInline(p.phase.name)}** (${p.leafCount} tickets) \u2014 ${escapeMarkdownInline(summary)}`);
|
|
2372
2383
|
}
|
|
2384
|
+
if (state.isEmptyScaffold) {
|
|
2385
|
+
lines.push("");
|
|
2386
|
+
lines.push(EMPTY_SCAFFOLD_HEADING);
|
|
2387
|
+
lines.push("");
|
|
2388
|
+
lines.push("This project has been initialized but has no tickets, issues, or handovers yet.");
|
|
2389
|
+
lines.push("Run the /story setup flow to analyze your project and create an initial roadmap.");
|
|
2390
|
+
}
|
|
2373
2391
|
return lines.join("\n");
|
|
2374
2392
|
}
|
|
2375
2393
|
function formatPhaseList(state, format) {
|
|
@@ -2967,11 +2985,14 @@ function formatTicketOneLiner(t, state) {
|
|
|
2967
2985
|
const blocked = state.isBlocked(t) ? " [BLOCKED]" : "";
|
|
2968
2986
|
return `${status} ${t.id}: ${escapeMarkdownInline(t.title)}${blocked}`;
|
|
2969
2987
|
}
|
|
2970
|
-
function formatRecommendations(result, format) {
|
|
2988
|
+
function formatRecommendations(result, state, format) {
|
|
2971
2989
|
if (format === "json") {
|
|
2972
|
-
return JSON.stringify(successEnvelope(result), null, 2);
|
|
2990
|
+
return JSON.stringify(successEnvelope({ ...result, isEmptyScaffold: state.isEmptyScaffold }), null, 2);
|
|
2973
2991
|
}
|
|
2974
2992
|
if (result.recommendations.length === 0) {
|
|
2993
|
+
if (state.isEmptyScaffold) {
|
|
2994
|
+
return "No recommendations yet \u2014 this project needs tickets and phases. Run the /story setup flow to get started.";
|
|
2995
|
+
}
|
|
2975
2996
|
return "No recommendations \u2014 all work is complete or blocked.";
|
|
2976
2997
|
}
|
|
2977
2998
|
const lines = ["# Recommendations", ""];
|
|
@@ -2996,6 +3017,7 @@ export {
|
|
|
2996
3017
|
ConfigSchema,
|
|
2997
3018
|
DATE_REGEX,
|
|
2998
3019
|
DateSchema,
|
|
3020
|
+
EMPTY_SCAFFOLD_HEADING,
|
|
2999
3021
|
ERROR_CODES,
|
|
3000
3022
|
ExitCode,
|
|
3001
3023
|
FeaturesSchema,
|
package/dist/mcp.js
CHANGED
|
@@ -433,6 +433,15 @@ var init_project_state = __esm({
|
|
|
433
433
|
get blockedCount() {
|
|
434
434
|
return this.leafTickets.filter((t) => t.status !== "complete" && this.isBlocked(t)).length;
|
|
435
435
|
}
|
|
436
|
+
/** True when the project has been initialized but not yet populated with tickets/issues/handovers. */
|
|
437
|
+
get isEmptyScaffold() {
|
|
438
|
+
return this.tickets.length === 0 && this.issues.length === 0 && this.handoverFilenames.length === 0 && this.isDefaultScaffoldPhases;
|
|
439
|
+
}
|
|
440
|
+
get isDefaultScaffoldPhases() {
|
|
441
|
+
const { phases } = this.roadmap;
|
|
442
|
+
if (phases.length === 0) return true;
|
|
443
|
+
return phases.length === 1 && phases[0].id === "p0";
|
|
444
|
+
}
|
|
436
445
|
ticketByID(id) {
|
|
437
446
|
return this.ticketsByID.get(id);
|
|
438
447
|
}
|
|
@@ -1563,6 +1572,7 @@ function formatStatus(state, format) {
|
|
|
1563
1572
|
activeLessons: state.activeLessonCount,
|
|
1564
1573
|
deprecatedLessons: state.deprecatedLessonCount,
|
|
1565
1574
|
handovers: state.handoverFilenames.length,
|
|
1575
|
+
isEmptyScaffold: state.isEmptyScaffold,
|
|
1566
1576
|
phases: phases.map((p) => ({
|
|
1567
1577
|
id: p.phase.id,
|
|
1568
1578
|
name: p.phase.name,
|
|
@@ -1590,6 +1600,13 @@ function formatStatus(state, format) {
|
|
|
1590
1600
|
const summary = p.phase.summary ?? truncate(p.phase.description, 80);
|
|
1591
1601
|
lines.push(`${indicator} **${escapeMarkdownInline(p.phase.name)}** (${p.leafCount} tickets) \u2014 ${escapeMarkdownInline(summary)}`);
|
|
1592
1602
|
}
|
|
1603
|
+
if (state.isEmptyScaffold) {
|
|
1604
|
+
lines.push("");
|
|
1605
|
+
lines.push(EMPTY_SCAFFOLD_HEADING);
|
|
1606
|
+
lines.push("");
|
|
1607
|
+
lines.push("This project has been initialized but has no tickets, issues, or handovers yet.");
|
|
1608
|
+
lines.push("Run the /story setup flow to analyze your project and create an initial roadmap.");
|
|
1609
|
+
}
|
|
1593
1610
|
return lines.join("\n");
|
|
1594
1611
|
}
|
|
1595
1612
|
function formatPhaseList(state, format) {
|
|
@@ -2356,11 +2373,14 @@ function formatTicketOneLiner(t, state) {
|
|
|
2356
2373
|
const blocked = state.isBlocked(t) ? " [BLOCKED]" : "";
|
|
2357
2374
|
return `${status} ${t.id}: ${escapeMarkdownInline(t.title)}${blocked}`;
|
|
2358
2375
|
}
|
|
2359
|
-
function formatRecommendations(result, format) {
|
|
2376
|
+
function formatRecommendations(result, state, format) {
|
|
2360
2377
|
if (format === "json") {
|
|
2361
|
-
return JSON.stringify(successEnvelope(result), null, 2);
|
|
2378
|
+
return JSON.stringify(successEnvelope({ ...result, isEmptyScaffold: state.isEmptyScaffold }), null, 2);
|
|
2362
2379
|
}
|
|
2363
2380
|
if (result.recommendations.length === 0) {
|
|
2381
|
+
if (state.isEmptyScaffold) {
|
|
2382
|
+
return "No recommendations yet \u2014 this project needs tickets and phases. Run the /story setup flow to get started.";
|
|
2383
|
+
}
|
|
2364
2384
|
return "No recommendations \u2014 all work is complete or blocked.";
|
|
2365
2385
|
}
|
|
2366
2386
|
const lines = ["# Recommendations", ""];
|
|
@@ -2379,12 +2399,13 @@ function formatRecommendations(result, format) {
|
|
|
2379
2399
|
}
|
|
2380
2400
|
return lines.join("\n");
|
|
2381
2401
|
}
|
|
2382
|
-
var ExitCode;
|
|
2402
|
+
var EMPTY_SCAFFOLD_HEADING, ExitCode;
|
|
2383
2403
|
var init_output_formatter = __esm({
|
|
2384
2404
|
"src/core/output-formatter.ts"() {
|
|
2385
2405
|
"use strict";
|
|
2386
2406
|
init_esm_shims();
|
|
2387
2407
|
init_queries();
|
|
2408
|
+
EMPTY_SCAFFOLD_HEADING = "## Getting Started";
|
|
2388
2409
|
ExitCode = {
|
|
2389
2410
|
OK: 0,
|
|
2390
2411
|
USER_ERROR: 1,
|
|
@@ -3596,11 +3617,11 @@ var init_session_types = __esm({
|
|
|
3596
3617
|
stealReason: z9.string().optional(),
|
|
3597
3618
|
// Recipe overrides (maxTicketsPerSession: 0 = no limit)
|
|
3598
3619
|
config: z9.object({
|
|
3599
|
-
maxTicketsPerSession: z9.number().min(0).default(
|
|
3600
|
-
handoverInterval: z9.number().min(0).default(
|
|
3620
|
+
maxTicketsPerSession: z9.number().min(0).default(5),
|
|
3621
|
+
handoverInterval: z9.number().min(0).default(3),
|
|
3601
3622
|
compactThreshold: z9.string().default("high"),
|
|
3602
3623
|
reviewBackends: z9.array(z9.string()).default(["codex", "agent"])
|
|
3603
|
-
}).default({ maxTicketsPerSession:
|
|
3624
|
+
}).default({ maxTicketsPerSession: 5, compactThreshold: "high", reviewBackends: ["codex", "agent"], handoverInterval: 3 }),
|
|
3604
3625
|
// T-123: Issue sweep tracking
|
|
3605
3626
|
issueSweepState: z9.object({
|
|
3606
3627
|
remaining: z9.array(z9.string()),
|
|
@@ -3721,10 +3742,10 @@ function createSession(root, recipe, workspaceId, configOverrides) {
|
|
|
3721
3742
|
startedAt: now,
|
|
3722
3743
|
guideCallCount: 0,
|
|
3723
3744
|
config: {
|
|
3724
|
-
maxTicketsPerSession: configOverrides?.maxTicketsPerSession ??
|
|
3745
|
+
maxTicketsPerSession: configOverrides?.maxTicketsPerSession ?? 5,
|
|
3725
3746
|
compactThreshold: configOverrides?.compactThreshold ?? "high",
|
|
3726
3747
|
reviewBackends: configOverrides?.reviewBackends ?? ["codex", "agent"],
|
|
3727
|
-
handoverInterval: configOverrides?.handoverInterval ??
|
|
3748
|
+
handoverInterval: configOverrides?.handoverInterval ?? 3
|
|
3728
3749
|
}
|
|
3729
3750
|
};
|
|
3730
3751
|
writeSessionSync(dir, state);
|
|
@@ -4884,7 +4905,7 @@ function sortByPhaseAndOrder(tickets, phaseIndex) {
|
|
|
4884
4905
|
init_output_formatter();
|
|
4885
4906
|
function handleRecommend(ctx, count) {
|
|
4886
4907
|
const result = recommend(ctx.state, count);
|
|
4887
|
-
return { output: formatRecommendations(result, ctx.format) };
|
|
4908
|
+
return { output: formatRecommendations(result, ctx.state, ctx.format) };
|
|
4888
4909
|
}
|
|
4889
4910
|
|
|
4890
4911
|
// src/cli/commands/snapshot.ts
|
|
@@ -7734,7 +7755,7 @@ ${ticket.description}` : "",
|
|
|
7734
7755
|
});
|
|
7735
7756
|
const topCandidate = nextResult.kind === "found" ? nextResult.candidates[0] : null;
|
|
7736
7757
|
const maxTickets = updated.config.maxTicketsPerSession;
|
|
7737
|
-
const interval = updated.config.handoverInterval ??
|
|
7758
|
+
const interval = updated.config.handoverInterval ?? 3;
|
|
7738
7759
|
const sessionDesc = maxTickets > 0 ? `Work continuously until all tickets are done or you reach ${maxTickets} tickets.` : "Work continuously until all tickets are done.";
|
|
7739
7760
|
const checkpointDesc = interval > 0 ? ` A checkpoint handover will be saved every ${interval} tickets.` : "";
|
|
7740
7761
|
const instruction = [
|
|
@@ -9374,7 +9395,7 @@ async function ensureGitignoreEntries(gitignorePath, entries) {
|
|
|
9374
9395
|
// src/mcp/index.ts
|
|
9375
9396
|
var ENV_VAR2 = "CLAUDESTORY_PROJECT_ROOT";
|
|
9376
9397
|
var CONFIG_PATH2 = ".story/config.json";
|
|
9377
|
-
var version = "0.1.
|
|
9398
|
+
var version = "0.1.30";
|
|
9378
9399
|
function tryDiscoverRoot() {
|
|
9379
9400
|
const envRoot = process.env[ENV_VAR2];
|
|
9380
9401
|
if (envRoot) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anthropologies/claudestory",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.30",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"description": "Cross-session context persistence for AI coding projects. Tracks tickets, issues, roadmap, and handovers so every session builds on the last.",
|
|
6
6
|
"keywords": [
|
package/src/skill/SKILL.md
CHANGED
|
@@ -199,6 +199,14 @@ Call these in order:
|
|
|
199
199
|
5. **Lessons learned** — call `claudestory_lesson_digest` MCP tool
|
|
200
200
|
6. **Recent commits** — run `git log --oneline -10`
|
|
201
201
|
|
|
202
|
+
## Step 2b: Empty Scaffold Check
|
|
203
|
+
|
|
204
|
+
After `claudestory_status` returns, check in order:
|
|
205
|
+
|
|
206
|
+
1. **Integrity guard** — if the response starts with "Warning:" and contains "item(s) skipped due to data integrity issues", this is NOT an empty scaffold. Tell the user to run `claudestory validate`. Continue Step 2/3 normally.
|
|
207
|
+
2. **Scaffold detection** — check BOTH: output contains "## Getting Started" AND shows `Tickets: 0/0 complete` + `Handovers: 0`. If met AND the project has code indicators (git history, package manifest, source files), route to the AI-Assisted Setup Flow (section 1b above) instead of Step 3. Skip remaining Step 2 calls and Step 3.
|
|
208
|
+
3. **Empty without code** — if scaffold detected but no code indicators (truly empty directory), continue to Step 3 which will show: "Your project is set up but has no tickets yet. Would you like me to help you create your first phase and tickets?"
|
|
209
|
+
|
|
202
210
|
## Step 3: Present Summary
|
|
203
211
|
|
|
204
212
|
After loading context, present a concise summary:
|