@snipcodeit/mgw 0.1.0
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/LICENSE +21 -0
- package/README.md +517 -0
- package/bin/mgw-install.cjs +81 -0
- package/commands/ask.md +416 -0
- package/commands/assign.md +333 -0
- package/commands/board.md +1679 -0
- package/commands/help.md +119 -0
- package/commands/init.md +250 -0
- package/commands/issue.md +469 -0
- package/commands/issues.md +109 -0
- package/commands/link.md +122 -0
- package/commands/milestone.md +952 -0
- package/commands/next.md +375 -0
- package/commands/pr.md +277 -0
- package/commands/project.md +1801 -0
- package/commands/review.md +260 -0
- package/commands/roadmap.md +489 -0
- package/commands/run.md +1282 -0
- package/commands/status.md +526 -0
- package/commands/sync.md +243 -0
- package/commands/update.md +282 -0
- package/commands/workflows/board-sync.md +404 -0
- package/commands/workflows/github.md +385 -0
- package/commands/workflows/gsd.md +377 -0
- package/commands/workflows/state.md +412 -0
- package/commands/workflows/validation.md +144 -0
- package/dist/bin/mgw.cjs +291 -0
- package/dist/claude-Vp9qvImH.cjs +466 -0
- package/dist/lib/index.cjs +395 -0
- package/package.json +51 -0
- package/templates/schema.json +164 -0
- package/templates/vision-brief-schema.json +98 -0
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var claude = require('../claude-Vp9qvImH.cjs');
|
|
4
|
+
var require$$0 = require('child_process');
|
|
5
|
+
var require$$1 = require('path');
|
|
6
|
+
var require$$2 = require('os');
|
|
7
|
+
var require$$0$1 = require('fs');
|
|
8
|
+
|
|
9
|
+
var gsd;
|
|
10
|
+
var hasRequiredGsd;
|
|
11
|
+
|
|
12
|
+
function requireGsd () {
|
|
13
|
+
if (hasRequiredGsd) return gsd;
|
|
14
|
+
hasRequiredGsd = 1;
|
|
15
|
+
const { execSync } = require$$0;
|
|
16
|
+
const path = require$$1;
|
|
17
|
+
const os = require$$2;
|
|
18
|
+
function getGsdToolsPath() {
|
|
19
|
+
const standard = path.join(os.homedir(), ".claude", "get-shit-done", "bin", "gsd-tools.cjs");
|
|
20
|
+
const fs = require$$0$1;
|
|
21
|
+
if (fs.existsSync(standard)) {
|
|
22
|
+
return standard;
|
|
23
|
+
}
|
|
24
|
+
throw new Error(
|
|
25
|
+
`GSD tools not found at ${standard}.
|
|
26
|
+
Ensure the get-shit-done framework is installed at ~/.claude/get-shit-done/`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
function invokeGsdTool(command, args) {
|
|
30
|
+
const toolPath = getGsdToolsPath();
|
|
31
|
+
const argsStr = Array.isArray(args) ? args.map((a) => JSON.stringify(String(a))).join(" ") : "";
|
|
32
|
+
const cmd = `node ${JSON.stringify(toolPath)} ${command}${argsStr ? " " + argsStr : ""}`;
|
|
33
|
+
let raw;
|
|
34
|
+
try {
|
|
35
|
+
raw = execSync(cmd, {
|
|
36
|
+
encoding: "utf-8",
|
|
37
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
38
|
+
}).trim();
|
|
39
|
+
} catch (err) {
|
|
40
|
+
const stderr = err.stderr ? err.stderr.trim() : "";
|
|
41
|
+
throw new Error(
|
|
42
|
+
`GSD tool command failed: ${command}
|
|
43
|
+
` + (stderr ? `stderr: ${stderr}` : `exit code: ${err.status}`)
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
if (!raw) return null;
|
|
47
|
+
try {
|
|
48
|
+
return JSON.parse(raw);
|
|
49
|
+
} catch {
|
|
50
|
+
return raw;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
gsd = {
|
|
54
|
+
getGsdToolsPath,
|
|
55
|
+
invokeGsdTool
|
|
56
|
+
};
|
|
57
|
+
return gsd;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
var templateLoader = {exports: {}};
|
|
61
|
+
|
|
62
|
+
var hasRequiredTemplateLoader;
|
|
63
|
+
|
|
64
|
+
function requireTemplateLoader () {
|
|
65
|
+
if (hasRequiredTemplateLoader) return templateLoader.exports;
|
|
66
|
+
hasRequiredTemplateLoader = 1;
|
|
67
|
+
(function (module) {
|
|
68
|
+
const fs = require$$0$1;
|
|
69
|
+
const path = require$$1;
|
|
70
|
+
const VALID_GSD_ROUTES = [
|
|
71
|
+
"quick",
|
|
72
|
+
"plan-phase",
|
|
73
|
+
"discuss-phase",
|
|
74
|
+
"research-phase",
|
|
75
|
+
"execute-phase",
|
|
76
|
+
"verify-phase",
|
|
77
|
+
"new-project",
|
|
78
|
+
"new-milestone",
|
|
79
|
+
"complete-milestone",
|
|
80
|
+
"debug",
|
|
81
|
+
"diagnose-issues"
|
|
82
|
+
];
|
|
83
|
+
function getTemplatesDir() {
|
|
84
|
+
let dir = path.join(__dirname, "..", "templates");
|
|
85
|
+
if (fs.existsSync(dir)) return dir;
|
|
86
|
+
dir = path.join(__dirname, "..", "..", "templates");
|
|
87
|
+
if (fs.existsSync(dir)) return dir;
|
|
88
|
+
throw new Error(
|
|
89
|
+
`Templates directory not found.
|
|
90
|
+
Checked: ` + path.join(__dirname, "..", "templates") + "\nChecked: " + path.join(__dirname, "..", "..", "templates")
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
function getSchema() {
|
|
94
|
+
const schemaPath = path.join(getTemplatesDir(), "schema.json");
|
|
95
|
+
return fs.readFileSync(schemaPath, "utf-8");
|
|
96
|
+
}
|
|
97
|
+
function validate(output) {
|
|
98
|
+
const errors = [];
|
|
99
|
+
if (!output.type || typeof output.type !== "string" || output.type.trim() === "") {
|
|
100
|
+
errors.push({
|
|
101
|
+
field: "type",
|
|
102
|
+
error: `Missing or empty type field: ${output.type}`,
|
|
103
|
+
suggestion: 'Provide a descriptive type string (e.g. "game", "mobile-app", "api-service", "data-pipeline")'
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
if (!output.project) {
|
|
107
|
+
errors.push({
|
|
108
|
+
field: "project",
|
|
109
|
+
error: "Missing project metadata",
|
|
110
|
+
suggestion: "Output must include a project object with name and description"
|
|
111
|
+
});
|
|
112
|
+
} else {
|
|
113
|
+
if (!output.project.name || String(output.project.name).trim() === "") {
|
|
114
|
+
errors.push({
|
|
115
|
+
field: "project.name",
|
|
116
|
+
error: "Project name is empty",
|
|
117
|
+
suggestion: "Provide a non-empty project_name parameter"
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
if (!output.project.description || String(output.project.description).trim() === "") {
|
|
121
|
+
errors.push({
|
|
122
|
+
field: "project.description",
|
|
123
|
+
error: "Project description is empty",
|
|
124
|
+
suggestion: "Provide a non-empty description parameter"
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (!Array.isArray(output.milestones) || output.milestones.length === 0) {
|
|
129
|
+
errors.push({
|
|
130
|
+
field: "milestones",
|
|
131
|
+
error: "Milestones array is empty or missing",
|
|
132
|
+
suggestion: "Template must define at least one milestone"
|
|
133
|
+
});
|
|
134
|
+
return { valid: false, errors };
|
|
135
|
+
}
|
|
136
|
+
const milestoneNames = output.milestones.map((m) => m.name);
|
|
137
|
+
const nameSet = new Set(milestoneNames);
|
|
138
|
+
if (nameSet.size !== milestoneNames.length) {
|
|
139
|
+
const dupes = milestoneNames.filter((n, i) => milestoneNames.indexOf(n) !== i);
|
|
140
|
+
errors.push({
|
|
141
|
+
field: "milestones",
|
|
142
|
+
error: `Duplicate milestone names: ${[...new Set(dupes)].join(", ")}`,
|
|
143
|
+
suggestion: "Each milestone must have a unique name"
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
for (let mi = 0; mi < output.milestones.length; mi++) {
|
|
147
|
+
const milestone = output.milestones[mi];
|
|
148
|
+
if (!Array.isArray(milestone.phases) || milestone.phases.length === 0) {
|
|
149
|
+
errors.push({
|
|
150
|
+
field: `milestones[${mi}].phases`,
|
|
151
|
+
error: `Milestone "${milestone.name}" has no phases`,
|
|
152
|
+
suggestion: "Each milestone must have at least one phase"
|
|
153
|
+
});
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
for (let pi = 0; pi < milestone.phases.length; pi++) {
|
|
157
|
+
const phase = milestone.phases[pi];
|
|
158
|
+
const phasePath = `milestones[${mi}].phases[${pi}]`;
|
|
159
|
+
if (typeof phase.number !== "number" || !Number.isInteger(phase.number)) {
|
|
160
|
+
errors.push({
|
|
161
|
+
field: `${phasePath}.number`,
|
|
162
|
+
error: `Phase number must be an integer, got: ${phase.number}`,
|
|
163
|
+
suggestion: "Use sequential integers starting from 1"
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
if (!phase.name || String(phase.name).trim() === "") {
|
|
167
|
+
errors.push({
|
|
168
|
+
field: `${phasePath}.name`,
|
|
169
|
+
error: "Phase name is empty",
|
|
170
|
+
suggestion: "Each phase must have a descriptive name"
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
if (!phase.description || String(phase.description).trim() === "") {
|
|
174
|
+
errors.push({
|
|
175
|
+
field: `${phasePath}.description`,
|
|
176
|
+
error: "Phase description is empty",
|
|
177
|
+
suggestion: "Each phase must have a description"
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
if (!VALID_GSD_ROUTES.includes(phase.gsd_route)) {
|
|
181
|
+
errors.push({
|
|
182
|
+
field: `${phasePath}.gsd_route`,
|
|
183
|
+
error: `Invalid GSD route: ${phase.gsd_route}`,
|
|
184
|
+
suggestion: `Valid routes: ${VALID_GSD_ROUTES.join(", ")}`
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
if (!Array.isArray(phase.issues) || phase.issues.length === 0) {
|
|
188
|
+
errors.push({
|
|
189
|
+
field: `${phasePath}.issues`,
|
|
190
|
+
error: `Phase "${phase.name}" has no issues`,
|
|
191
|
+
suggestion: "Each phase must have at least one issue"
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return {
|
|
197
|
+
valid: errors.length === 0,
|
|
198
|
+
errors
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function parseRoadmap(content) {
|
|
202
|
+
if (!content || typeof content !== "string") {
|
|
203
|
+
return { phases: [], total_phases: 0, completed_phases: 0, error: "No content provided" };
|
|
204
|
+
}
|
|
205
|
+
const statusMap = {};
|
|
206
|
+
const progressTableMatch = content.match(/##\s+Progress[\s\S]*?\n((?:\|[^\n]+\|\n)+)/);
|
|
207
|
+
if (progressTableMatch) {
|
|
208
|
+
const tableRows = progressTableMatch[1].split("\n").filter((r) => r.trim().startsWith("|"));
|
|
209
|
+
for (const row of tableRows) {
|
|
210
|
+
if (row.includes("---") || row.toLowerCase().includes("phase") && row.toLowerCase().includes("status")) continue;
|
|
211
|
+
const cells = row.split("|").map((c) => c.trim()).filter(Boolean);
|
|
212
|
+
if (cells.length >= 3) {
|
|
213
|
+
const phaseNum = parseInt(cells[0], 10);
|
|
214
|
+
if (!isNaN(phaseNum)) {
|
|
215
|
+
statusMap[phaseNum] = cells[2] || "Not Started";
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
const checkboxRe = /- \[([ xX])\]\s+Phase\s+(\d+)[:\s]/gm;
|
|
221
|
+
let cbMatch;
|
|
222
|
+
while ((cbMatch = checkboxRe.exec(content)) !== null) {
|
|
223
|
+
const checked = cbMatch[1].trim().toLowerCase() === "x";
|
|
224
|
+
const num = parseInt(cbMatch[2], 10);
|
|
225
|
+
if (!isNaN(num)) {
|
|
226
|
+
statusMap[num] = checked ? "Complete" : statusMap[num] || "Not Started";
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const phaseSectionRe = /###\s+Phase\s+(\d+)[:\s]+([^\n]+)/g;
|
|
230
|
+
const phases = [];
|
|
231
|
+
let match;
|
|
232
|
+
while ((match = phaseSectionRe.exec(content)) !== null) {
|
|
233
|
+
const phaseNumber = parseInt(match[1], 10);
|
|
234
|
+
const phaseName = match[2].trim();
|
|
235
|
+
const sectionStart = match.index + match[0].length;
|
|
236
|
+
const nextSectionMatch = /\n###\s+/g;
|
|
237
|
+
nextSectionMatch.lastIndex = sectionStart;
|
|
238
|
+
const nextMatch = nextSectionMatch.exec(content);
|
|
239
|
+
const sectionEnd = nextMatch ? nextMatch.index : content.length;
|
|
240
|
+
const sectionText = content.slice(sectionStart, sectionEnd);
|
|
241
|
+
const goalMatch = sectionText.match(/\*\*Goal[:\*]*\*?\*?[:\s]+([^\n]+)/);
|
|
242
|
+
const goal = goalMatch ? goalMatch[1].trim().replace(/\*+$/, "") : "";
|
|
243
|
+
const reqMatch = sectionText.match(/\*\*Requirements?[:\*]*\*?\*?[:\s]+([\s\S]*?)(?=\n\*\*|\n###|$)/);
|
|
244
|
+
let requirements = [];
|
|
245
|
+
if (reqMatch) {
|
|
246
|
+
const reqText = reqMatch[1].trim();
|
|
247
|
+
requirements = reqText.split(/[,\n]+/).map((r) => r.trim().replace(/^[-*\s]+/, "").trim()).filter((r) => r.length > 0);
|
|
248
|
+
}
|
|
249
|
+
const scMatch = sectionText.match(/\*\*Success Criteria[:\*]*\*?\*?[:\s]+([\s\S]*?)(?=\n\*\*|\n###|$)/);
|
|
250
|
+
let success_criteria = [];
|
|
251
|
+
if (scMatch) {
|
|
252
|
+
const scText = scMatch[1];
|
|
253
|
+
success_criteria = scText.split("\n").map((line) => line.trim().replace(/^[\d]+\.\s*/, "").replace(/^[-*]\s*/, "").trim()).filter((line) => line.length > 0);
|
|
254
|
+
}
|
|
255
|
+
const status = statusMap[phaseNumber] || "Not Started";
|
|
256
|
+
phases.push({
|
|
257
|
+
number: phaseNumber,
|
|
258
|
+
name: phaseName,
|
|
259
|
+
goal,
|
|
260
|
+
requirements,
|
|
261
|
+
success_criteria,
|
|
262
|
+
status
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
if (phases.length === 0) {
|
|
266
|
+
return { phases: [], total_phases: 0, completed_phases: 0, error: "No phases found in ROADMAP.md" };
|
|
267
|
+
}
|
|
268
|
+
phases.sort((a, b) => a.number - b.number);
|
|
269
|
+
const completedPhases = phases.filter(
|
|
270
|
+
(p) => p.status === "Complete" || p.status === "complete" || p.status === "Done"
|
|
271
|
+
).length;
|
|
272
|
+
return {
|
|
273
|
+
phases,
|
|
274
|
+
total_phases: phases.length,
|
|
275
|
+
completed_phases: completedPhases
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
if (require.main === module) {
|
|
279
|
+
const args = process.argv.slice(2);
|
|
280
|
+
const command = args[0];
|
|
281
|
+
if (!command || command === "--help" || command === "-h") {
|
|
282
|
+
console.log(`Usage:
|
|
283
|
+
node template-loader.cjs validate (reads JSON from stdin)
|
|
284
|
+
node template-loader.cjs schema (prints templates/schema.json to stdout)
|
|
285
|
+
node template-loader.cjs parse-roadmap (reads ROADMAP.md from stdin, outputs JSON)
|
|
286
|
+
|
|
287
|
+
Commands:
|
|
288
|
+
validate Validate an AI-generated template from stdin
|
|
289
|
+
schema Print the templates/schema.json schema to stdout
|
|
290
|
+
parse-roadmap Parse a GSD ROADMAP.md from stdin into structured JSON
|
|
291
|
+
|
|
292
|
+
Valid GSD routes: ${VALID_GSD_ROUTES.join(", ")}
|
|
293
|
+
|
|
294
|
+
The validate command accepts any JSON object with:
|
|
295
|
+
- type: any descriptive string (game, mobile-app, api-service, data-pipeline, etc.)
|
|
296
|
+
- project: { name, description }
|
|
297
|
+
- milestones: array of milestones with phases and issues
|
|
298
|
+
`);
|
|
299
|
+
process.exit(0);
|
|
300
|
+
}
|
|
301
|
+
if (command === "validate") {
|
|
302
|
+
let input = "";
|
|
303
|
+
process.stdin.setEncoding("utf-8");
|
|
304
|
+
process.stdin.on("data", (chunk) => {
|
|
305
|
+
input += chunk;
|
|
306
|
+
});
|
|
307
|
+
process.stdin.on("end", () => {
|
|
308
|
+
try {
|
|
309
|
+
const output = JSON.parse(input);
|
|
310
|
+
const result = validate(output);
|
|
311
|
+
console.log(JSON.stringify(result, null, 2));
|
|
312
|
+
process.exit(result.valid ? 0 : 1);
|
|
313
|
+
} catch (err) {
|
|
314
|
+
console.error(JSON.stringify({
|
|
315
|
+
valid: false,
|
|
316
|
+
errors: [{ field: "input", error: `Failed to parse stdin as JSON: ${err.message}`, suggestion: "Pipe valid JSON to stdin" }]
|
|
317
|
+
}, null, 2));
|
|
318
|
+
process.exit(1);
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
} else if (command === "schema") {
|
|
322
|
+
try {
|
|
323
|
+
console.log(getSchema());
|
|
324
|
+
process.exit(0);
|
|
325
|
+
} catch (err) {
|
|
326
|
+
console.error(`Error reading schema: ${err.message}`);
|
|
327
|
+
process.exit(1);
|
|
328
|
+
}
|
|
329
|
+
} else if (command === "parse-roadmap") {
|
|
330
|
+
let input = "";
|
|
331
|
+
process.stdin.setEncoding("utf-8");
|
|
332
|
+
process.stdin.on("data", (chunk) => {
|
|
333
|
+
input += chunk;
|
|
334
|
+
});
|
|
335
|
+
process.stdin.on("end", () => {
|
|
336
|
+
try {
|
|
337
|
+
const result = parseRoadmap(input);
|
|
338
|
+
console.log(JSON.stringify(result, null, 2));
|
|
339
|
+
process.exit(result.error ? 1 : 0);
|
|
340
|
+
} catch (err) {
|
|
341
|
+
console.error(JSON.stringify({
|
|
342
|
+
phases: [],
|
|
343
|
+
total_phases: 0,
|
|
344
|
+
completed_phases: 0,
|
|
345
|
+
error: `Failed to parse ROADMAP.md: ${err.message}`
|
|
346
|
+
}, null, 2));
|
|
347
|
+
process.exit(1);
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
} else {
|
|
351
|
+
console.error(JSON.stringify({
|
|
352
|
+
success: false,
|
|
353
|
+
errors: [{ field: "command", error: `Unknown command: ${command}`, suggestion: "Valid commands: validate, schema, parse-roadmap" }]
|
|
354
|
+
}, null, 2));
|
|
355
|
+
process.exit(1);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
module.exports = { validate, getSchema, parseRoadmap, VALID_GSD_ROUTES };
|
|
359
|
+
} (templateLoader));
|
|
360
|
+
return templateLoader.exports;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
var templates;
|
|
364
|
+
var hasRequiredTemplates;
|
|
365
|
+
|
|
366
|
+
function requireTemplates () {
|
|
367
|
+
if (hasRequiredTemplates) return templates;
|
|
368
|
+
hasRequiredTemplates = 1;
|
|
369
|
+
const { validate, getSchema, VALID_GSD_ROUTES } = requireTemplateLoader();
|
|
370
|
+
templates = { validate, getSchema, VALID_GSD_ROUTES };
|
|
371
|
+
return templates;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
var lib;
|
|
375
|
+
var hasRequiredLib;
|
|
376
|
+
|
|
377
|
+
function requireLib () {
|
|
378
|
+
if (hasRequiredLib) return lib;
|
|
379
|
+
hasRequiredLib = 1;
|
|
380
|
+
lib = {
|
|
381
|
+
...claude.requireState(),
|
|
382
|
+
...claude.requireGithub(),
|
|
383
|
+
...requireGsd(),
|
|
384
|
+
...requireTemplates(),
|
|
385
|
+
...claude.requireOutput(),
|
|
386
|
+
...claude.requireClaude()
|
|
387
|
+
};
|
|
388
|
+
return lib;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
var libExports = requireLib();
|
|
392
|
+
var index = /*@__PURE__*/claude.getDefaultExportFromCjs(libExports);
|
|
393
|
+
|
|
394
|
+
module.exports = index;
|
|
395
|
+
0&&(module.exports={getMgwDir,getActiveDir,getCompletedDir,loadProjectState,writeProjectState,loadActiveIssue,mergeProjectState,migrateProjectState,resolveActiveMilestoneIndex,getRepo,getIssue,listIssues,getMilestone,getRateLimit,closeMilestone,createRelease,createProject,addItemToProject,postMilestoneStartAnnouncement,getGsdToolsPath,invokeGsdTool,validate,getSchema,VALID_GSD_ROUTES,IS_TTY,IS_CI,USE_COLOR,COLORS,colorize,statusLine,log,error,verbose,debug,formatJson,assertClaudeAvailable,invokeClaude,getCommandsDir});
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@snipcodeit/mgw",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "GitHub-native issue-to-PR automation for Claude Code, powered by Get Shit Done",
|
|
5
|
+
"bin": {
|
|
6
|
+
"mgw": "./dist/bin/mgw.cjs"
|
|
7
|
+
},
|
|
8
|
+
"main": "./dist/lib/index.cjs",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/",
|
|
11
|
+
"bin/mgw-install.cjs",
|
|
12
|
+
"commands/",
|
|
13
|
+
"templates/"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "pkgroll --clean-dist --src .",
|
|
17
|
+
"dev": "pkgroll --watch --src .",
|
|
18
|
+
"test": "node --test 'test/**/*.test.cjs'",
|
|
19
|
+
"prepublishOnly": "npm run build",
|
|
20
|
+
"postinstall": "node ./bin/mgw-install.cjs"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"commander": "^14.0.3"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"pkgroll": "^2.26.3"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=18.0.0"
|
|
30
|
+
},
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/snipcodeit/mgw.git"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"claude-code",
|
|
37
|
+
"github",
|
|
38
|
+
"automation",
|
|
39
|
+
"project-management",
|
|
40
|
+
"gsd",
|
|
41
|
+
"cli",
|
|
42
|
+
"developer-tools",
|
|
43
|
+
"ai"
|
|
44
|
+
],
|
|
45
|
+
"author": "snipcodeit",
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"homepage": "https://github.com/snipcodeit/mgw",
|
|
48
|
+
"bugs": {
|
|
49
|
+
"url": "https://github.com/snipcodeit/mgw/issues"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "MGW Pipeline Template",
|
|
4
|
+
"description": "Schema for MGW pipeline templates. Each template defines an opinionated project lifecycle with milestones, phases, and GSD route recommendations.",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["type", "version", "description", "parameters", "milestones"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"type": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"minLength": 1,
|
|
11
|
+
"description": "Project type identifier — any descriptive string (e.g. game, mobile-app, api-service, data-pipeline, saas-platform, etc.)"
|
|
12
|
+
},
|
|
13
|
+
"version": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"pattern": "^\\d+\\.\\d+\\.\\d+$",
|
|
16
|
+
"description": "Template version (semver)"
|
|
17
|
+
},
|
|
18
|
+
"description": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"minLength": 1,
|
|
21
|
+
"description": "Human-readable template description"
|
|
22
|
+
},
|
|
23
|
+
"parameters": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"required": ["required", "optional"],
|
|
26
|
+
"properties": {
|
|
27
|
+
"required": {
|
|
28
|
+
"type": "array",
|
|
29
|
+
"items": { "$ref": "#/definitions/requiredParameter" },
|
|
30
|
+
"description": "Parameters the user must provide"
|
|
31
|
+
},
|
|
32
|
+
"optional": {
|
|
33
|
+
"type": "array",
|
|
34
|
+
"items": { "$ref": "#/definitions/optionalParameter" },
|
|
35
|
+
"description": "Parameters with smart defaults"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"additionalProperties": false
|
|
39
|
+
},
|
|
40
|
+
"milestones": {
|
|
41
|
+
"type": "array",
|
|
42
|
+
"minItems": 1,
|
|
43
|
+
"items": { "$ref": "#/definitions/milestone" },
|
|
44
|
+
"description": "Ordered milestones for the project lifecycle"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"additionalProperties": false,
|
|
48
|
+
"definitions": {
|
|
49
|
+
"requiredParameter": {
|
|
50
|
+
"type": "object",
|
|
51
|
+
"required": ["name", "type", "description"],
|
|
52
|
+
"properties": {
|
|
53
|
+
"name": { "type": "string", "minLength": 1 },
|
|
54
|
+
"type": { "type": "string", "enum": ["string"] },
|
|
55
|
+
"description": { "type": "string", "minLength": 1 }
|
|
56
|
+
},
|
|
57
|
+
"additionalProperties": false
|
|
58
|
+
},
|
|
59
|
+
"optionalParameter": {
|
|
60
|
+
"type": "object",
|
|
61
|
+
"required": ["name", "type", "default", "description"],
|
|
62
|
+
"properties": {
|
|
63
|
+
"name": { "type": "string", "minLength": 1 },
|
|
64
|
+
"type": { "type": "string", "enum": ["string"] },
|
|
65
|
+
"default": { "type": "string" },
|
|
66
|
+
"description": { "type": "string", "minLength": 1 }
|
|
67
|
+
},
|
|
68
|
+
"additionalProperties": false
|
|
69
|
+
},
|
|
70
|
+
"milestone": {
|
|
71
|
+
"type": "object",
|
|
72
|
+
"required": ["name", "description", "phases"],
|
|
73
|
+
"properties": {
|
|
74
|
+
"name": {
|
|
75
|
+
"type": "string",
|
|
76
|
+
"minLength": 1,
|
|
77
|
+
"description": "Milestone name (may contain {prefix} placeholder)"
|
|
78
|
+
},
|
|
79
|
+
"description": {
|
|
80
|
+
"type": "string",
|
|
81
|
+
"minLength": 1,
|
|
82
|
+
"description": "What this milestone delivers"
|
|
83
|
+
},
|
|
84
|
+
"phases": {
|
|
85
|
+
"type": "array",
|
|
86
|
+
"minItems": 1,
|
|
87
|
+
"items": { "$ref": "#/definitions/phase" }
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"additionalProperties": false
|
|
91
|
+
},
|
|
92
|
+
"phase": {
|
|
93
|
+
"type": "object",
|
|
94
|
+
"required": ["number", "name", "description", "gsd_route", "issues"],
|
|
95
|
+
"properties": {
|
|
96
|
+
"number": {
|
|
97
|
+
"type": "integer",
|
|
98
|
+
"minimum": 1,
|
|
99
|
+
"description": "Phase number within the project"
|
|
100
|
+
},
|
|
101
|
+
"name": {
|
|
102
|
+
"type": "string",
|
|
103
|
+
"minLength": 1,
|
|
104
|
+
"description": "Phase name"
|
|
105
|
+
},
|
|
106
|
+
"description": {
|
|
107
|
+
"type": "string",
|
|
108
|
+
"minLength": 1,
|
|
109
|
+
"description": "What this phase accomplishes"
|
|
110
|
+
},
|
|
111
|
+
"gsd_route": {
|
|
112
|
+
"type": "string",
|
|
113
|
+
"enum": [
|
|
114
|
+
"quick",
|
|
115
|
+
"plan-phase",
|
|
116
|
+
"discuss-phase",
|
|
117
|
+
"research-phase",
|
|
118
|
+
"execute-phase",
|
|
119
|
+
"verify-phase",
|
|
120
|
+
"new-project",
|
|
121
|
+
"new-milestone",
|
|
122
|
+
"complete-milestone"
|
|
123
|
+
],
|
|
124
|
+
"description": "Recommended GSD workflow for this phase"
|
|
125
|
+
},
|
|
126
|
+
"issues": {
|
|
127
|
+
"type": "array",
|
|
128
|
+
"minItems": 1,
|
|
129
|
+
"items": { "$ref": "#/definitions/issue" },
|
|
130
|
+
"description": "Issue templates for this phase"
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
"additionalProperties": false
|
|
134
|
+
},
|
|
135
|
+
"issue": {
|
|
136
|
+
"type": "object",
|
|
137
|
+
"required": ["title", "description", "labels"],
|
|
138
|
+
"properties": {
|
|
139
|
+
"title": {
|
|
140
|
+
"type": "string",
|
|
141
|
+
"minLength": 1,
|
|
142
|
+
"description": "Issue title (may contain {project_name} or {description} placeholders)"
|
|
143
|
+
},
|
|
144
|
+
"description": {
|
|
145
|
+
"type": "string",
|
|
146
|
+
"minLength": 1,
|
|
147
|
+
"description": "Issue description"
|
|
148
|
+
},
|
|
149
|
+
"labels": {
|
|
150
|
+
"type": "array",
|
|
151
|
+
"items": { "type": "string" },
|
|
152
|
+
"description": "Labels to apply to the issue"
|
|
153
|
+
},
|
|
154
|
+
"depends_on": {
|
|
155
|
+
"type": "array",
|
|
156
|
+
"items": { "type": "string" },
|
|
157
|
+
"default": [],
|
|
158
|
+
"description": "Issue slugs this issue depends on (resolved to GitHub issue numbers during init)"
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
"additionalProperties": false
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|