@howaboua/opencode-roadmap-plugin 0.1.4 → 0.1.6
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 +85 -14
- package/dist/src/descriptions/createroadmap.txt +20 -16
- package/dist/src/descriptions/loader.js +11 -4
- package/dist/src/descriptions/readroadmap.txt +19 -2
- package/dist/src/descriptions/updateroadmap.txt +8 -6
- package/dist/src/errors/loader.js +11 -3
- package/dist/src/index.js +1 -1
- package/dist/src/storage.d.ts +13 -12
- package/dist/src/storage.js +83 -52
- package/dist/src/tools/createroadmap.d.ts +4 -0
- package/dist/src/tools/createroadmap.js +19 -8
- package/dist/src/tools/readroadmap.d.ts +4 -0
- package/dist/src/tools/readroadmap.js +8 -5
- package/dist/src/tools/updateroadmap.d.ts +4 -0
- package/dist/src/tools/updateroadmap.js +20 -10
- package/dist/src/types.d.ts +21 -21
- package/dist/src/types.js +1 -1
- package/package.json +10 -4
- package/dist/descriptions/index.d.ts +0 -1
- package/dist/descriptions/index.js +0 -1
- package/dist/descriptions/loader.d.ts +0 -1
- package/dist/descriptions/loader.js +0 -17
- package/dist/errors/loader.d.ts +0 -2
- package/dist/errors/loader.js +0 -24
- package/dist/storage.d.ts +0 -25
- package/dist/storage.js +0 -214
- package/dist/tools/createroadmap.d.ts +0 -2
- package/dist/tools/createroadmap.js +0 -135
- package/dist/tools/readroadmap.d.ts +0 -2
- package/dist/tools/readroadmap.js +0 -90
- package/dist/tools/updateroadmap.d.ts +0 -2
- package/dist/tools/updateroadmap.js +0 -107
- package/dist/types.d.ts +0 -151
- package/dist/types.js +0 -18
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { tool } from "@opencode-ai/plugin";
|
|
2
|
-
import { FileStorage, RoadmapValidator } from "../storage.js";
|
|
3
|
-
import { loadDescription } from "../descriptions/index.js";
|
|
4
|
-
import { getErrorMessage } from "../errors/loader.js";
|
|
5
|
-
export async function createCreateRoadmapTool(directory) {
|
|
6
|
-
const description = await loadDescription("createroadmap.txt");
|
|
7
|
-
return tool({
|
|
8
|
-
description,
|
|
9
|
-
args: {
|
|
10
|
-
features: tool.schema
|
|
11
|
-
.array(tool.schema.object({
|
|
12
|
-
number: tool.schema.string().describe('Feature number as string ("1", "2", "3...")'),
|
|
13
|
-
title: tool.schema.string().describe("Feature title"),
|
|
14
|
-
description: tool.schema.string().describe("Brief description of what this feature accomplishes"),
|
|
15
|
-
actions: tool.schema
|
|
16
|
-
.array(tool.schema.object({
|
|
17
|
-
number: tool.schema
|
|
18
|
-
.string()
|
|
19
|
-
.describe('Action number as string with two decimals ("1.01", "1.02", etc.)'),
|
|
20
|
-
description: tool.schema.string().describe("Action description"),
|
|
21
|
-
status: tool.schema.enum(["pending"]).describe('Initial action status (must be "pending")'),
|
|
22
|
-
}))
|
|
23
|
-
.describe("List of actions for this feature in order"),
|
|
24
|
-
}))
|
|
25
|
-
.describe("Array of features for roadmap"),
|
|
26
|
-
},
|
|
27
|
-
async execute(args) {
|
|
28
|
-
const storage = new FileStorage(directory);
|
|
29
|
-
let roadmap;
|
|
30
|
-
let isUpdate = false;
|
|
31
|
-
if (await storage.exists()) {
|
|
32
|
-
const existing = await storage.read();
|
|
33
|
-
if (!existing) {
|
|
34
|
-
throw new Error("Existing roadmap file is corrupted. Please fix manually.");
|
|
35
|
-
}
|
|
36
|
-
roadmap = existing;
|
|
37
|
-
isUpdate = true;
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
roadmap = { features: [] };
|
|
41
|
-
}
|
|
42
|
-
if (!args.features || args.features.length === 0) {
|
|
43
|
-
throw new Error('Roadmap must have at least one feature with at least one action. Example: {"features": [{"number": "1", "title": "Feature 1", "description": "Description", "actions": [{"number": "1.01", "description": "Action 1", "status": "pending"}]}]}');
|
|
44
|
-
}
|
|
45
|
-
const validationErrors = [];
|
|
46
|
-
// First pass: structural validation of input
|
|
47
|
-
for (const feature of args.features) {
|
|
48
|
-
if (!feature.actions || feature.actions.length === 0) {
|
|
49
|
-
throw new Error(`Feature "${feature.number}" must have at least one action. Each feature needs at least one action to be valid.`);
|
|
50
|
-
}
|
|
51
|
-
const titleError = await RoadmapValidator.validateTitle(feature.title, "feature");
|
|
52
|
-
if (titleError)
|
|
53
|
-
validationErrors.push(titleError);
|
|
54
|
-
const descError = await RoadmapValidator.validateDescription(feature.description, "feature");
|
|
55
|
-
if (descError)
|
|
56
|
-
validationErrors.push(descError);
|
|
57
|
-
for (const action of feature.actions) {
|
|
58
|
-
const actionTitleError = await RoadmapValidator.validateTitle(action.description, "action");
|
|
59
|
-
if (actionTitleError)
|
|
60
|
-
validationErrors.push(actionTitleError);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
// Validate sequence consistency of input (internal consistency)
|
|
64
|
-
const sequenceErrors = await RoadmapValidator.validateFeatureSequence(args.features);
|
|
65
|
-
validationErrors.push(...sequenceErrors);
|
|
66
|
-
if (validationErrors.length > 0) {
|
|
67
|
-
const errorMessages = validationErrors.map((err) => err.message).join("\n");
|
|
68
|
-
throw new Error(`Validation errors:\n${errorMessages}\n\nPlease fix these issues and try again.`);
|
|
69
|
-
}
|
|
70
|
-
// Merge Logic
|
|
71
|
-
for (const inputFeature of args.features) {
|
|
72
|
-
const existingFeature = roadmap.features.find((f) => f.number === inputFeature.number);
|
|
73
|
-
if (existingFeature) {
|
|
74
|
-
// Feature exists: Validate Immutability
|
|
75
|
-
if (existingFeature.title !== inputFeature.title || existingFeature.description !== inputFeature.description) {
|
|
76
|
-
const msg = await getErrorMessage("immutable_feature", {
|
|
77
|
-
id: inputFeature.number,
|
|
78
|
-
oldTitle: existingFeature.title,
|
|
79
|
-
oldDesc: existingFeature.description,
|
|
80
|
-
newTitle: inputFeature.title,
|
|
81
|
-
newDesc: inputFeature.description
|
|
82
|
-
});
|
|
83
|
-
throw new Error(msg);
|
|
84
|
-
}
|
|
85
|
-
// Process Actions
|
|
86
|
-
for (const inputAction of inputFeature.actions) {
|
|
87
|
-
const existingAction = existingFeature.actions.find((a) => a.number === inputAction.number);
|
|
88
|
-
if (existingAction) {
|
|
89
|
-
// Action exists: skip (immutable)
|
|
90
|
-
continue;
|
|
91
|
-
}
|
|
92
|
-
else {
|
|
93
|
-
// New Action: Append
|
|
94
|
-
existingFeature.actions.push({
|
|
95
|
-
number: inputAction.number,
|
|
96
|
-
description: inputAction.description,
|
|
97
|
-
status: inputAction.status,
|
|
98
|
-
});
|
|
99
|
-
// Sort actions to ensure order
|
|
100
|
-
existingFeature.actions.sort((a, b) => parseFloat(a.number) - parseFloat(b.number));
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
// New Feature: Append
|
|
106
|
-
roadmap.features.push({
|
|
107
|
-
number: inputFeature.number,
|
|
108
|
-
title: inputFeature.title,
|
|
109
|
-
description: inputFeature.description,
|
|
110
|
-
actions: inputFeature.actions.map((a) => ({
|
|
111
|
-
number: a.number,
|
|
112
|
-
description: a.description,
|
|
113
|
-
status: a.status,
|
|
114
|
-
})),
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
// Final Sort of Features
|
|
119
|
-
roadmap.features.sort((a, b) => parseInt(a.number) - parseInt(b.number));
|
|
120
|
-
// Final Validation of the Merged Roadmap
|
|
121
|
-
const finalErrors = await RoadmapValidator.validateFeatureSequence(roadmap.features);
|
|
122
|
-
if (finalErrors.length > 0) {
|
|
123
|
-
throw new Error(`Resulting roadmap would be invalid:\n${finalErrors.map(e => e.message).join("\n")}`);
|
|
124
|
-
}
|
|
125
|
-
await storage.write(roadmap);
|
|
126
|
-
const totalActions = roadmap.features.reduce((sum, feature) => sum + feature.actions.length, 0);
|
|
127
|
-
const action = isUpdate ? "Updated" : "Created";
|
|
128
|
-
const summary = `${action} roadmap with ${roadmap.features.length} features and ${totalActions} actions:\n` +
|
|
129
|
-
roadmap.features
|
|
130
|
-
.map((feature) => ` Feature ${feature.number}: ${feature.title} (${feature.actions.length} actions)`)
|
|
131
|
-
.join("\n");
|
|
132
|
-
return summary;
|
|
133
|
-
},
|
|
134
|
-
});
|
|
135
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { tool } from "@opencode-ai/plugin";
|
|
2
|
-
import { FileStorage, RoadmapValidator } from "../storage.js";
|
|
3
|
-
import { loadDescription } from "../descriptions/index.js";
|
|
4
|
-
import { getErrorMessage } from "../errors/loader.js";
|
|
5
|
-
export async function createReadRoadmapTool(directory) {
|
|
6
|
-
const description = await loadDescription("readroadmap.txt");
|
|
7
|
-
return tool({
|
|
8
|
-
description,
|
|
9
|
-
args: {
|
|
10
|
-
actionNumber: tool.schema
|
|
11
|
-
.string()
|
|
12
|
-
.optional()
|
|
13
|
-
.describe('Specific action to read ("1.01", "1.02", etc.). If not provided, reads entire roadmap.'),
|
|
14
|
-
featureNumber: tool.schema
|
|
15
|
-
.string()
|
|
16
|
-
.optional()
|
|
17
|
-
.describe('Specific feature to read ("1", "2", etc.). Use only if not providing actionNumber.'),
|
|
18
|
-
},
|
|
19
|
-
async execute(args) {
|
|
20
|
-
const storage = new FileStorage(directory);
|
|
21
|
-
if (!(await storage.exists())) {
|
|
22
|
-
throw new Error(await getErrorMessage("roadmap_not_found"));
|
|
23
|
-
}
|
|
24
|
-
const roadmap = await storage.read();
|
|
25
|
-
if (!roadmap) {
|
|
26
|
-
throw new Error(await getErrorMessage("roadmap_corrupted"));
|
|
27
|
-
}
|
|
28
|
-
if (args.actionNumber && args.featureNumber) {
|
|
29
|
-
throw new Error("Cannot specify both actionNumber and featureNumber. Use one or the other, or neither for full roadmap.");
|
|
30
|
-
}
|
|
31
|
-
if (args.actionNumber) {
|
|
32
|
-
const actionNumberError = await RoadmapValidator.validateActionNumber(args.actionNumber);
|
|
33
|
-
if (actionNumberError) {
|
|
34
|
-
throw new Error(`${actionNumberError.message} Use ReadRoadmap to see valid action numbers.`);
|
|
35
|
-
}
|
|
36
|
-
for (const feature of roadmap.features) {
|
|
37
|
-
const action = feature.actions.find((a) => a.number === args.actionNumber);
|
|
38
|
-
if (action) {
|
|
39
|
-
return (`Action ${args.actionNumber} from Feature "${feature.title}":\n` +
|
|
40
|
-
`Description: ${action.description}\n` +
|
|
41
|
-
`Status: ${action.status}\n` +
|
|
42
|
-
`Feature: ${feature.number} - ${feature.title}\n` +
|
|
43
|
-
`Feature Description: ${feature.description}`);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
throw new Error(`Action "${args.actionNumber}" not found. Use ReadRoadmap with no arguments to see all available actions.`);
|
|
47
|
-
}
|
|
48
|
-
if (args.featureNumber) {
|
|
49
|
-
const featureNumberError = await RoadmapValidator.validateFeatureNumber(args.featureNumber);
|
|
50
|
-
if (featureNumberError) {
|
|
51
|
-
throw new Error(`${featureNumberError.message} Use ReadRoadmap to see valid feature numbers.`);
|
|
52
|
-
}
|
|
53
|
-
const feature = roadmap.features.find((f) => f.number === args.featureNumber);
|
|
54
|
-
if (!feature) {
|
|
55
|
-
throw new Error(`Feature "${args.featureNumber}" not found. Use ReadRoadmap with no arguments to see all available features.`);
|
|
56
|
-
}
|
|
57
|
-
const actionList = feature.actions
|
|
58
|
-
.map((action) => ` ${action.number}: ${action.description} [${action.status}]`)
|
|
59
|
-
.join("\n");
|
|
60
|
-
const completedCount = feature.actions.filter((a) => a.status === "completed").length;
|
|
61
|
-
const totalCount = feature.actions.length;
|
|
62
|
-
return (`Feature ${feature.number}: ${feature.title}\n` +
|
|
63
|
-
`Description: ${feature.description}\n` +
|
|
64
|
-
`Progress: ${completedCount}/${totalCount} actions completed\n` +
|
|
65
|
-
`Actions:\n${actionList}`);
|
|
66
|
-
}
|
|
67
|
-
const totalActions = roadmap.features.reduce((sum, feature) => sum + feature.actions.length, 0);
|
|
68
|
-
const completedActions = roadmap.features.reduce((sum, feature) => sum + feature.actions.filter((a) => a.status === "completed").length, 0);
|
|
69
|
-
const inProgressActions = roadmap.features.reduce((sum, feature) => sum + feature.actions.filter((a) => a.status === "in_progress").length, 0);
|
|
70
|
-
const pendingActions = totalActions - completedActions - inProgressActions;
|
|
71
|
-
let output = `Project Roadmap Overview\n` +
|
|
72
|
-
`========================\n` +
|
|
73
|
-
`Features: ${roadmap.features.length}\n` +
|
|
74
|
-
`Total Actions: ${totalActions}\n` +
|
|
75
|
-
`Progress: ${completedActions} completed, ${inProgressActions} in progress, ${pendingActions} pending\n\n`;
|
|
76
|
-
for (const feature of roadmap.features) {
|
|
77
|
-
const featureCompleted = feature.actions.filter((a) => a.status === "completed").length;
|
|
78
|
-
const featureTotal = feature.actions.length;
|
|
79
|
-
output += `Feature ${feature.number}: ${feature.title} (${featureCompleted}/${featureTotal} complete)\n`;
|
|
80
|
-
output += ` Description: ${feature.description}\n`;
|
|
81
|
-
for (const action of feature.actions) {
|
|
82
|
-
const statusIcon = action.status === "completed" ? "✓" : action.status === "in_progress" ? "→" : "○";
|
|
83
|
-
output += ` ${action.number} ${statusIcon} ${action.description} [${action.status}]\n`;
|
|
84
|
-
}
|
|
85
|
-
output += "\n";
|
|
86
|
-
}
|
|
87
|
-
return output.trim();
|
|
88
|
-
},
|
|
89
|
-
});
|
|
90
|
-
}
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { tool } from "@opencode-ai/plugin";
|
|
2
|
-
import { FileStorage, RoadmapValidator } from "../storage.js";
|
|
3
|
-
import { loadDescription } from "../descriptions/index.js";
|
|
4
|
-
import { getErrorMessage } from "../errors/loader.js";
|
|
5
|
-
export async function createUpdateRoadmapTool(directory) {
|
|
6
|
-
const description = await loadDescription("updateroadmap.txt");
|
|
7
|
-
return tool({
|
|
8
|
-
description,
|
|
9
|
-
args: {
|
|
10
|
-
actionNumber: tool.schema.string().describe('Action number to update ("1.01", "1.02", "2.01", etc.) - required'),
|
|
11
|
-
description: tool.schema
|
|
12
|
-
.string()
|
|
13
|
-
.optional()
|
|
14
|
-
.describe("New action description (full overwrite). If not provided, only status is updated."),
|
|
15
|
-
status: tool.schema
|
|
16
|
-
.enum(["pending", "in_progress", "completed"])
|
|
17
|
-
.optional()
|
|
18
|
-
.describe("New action status - optional if only updating description"),
|
|
19
|
-
},
|
|
20
|
-
async execute(args) {
|
|
21
|
-
const storage = new FileStorage(directory);
|
|
22
|
-
if (!(await storage.exists())) {
|
|
23
|
-
throw new Error(await getErrorMessage("roadmap_not_found"));
|
|
24
|
-
}
|
|
25
|
-
const roadmap = await storage.read();
|
|
26
|
-
if (!roadmap) {
|
|
27
|
-
throw new Error(await getErrorMessage("roadmap_corrupted"));
|
|
28
|
-
}
|
|
29
|
-
const actionNumberError = await RoadmapValidator.validateActionNumber(args.actionNumber);
|
|
30
|
-
if (actionNumberError) {
|
|
31
|
-
throw new Error(`${actionNumberError.message} Use ReadRoadmap to see valid action numbers.`);
|
|
32
|
-
}
|
|
33
|
-
let targetAction = null;
|
|
34
|
-
let targetFeature = null;
|
|
35
|
-
let actionFound = false;
|
|
36
|
-
for (const feature of roadmap.features) {
|
|
37
|
-
const action = feature.actions.find((a) => a.number === args.actionNumber);
|
|
38
|
-
if (action) {
|
|
39
|
-
targetAction = action;
|
|
40
|
-
targetFeature = feature;
|
|
41
|
-
actionFound = true;
|
|
42
|
-
break;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
if (!actionFound) {
|
|
46
|
-
throw new Error(await getErrorMessage("action_not_found", { id: args.actionNumber }));
|
|
47
|
-
}
|
|
48
|
-
// Validate that at least one field is being updated
|
|
49
|
-
if (args.description === undefined && args.status === undefined) {
|
|
50
|
-
throw new Error(await getErrorMessage("no_changes_specified"));
|
|
51
|
-
}
|
|
52
|
-
const oldStatus = targetAction.status;
|
|
53
|
-
const oldDescription = targetAction.description;
|
|
54
|
-
// Validate description if provided
|
|
55
|
-
if (args.description !== undefined) {
|
|
56
|
-
const descError = await RoadmapValidator.validateDescription(args.description, "action");
|
|
57
|
-
if (descError) {
|
|
58
|
-
throw new Error(`${descError.message}`);
|
|
59
|
-
}
|
|
60
|
-
targetAction.description = args.description;
|
|
61
|
-
}
|
|
62
|
-
// Validate and update status if provided
|
|
63
|
-
if (args.status !== undefined) {
|
|
64
|
-
const statusTransitionError = await RoadmapValidator.validateStatusProgression(targetAction.status, args.status);
|
|
65
|
-
if (statusTransitionError) {
|
|
66
|
-
throw new Error(`${statusTransitionError.message} Current status: "${targetAction.status}", requested: "${args.status}"`);
|
|
67
|
-
}
|
|
68
|
-
targetAction.status = args.status;
|
|
69
|
-
}
|
|
70
|
-
await storage.write(roadmap);
|
|
71
|
-
const changes = [];
|
|
72
|
-
if (args.description !== undefined && oldDescription !== args.description) {
|
|
73
|
-
changes.push(`description updated`);
|
|
74
|
-
}
|
|
75
|
-
if (args.status !== undefined && oldStatus !== args.status) {
|
|
76
|
-
changes.push(`status: "${oldStatus}" → "${args.status}"`);
|
|
77
|
-
}
|
|
78
|
-
// Check if all actions are completed
|
|
79
|
-
let allCompleted = true;
|
|
80
|
-
for (const feature of roadmap.features) {
|
|
81
|
-
for (const action of feature.actions) {
|
|
82
|
-
if (action.status !== "completed") {
|
|
83
|
-
allCompleted = false;
|
|
84
|
-
break;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
if (!allCompleted)
|
|
88
|
-
break;
|
|
89
|
-
}
|
|
90
|
-
let archiveMsg = "";
|
|
91
|
-
if (allCompleted) {
|
|
92
|
-
const archiveName = await storage.archive();
|
|
93
|
-
archiveMsg = `\n\n🎉 All actions completed! Roadmap archived to "${archiveName}".`;
|
|
94
|
-
}
|
|
95
|
-
// Format feature context
|
|
96
|
-
const featureCompleted = targetFeature.actions.filter((a) => a.status === "completed").length;
|
|
97
|
-
const featureTotal = targetFeature.actions.length;
|
|
98
|
-
let featureContext = `\n\nFeature ${targetFeature.number}: ${targetFeature.title} (${featureCompleted}/${featureTotal} complete)\n`;
|
|
99
|
-
featureContext += `Description: ${targetFeature.description}\n`;
|
|
100
|
-
for (const action of targetFeature.actions) {
|
|
101
|
-
const statusIcon = action.status === "completed" ? "✓" : action.status === "in_progress" ? "→" : "○";
|
|
102
|
-
featureContext += `${action.number} ${statusIcon} ${action.description} [${action.status}]\n`;
|
|
103
|
-
}
|
|
104
|
-
return `Updated action ${args.actionNumber} in feature "${targetFeature.title}": ${changes.join(", ")}${featureContext}${archiveMsg}`;
|
|
105
|
-
},
|
|
106
|
-
});
|
|
107
|
-
}
|
package/dist/types.d.ts
DELETED
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
export declare const ActionStatus: z.ZodEnum<["pending", "in_progress", "completed"]>;
|
|
3
|
-
export type ActionStatus = z.infer<typeof ActionStatus>;
|
|
4
|
-
export declare const Action: z.ZodObject<{
|
|
5
|
-
number: z.ZodString;
|
|
6
|
-
description: z.ZodString;
|
|
7
|
-
status: z.ZodEnum<["pending", "in_progress", "completed"]>;
|
|
8
|
-
}, "strip", z.ZodTypeAny, {
|
|
9
|
-
number: string;
|
|
10
|
-
status: "pending" | "in_progress" | "completed";
|
|
11
|
-
description: string;
|
|
12
|
-
}, {
|
|
13
|
-
number: string;
|
|
14
|
-
status: "pending" | "in_progress" | "completed";
|
|
15
|
-
description: string;
|
|
16
|
-
}>;
|
|
17
|
-
export type Action = z.infer<typeof Action>;
|
|
18
|
-
export declare const Feature: z.ZodObject<{
|
|
19
|
-
number: z.ZodString;
|
|
20
|
-
title: z.ZodString;
|
|
21
|
-
description: z.ZodString;
|
|
22
|
-
actions: z.ZodArray<z.ZodObject<{
|
|
23
|
-
number: z.ZodString;
|
|
24
|
-
description: z.ZodString;
|
|
25
|
-
status: z.ZodEnum<["pending", "in_progress", "completed"]>;
|
|
26
|
-
}, "strip", z.ZodTypeAny, {
|
|
27
|
-
number: string;
|
|
28
|
-
status: "pending" | "in_progress" | "completed";
|
|
29
|
-
description: string;
|
|
30
|
-
}, {
|
|
31
|
-
number: string;
|
|
32
|
-
status: "pending" | "in_progress" | "completed";
|
|
33
|
-
description: string;
|
|
34
|
-
}>, "many">;
|
|
35
|
-
}, "strip", z.ZodTypeAny, {
|
|
36
|
-
number: string;
|
|
37
|
-
description: string;
|
|
38
|
-
title: string;
|
|
39
|
-
actions: {
|
|
40
|
-
number: string;
|
|
41
|
-
status: "pending" | "in_progress" | "completed";
|
|
42
|
-
description: string;
|
|
43
|
-
}[];
|
|
44
|
-
}, {
|
|
45
|
-
number: string;
|
|
46
|
-
description: string;
|
|
47
|
-
title: string;
|
|
48
|
-
actions: {
|
|
49
|
-
number: string;
|
|
50
|
-
status: "pending" | "in_progress" | "completed";
|
|
51
|
-
description: string;
|
|
52
|
-
}[];
|
|
53
|
-
}>;
|
|
54
|
-
export type Feature = z.infer<typeof Feature>;
|
|
55
|
-
export declare const Roadmap: z.ZodObject<{
|
|
56
|
-
features: z.ZodArray<z.ZodObject<{
|
|
57
|
-
number: z.ZodString;
|
|
58
|
-
title: z.ZodString;
|
|
59
|
-
description: z.ZodString;
|
|
60
|
-
actions: z.ZodArray<z.ZodObject<{
|
|
61
|
-
number: z.ZodString;
|
|
62
|
-
description: z.ZodString;
|
|
63
|
-
status: z.ZodEnum<["pending", "in_progress", "completed"]>;
|
|
64
|
-
}, "strip", z.ZodTypeAny, {
|
|
65
|
-
number: string;
|
|
66
|
-
status: "pending" | "in_progress" | "completed";
|
|
67
|
-
description: string;
|
|
68
|
-
}, {
|
|
69
|
-
number: string;
|
|
70
|
-
status: "pending" | "in_progress" | "completed";
|
|
71
|
-
description: string;
|
|
72
|
-
}>, "many">;
|
|
73
|
-
}, "strip", z.ZodTypeAny, {
|
|
74
|
-
number: string;
|
|
75
|
-
description: string;
|
|
76
|
-
title: string;
|
|
77
|
-
actions: {
|
|
78
|
-
number: string;
|
|
79
|
-
status: "pending" | "in_progress" | "completed";
|
|
80
|
-
description: string;
|
|
81
|
-
}[];
|
|
82
|
-
}, {
|
|
83
|
-
number: string;
|
|
84
|
-
description: string;
|
|
85
|
-
title: string;
|
|
86
|
-
actions: {
|
|
87
|
-
number: string;
|
|
88
|
-
status: "pending" | "in_progress" | "completed";
|
|
89
|
-
description: string;
|
|
90
|
-
}[];
|
|
91
|
-
}>, "many">;
|
|
92
|
-
}, "strip", z.ZodTypeAny, {
|
|
93
|
-
features: {
|
|
94
|
-
number: string;
|
|
95
|
-
description: string;
|
|
96
|
-
title: string;
|
|
97
|
-
actions: {
|
|
98
|
-
number: string;
|
|
99
|
-
status: "pending" | "in_progress" | "completed";
|
|
100
|
-
description: string;
|
|
101
|
-
}[];
|
|
102
|
-
}[];
|
|
103
|
-
}, {
|
|
104
|
-
features: {
|
|
105
|
-
number: string;
|
|
106
|
-
description: string;
|
|
107
|
-
title: string;
|
|
108
|
-
actions: {
|
|
109
|
-
number: string;
|
|
110
|
-
status: "pending" | "in_progress" | "completed";
|
|
111
|
-
description: string;
|
|
112
|
-
}[];
|
|
113
|
-
}[];
|
|
114
|
-
}>;
|
|
115
|
-
export type Roadmap = z.infer<typeof Roadmap>;
|
|
116
|
-
export interface RoadmapStorage {
|
|
117
|
-
read(): Promise<Roadmap | null>;
|
|
118
|
-
write(roadmap: Roadmap): Promise<void>;
|
|
119
|
-
exists(): Promise<boolean>;
|
|
120
|
-
archive(): Promise<string>;
|
|
121
|
-
}
|
|
122
|
-
export interface ValidationError {
|
|
123
|
-
code: string;
|
|
124
|
-
message: string;
|
|
125
|
-
tutorial?: string;
|
|
126
|
-
}
|
|
127
|
-
export interface ValidationResult {
|
|
128
|
-
isValid: boolean;
|
|
129
|
-
errors: ValidationError[];
|
|
130
|
-
}
|
|
131
|
-
export interface CreateRoadmapInput {
|
|
132
|
-
features: Array<{
|
|
133
|
-
number: string;
|
|
134
|
-
title: string;
|
|
135
|
-
description: string;
|
|
136
|
-
actions: Array<{
|
|
137
|
-
number: string;
|
|
138
|
-
description: string;
|
|
139
|
-
status: "pending";
|
|
140
|
-
}>;
|
|
141
|
-
}>;
|
|
142
|
-
}
|
|
143
|
-
export interface UpdateRoadmapInput {
|
|
144
|
-
actionNumber: string;
|
|
145
|
-
description?: string;
|
|
146
|
-
status: ActionStatus;
|
|
147
|
-
}
|
|
148
|
-
export interface ReadRoadmapInput {
|
|
149
|
-
actionNumber?: string;
|
|
150
|
-
featureNumber?: string;
|
|
151
|
-
}
|
package/dist/types.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
export const ActionStatus = z.enum(["pending", "in_progress", "completed"]);
|
|
3
|
-
export const Action = z.object({
|
|
4
|
-
number: z
|
|
5
|
-
.string()
|
|
6
|
-
.describe('Action number as string with two decimals ("1.01", "1.02", etc.) - canonical ID, never changes'),
|
|
7
|
-
description: z.string().describe("Action description - MUTABLE (overwrite only)"),
|
|
8
|
-
status: ActionStatus.describe("Current status of this action - MUTABLE"),
|
|
9
|
-
});
|
|
10
|
-
export const Feature = z.object({
|
|
11
|
-
number: z.string().describe('Feature number as string ("1", "2", "3...") - canonical ID, never changes'),
|
|
12
|
-
title: z.string().describe("Feature title"),
|
|
13
|
-
description: z.string().describe("Brief description of what this feature accomplishes"),
|
|
14
|
-
actions: z.array(Action).describe("Array of actions for this feature"),
|
|
15
|
-
});
|
|
16
|
-
export const Roadmap = z.object({
|
|
17
|
-
features: z.array(Feature).describe("Array of features in the roadmap"),
|
|
18
|
-
});
|