@howaboua/opencode-roadmap-plugin 0.1.5 → 0.1.7

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.
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Tool for creating and appending to project roadmaps.
3
+ * Supports merge logic for adding new features/actions to existing roadmaps.
4
+ */
1
5
  import { tool } from "@opencode-ai/plugin";
2
6
  import { FileStorage, RoadmapValidator } from "../storage.js";
3
7
  import { loadDescription } from "../descriptions/index.js";
@@ -26,110 +30,110 @@ export async function createCreateRoadmapTool(directory) {
26
30
  },
27
31
  async execute(args) {
28
32
  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
33
  if (!args.features || args.features.length === 0) {
43
34
  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
35
  }
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.`);
36
+ return await storage.update(async (current) => {
37
+ const roadmap = current ?? { features: [] };
38
+ const isUpdate = current !== null;
39
+ const validationErrors = [];
40
+ // First pass: structural validation of input
41
+ for (const feature of args.features) {
42
+ if (!feature.actions || feature.actions.length === 0) {
43
+ throw new Error(`Feature "${feature.number}" must have at least one action. Each feature needs at least one action to be valid.`);
44
+ }
45
+ const titleError = RoadmapValidator.validateTitle(feature.title, "feature");
46
+ if (titleError)
47
+ validationErrors.push(titleError);
48
+ const descError = RoadmapValidator.validateDescription(feature.description, "feature");
49
+ if (descError)
50
+ validationErrors.push(descError);
51
+ for (const action of feature.actions) {
52
+ const actionTitleError = RoadmapValidator.validateTitle(action.description, "action");
53
+ if (actionTitleError)
54
+ validationErrors.push(actionTitleError);
55
+ }
50
56
  }
51
- const titleError = RoadmapValidator.validateTitle(feature.title, "feature");
52
- if (titleError)
53
- validationErrors.push(titleError);
54
- const descError = RoadmapValidator.validateDescription(feature.description, "feature");
55
- if (descError)
56
- validationErrors.push(descError);
57
- for (const action of feature.actions) {
58
- const actionTitleError = RoadmapValidator.validateTitle(action.description, "action");
59
- if (actionTitleError)
60
- validationErrors.push(actionTitleError);
57
+ // Validate sequence consistency of input (internal consistency)
58
+ const sequenceErrors = RoadmapValidator.validateFeatureSequence(args.features);
59
+ validationErrors.push(...sequenceErrors);
60
+ if (validationErrors.length > 0) {
61
+ const errorMessages = validationErrors.map((err) => err.message).join("\n");
62
+ throw new Error(`Validation errors:\n${errorMessages}\n\nPlease fix these issues and try again.`);
61
63
  }
62
- }
63
- // Validate sequence consistency of input (internal consistency)
64
- const sequenceErrors = 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,
64
+ // Merge Logic
65
+ for (const inputFeature of args.features) {
66
+ const existingFeature = roadmap.features.find((f) => f.number === inputFeature.number);
67
+ if (existingFeature) {
68
+ // Feature exists: Validate Immutability
69
+ if (existingFeature.title !== inputFeature.title ||
70
+ existingFeature.description !== inputFeature.description) {
71
+ const msg = await getErrorMessage("immutable_feature", {
72
+ id: inputFeature.number,
73
+ oldTitle: existingFeature.title,
74
+ oldDesc: existingFeature.description,
75
+ newTitle: inputFeature.title,
76
+ newDesc: inputFeature.description,
98
77
  });
99
- // Sort actions to ensure order
100
- existingFeature.actions.sort((a, b) => parseFloat(a.number) - parseFloat(b.number));
78
+ throw new Error(msg);
79
+ }
80
+ // Process Actions
81
+ for (const inputAction of inputFeature.actions) {
82
+ const existingAction = existingFeature.actions.find((a) => a.number === inputAction.number);
83
+ if (existingAction) {
84
+ // Action exists: skip (immutable)
85
+ continue;
86
+ }
87
+ else {
88
+ // New Action: Append
89
+ existingFeature.actions.push({
90
+ number: inputAction.number,
91
+ description: inputAction.description,
92
+ status: inputAction.status,
93
+ });
94
+ // Sort actions to ensure order
95
+ existingFeature.actions.sort((a, b) => parseFloat(a.number) - parseFloat(b.number));
96
+ }
101
97
  }
102
98
  }
99
+ else {
100
+ // New Feature: Append
101
+ roadmap.features.push({
102
+ number: inputFeature.number,
103
+ title: inputFeature.title,
104
+ description: inputFeature.description,
105
+ actions: inputFeature.actions.map((a) => ({
106
+ number: a.number,
107
+ description: a.description,
108
+ status: a.status,
109
+ })),
110
+ });
111
+ }
103
112
  }
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
- });
113
+ // Final Sort of Features
114
+ roadmap.features.sort((a, b) => parseInt(a.number) - parseInt(b.number));
115
+ // Safety check: ensure no feature ended up with zero actions after merge
116
+ for (const feature of roadmap.features) {
117
+ if (feature.actions.length === 0) {
118
+ throw new Error(`Feature "${feature.number}" has no actions. This indicates a merge error.`);
119
+ }
116
120
  }
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 = 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;
121
+ // Final Validation of the Merged Roadmap
122
+ const finalErrors = RoadmapValidator.validateFeatureSequence(roadmap.features);
123
+ if (finalErrors.length > 0) {
124
+ throw new Error(`Resulting roadmap would be invalid:\n${finalErrors.map((e) => e.message).join("\n")}`);
125
+ }
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 {
133
+ roadmap,
134
+ buildResult: () => summary,
135
+ };
136
+ });
133
137
  },
134
138
  });
135
139
  }
@@ -1,2 +1,6 @@
1
+ /**
2
+ * Tool for reading roadmap state, progress, and details.
3
+ * Supports filtering by feature or action number.
4
+ */
1
5
  import { type ToolDefinition } from "@opencode-ai/plugin";
2
6
  export declare function createReadRoadmapTool(directory: string): Promise<ToolDefinition>;
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Tool for reading roadmap state, progress, and details.
3
+ * Supports filtering by feature or action number.
4
+ */
1
5
  import { tool } from "@opencode-ai/plugin";
2
6
  import { FileStorage, RoadmapValidator } from "../storage.js";
3
7
  import { loadDescription } from "../descriptions/index.js";
@@ -1,2 +1,6 @@
1
+ /**
2
+ * Tool for updating action status and descriptions in a roadmap.
3
+ * Enforces forward-only status progression and archives when complete.
4
+ */
1
5
  import { type ToolDefinition } from "@opencode-ai/plugin";
2
6
  export declare function createUpdateRoadmapTool(directory: string): Promise<ToolDefinition>;
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Tool for updating action status and descriptions in a roadmap.
3
+ * Enforces forward-only status progression and archives when complete.
4
+ */
1
5
  import { tool } from "@opencode-ai/plugin";
2
6
  import { FileStorage, RoadmapValidator } from "../storage.js";
3
7
  import { loadDescription } from "../descriptions/index.js";
@@ -12,99 +16,103 @@ export async function createUpdateRoadmapTool(directory) {
12
16
  .optional()
13
17
  .describe("New action description (full overwrite). If not provided, only status is updated."),
14
18
  status: tool.schema
15
- .enum(["pending", "in_progress", "completed"])
19
+ .enum(["pending", "in_progress", "completed", "cancelled"])
16
20
  .optional()
17
- .describe("New action status - optional if only updating description"),
21
+ .describe("New action status. Flexible transitions allowed except from cancelled."),
18
22
  },
19
23
  async execute(args) {
20
24
  const storage = new FileStorage(directory);
21
- if (!(await storage.exists())) {
22
- throw new Error("Roadmap not found. Use CreateRoadmap to create one.");
23
- }
24
- const roadmap = await storage.read();
25
- if (!roadmap) {
26
- throw new Error("Roadmap file is corrupted. Please fix manually.");
27
- }
28
25
  const actionNumberError = RoadmapValidator.validateActionNumber(args.actionNumber);
29
26
  if (actionNumberError) {
30
27
  throw new Error(`${actionNumberError.message} Use ReadRoadmap to see valid action numbers.`);
31
28
  }
32
- let targetAction = null;
33
- let targetFeature = null;
34
- let actionFound = false;
35
- for (const feature of roadmap.features) {
36
- const action = feature.actions.find((a) => a.number === args.actionNumber);
37
- if (action) {
38
- targetAction = action;
39
- targetFeature = feature;
40
- actionFound = true;
41
- break;
29
+ return await storage.update((roadmap) => {
30
+ if (!roadmap) {
31
+ throw new Error("Roadmap not found. Use CreateRoadmap to create one.");
42
32
  }
43
- }
44
- if (!actionFound) {
45
- throw new Error(`Action "${args.actionNumber}" not found. Use ReadRoadmap to see valid action numbers.`);
46
- }
47
- // TypeScript: we know targetAction and targetFeature are not null here
48
- if (!targetAction || !targetFeature) {
49
- throw new Error("Internal error: target action not found.");
50
- }
51
- // Validate that at least one field is being updated
52
- if (args.description === undefined && args.status === undefined) {
53
- throw new Error("No changes specified. Please provide description and/or status.");
54
- }
55
- const oldStatus = targetAction.status;
56
- const oldDescription = targetAction.description;
57
- // Validate description if provided
58
- if (args.description !== undefined) {
59
- const descError = RoadmapValidator.validateDescription(args.description, "action");
60
- if (descError) {
61
- throw new Error(`${descError.message}`);
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
+ }
62
44
  }
63
- targetAction.description = args.description;
64
- }
65
- // Validate and update status if provided
66
- if (args.status !== undefined) {
67
- const statusTransitionError = RoadmapValidator.validateStatusProgression(targetAction.status, args.status);
68
- if (statusTransitionError) {
69
- throw new Error(`${statusTransitionError.message} Current status: "${targetAction.status}", requested: "${args.status}"`);
45
+ if (!actionFound) {
46
+ throw new Error(`Action "${args.actionNumber}" not found. Use ReadRoadmap to see valid action numbers.`);
70
47
  }
71
- targetAction.status = args.status;
72
- }
73
- await storage.write(roadmap);
74
- const changes = [];
75
- if (args.description !== undefined && oldDescription !== args.description) {
76
- changes.push(`description updated`);
77
- }
78
- if (args.status !== undefined && oldStatus !== args.status) {
79
- changes.push(`status: "${oldStatus}" "${args.status}"`);
80
- }
81
- // Check if all actions are completed
82
- let allCompleted = true;
83
- for (const feature of roadmap.features) {
84
- for (const action of feature.actions) {
85
- if (action.status !== "completed") {
86
- allCompleted = false;
87
- break;
48
+ if (!targetAction || !targetFeature) {
49
+ throw new Error("Internal error: target action not found.");
50
+ }
51
+ // Validate that at least one field is being updated
52
+ if (args.description === undefined && args.status === undefined) {
53
+ throw new Error("No changes specified. Please provide description and/or status.");
54
+ }
55
+ const oldStatus = targetAction.status;
56
+ const oldDescription = targetAction.description;
57
+ // Validate description if provided
58
+ if (args.description !== undefined) {
59
+ const descError = RoadmapValidator.validateDescription(args.description, "action");
60
+ if (descError) {
61
+ throw new Error(`${descError.message}`);
88
62
  }
63
+ targetAction.description = args.description;
89
64
  }
90
- if (!allCompleted)
91
- break;
92
- }
93
- let archiveMsg = "";
94
- if (allCompleted) {
95
- const archiveName = await storage.archive();
96
- archiveMsg = `\n\n🎉 All actions completed! Roadmap archived to "${archiveName}".`;
97
- }
98
- // Format feature context
99
- const featureCompleted = targetFeature.actions.filter((a) => a.status === "completed").length;
100
- const featureTotal = targetFeature.actions.length;
101
- let featureContext = `\n\nFeature ${targetFeature.number}: ${targetFeature.title} (${featureCompleted}/${featureTotal} complete)\n`;
102
- featureContext += `Description: ${targetFeature.description}\n`;
103
- for (const action of targetFeature.actions) {
104
- const statusIcon = action.status === "completed" ? "✓" : action.status === "in_progress" ? "→" : "○";
105
- featureContext += `${action.number} ${statusIcon} ${action.description} [${action.status}]\n`;
106
- }
107
- return `Updated action ${args.actionNumber} in feature "${targetFeature.title}": ${changes.join(", ")}${featureContext}${archiveMsg}`;
65
+ // Validate and update status if provided
66
+ if (args.status !== undefined) {
67
+ const statusTransitionError = RoadmapValidator.validateStatusProgression(targetAction.status, args.status);
68
+ if (statusTransitionError) {
69
+ throw new Error(`${statusTransitionError.message} Current status: "${targetAction.status}", requested: "${args.status}"`);
70
+ }
71
+ targetAction.status = args.status;
72
+ }
73
+ const changes = [];
74
+ if (args.description !== undefined && oldDescription !== args.description) {
75
+ changes.push("description updated");
76
+ }
77
+ if (args.status !== undefined && oldStatus !== args.status) {
78
+ changes.push(`status: "${oldStatus}" "${args.status}"`);
79
+ }
80
+ if (changes.length === 0) {
81
+ return {
82
+ roadmap,
83
+ buildResult: () => `Action ${args.actionNumber} unchanged. Provided values match current state.`,
84
+ };
85
+ }
86
+ // Check if all actions are completed
87
+ let allCompleted = true;
88
+ for (const feature of roadmap.features) {
89
+ for (const action of feature.actions) {
90
+ if (action.status !== "completed") {
91
+ allCompleted = false;
92
+ break;
93
+ }
94
+ }
95
+ if (!allCompleted)
96
+ break;
97
+ }
98
+ // Format feature context
99
+ const featureCompleted = targetFeature.actions.filter((a) => a.status === "completed").length;
100
+ const featureTotal = targetFeature.actions.length;
101
+ let featureContext = `\n\nFeature ${targetFeature.number}: ${targetFeature.title} (${featureCompleted}/${featureTotal} complete)\n`;
102
+ featureContext += `Description: ${targetFeature.description}\n`;
103
+ for (const action of targetFeature.actions) {
104
+ const statusIcon = action.status === "completed" ? "✓" : action.status === "in_progress" ? "→" : "○";
105
+ featureContext += `${action.number} ${statusIcon} ${action.description} [${action.status}]\n`;
106
+ }
107
+ return {
108
+ roadmap,
109
+ archive: allCompleted,
110
+ buildResult: (archiveName) => {
111
+ const archiveMsg = archiveName ? `\n\nAll actions completed! Roadmap archived to "${archiveName}".` : "";
112
+ return `Updated action ${args.actionNumber} in feature "${targetFeature.title}": ${changes.join(", ")}${featureContext}${archiveMsg}`;
113
+ },
114
+ };
115
+ });
108
116
  },
109
117
  });
110
118
  }
@@ -1,17 +1,17 @@
1
1
  import { z } from "zod";
2
- export declare const ActionStatus: z.ZodEnum<["pending", "in_progress", "completed"]>;
2
+ export declare const ActionStatus: z.ZodEnum<["pending", "in_progress", "completed", "cancelled"]>;
3
3
  export type ActionStatus = z.infer<typeof ActionStatus>;
4
4
  export declare const Action: z.ZodObject<{
5
5
  number: z.ZodString;
6
6
  description: z.ZodString;
7
- status: z.ZodEnum<["pending", "in_progress", "completed"]>;
7
+ status: z.ZodEnum<["pending", "in_progress", "completed", "cancelled"]>;
8
8
  }, "strip", z.ZodTypeAny, {
9
9
  number: string;
10
- status: "pending" | "in_progress" | "completed";
10
+ status: "pending" | "in_progress" | "completed" | "cancelled";
11
11
  description: string;
12
12
  }, {
13
13
  number: string;
14
- status: "pending" | "in_progress" | "completed";
14
+ status: "pending" | "in_progress" | "completed" | "cancelled";
15
15
  description: string;
16
16
  }>;
17
17
  export type Action = z.infer<typeof Action>;
@@ -22,14 +22,14 @@ export declare const Feature: z.ZodObject<{
22
22
  actions: z.ZodArray<z.ZodObject<{
23
23
  number: z.ZodString;
24
24
  description: z.ZodString;
25
- status: z.ZodEnum<["pending", "in_progress", "completed"]>;
25
+ status: z.ZodEnum<["pending", "in_progress", "completed", "cancelled"]>;
26
26
  }, "strip", z.ZodTypeAny, {
27
27
  number: string;
28
- status: "pending" | "in_progress" | "completed";
28
+ status: "pending" | "in_progress" | "completed" | "cancelled";
29
29
  description: string;
30
30
  }, {
31
31
  number: string;
32
- status: "pending" | "in_progress" | "completed";
32
+ status: "pending" | "in_progress" | "completed" | "cancelled";
33
33
  description: string;
34
34
  }>, "many">;
35
35
  }, "strip", z.ZodTypeAny, {
@@ -38,7 +38,7 @@ export declare const Feature: z.ZodObject<{
38
38
  title: string;
39
39
  actions: {
40
40
  number: string;
41
- status: "pending" | "in_progress" | "completed";
41
+ status: "pending" | "in_progress" | "completed" | "cancelled";
42
42
  description: string;
43
43
  }[];
44
44
  }, {
@@ -47,7 +47,7 @@ export declare const Feature: z.ZodObject<{
47
47
  title: string;
48
48
  actions: {
49
49
  number: string;
50
- status: "pending" | "in_progress" | "completed";
50
+ status: "pending" | "in_progress" | "completed" | "cancelled";
51
51
  description: string;
52
52
  }[];
53
53
  }>;
@@ -60,14 +60,14 @@ export declare const Roadmap: z.ZodObject<{
60
60
  actions: z.ZodArray<z.ZodObject<{
61
61
  number: z.ZodString;
62
62
  description: z.ZodString;
63
- status: z.ZodEnum<["pending", "in_progress", "completed"]>;
63
+ status: z.ZodEnum<["pending", "in_progress", "completed", "cancelled"]>;
64
64
  }, "strip", z.ZodTypeAny, {
65
65
  number: string;
66
- status: "pending" | "in_progress" | "completed";
66
+ status: "pending" | "in_progress" | "completed" | "cancelled";
67
67
  description: string;
68
68
  }, {
69
69
  number: string;
70
- status: "pending" | "in_progress" | "completed";
70
+ status: "pending" | "in_progress" | "completed" | "cancelled";
71
71
  description: string;
72
72
  }>, "many">;
73
73
  }, "strip", z.ZodTypeAny, {
@@ -76,7 +76,7 @@ export declare const Roadmap: z.ZodObject<{
76
76
  title: string;
77
77
  actions: {
78
78
  number: string;
79
- status: "pending" | "in_progress" | "completed";
79
+ status: "pending" | "in_progress" | "completed" | "cancelled";
80
80
  description: string;
81
81
  }[];
82
82
  }, {
@@ -85,7 +85,7 @@ export declare const Roadmap: z.ZodObject<{
85
85
  title: string;
86
86
  actions: {
87
87
  number: string;
88
- status: "pending" | "in_progress" | "completed";
88
+ status: "pending" | "in_progress" | "completed" | "cancelled";
89
89
  description: string;
90
90
  }[];
91
91
  }>, "many">;
@@ -96,7 +96,7 @@ export declare const Roadmap: z.ZodObject<{
96
96
  title: string;
97
97
  actions: {
98
98
  number: string;
99
- status: "pending" | "in_progress" | "completed";
99
+ status: "pending" | "in_progress" | "completed" | "cancelled";
100
100
  description: string;
101
101
  }[];
102
102
  }[];
@@ -107,7 +107,7 @@ export declare const Roadmap: z.ZodObject<{
107
107
  title: string;
108
108
  actions: {
109
109
  number: string;
110
- status: "pending" | "in_progress" | "completed";
110
+ status: "pending" | "in_progress" | "completed" | "cancelled";
111
111
  description: string;
112
112
  }[];
113
113
  }[];
package/dist/src/types.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- export const ActionStatus = z.enum(["pending", "in_progress", "completed"]);
2
+ export const ActionStatus = z.enum(["pending", "in_progress", "completed", "cancelled"]);
3
3
  export const Action = z.object({
4
4
  number: z
5
5
  .string()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@howaboua/opencode-roadmap-plugin",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Strategic roadmap planning and multi-agent coordination for OpenCode",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -32,7 +32,6 @@
32
32
  "typescript": "^5.0.0"
33
33
  },
34
34
  "dependencies": {
35
- "typescript": "^5.0.0",
36
35
  "zod": "^3.22.0"
37
36
  },
38
37
  "scripts": {
@@ -41,6 +40,9 @@
41
40
  "lint": "eslint . --ext .ts",
42
41
  "prepublishOnly": "npm run build"
43
42
  },
43
+ "publishConfig": {
44
+ "access": "public"
45
+ },
44
46
  "opencode": {
45
47
  "type": "plugin",
46
48
  "tools": [
@@ -1 +0,0 @@
1
- export { loadDescription } from "./loader";
@@ -1 +0,0 @@
1
- export { loadDescription } from "./loader.js";
@@ -1 +0,0 @@
1
- export declare function loadDescription(filename: string): Promise<string>;
@@ -1,17 +0,0 @@
1
- import { promises as fs } from "fs";
2
- import { join } from "path";
3
- export async function loadDescription(filename) {
4
- // In the compiled output, __dirname is .../dist/descriptions, but the assets are in .../src/descriptions.
5
- // This path adjustment ensures the assets are found regardless of the build process.
6
- const descriptionsDir = join(__dirname, "..", "..", "src", "descriptions");
7
- const filePath = join(descriptionsDir, filename);
8
- try {
9
- return await fs.readFile(filePath, "utf-8");
10
- }
11
- catch (error) {
12
- if (error.code === "ENOENT") {
13
- throw new Error(`Description file not found: ${filename}. Looked in: ${filePath}. Please ensure asset files are correctly located.`);
14
- }
15
- throw error;
16
- }
17
- }
@@ -1,2 +0,0 @@
1
- export declare function loadErrorTemplate(filename: string): Promise<string>;
2
- export declare function getErrorMessage(filename: string, params?: Record<string, string>): Promise<string>;
@@ -1,24 +0,0 @@
1
- import { promises as fs } from "fs";
2
- import { join } from "path";
3
- const ERROR_CACHE = {};
4
- export async function loadErrorTemplate(filename) {
5
- if (ERROR_CACHE[filename])
6
- return ERROR_CACHE[filename];
7
- const errorsDir = join(__dirname, "..", "..", "src", "errors");
8
- const filePath = join(errorsDir, filename + ".txt");
9
- try {
10
- const content = await fs.readFile(filePath, "utf-8");
11
- ERROR_CACHE[filename] = content.trim();
12
- return ERROR_CACHE[filename];
13
- }
14
- catch (error) {
15
- if (error.code === "ENOENT") {
16
- throw new Error(`Error template not found: ${filename} at ${filePath}`);
17
- }
18
- throw error;
19
- }
20
- }
21
- export async function getErrorMessage(filename, params = {}) {
22
- const template = await loadErrorTemplate(filename);
23
- return template.replace(/\{(\w+)\}/g, (_, key) => params[key] || `{${key}}`);
24
- }