ios-vibe-mcp01 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/dist/index.js +10 -6
- package/dist/iosVibe.js +14 -51
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,16 +2,20 @@
|
|
|
2
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
4
|
import { registerIosVibeTool } from "./iosVibe.js";
|
|
5
|
-
const server = new McpServer({
|
|
6
|
-
name: "iOS Vibe Factory",
|
|
7
|
-
version: "0.1.0",
|
|
8
|
-
});
|
|
9
|
-
registerIosVibeTool(server);
|
|
10
5
|
async function main() {
|
|
6
|
+
const server = new McpServer({
|
|
7
|
+
name: "ios-vibe-factory",
|
|
8
|
+
version: "0.1.2",
|
|
9
|
+
});
|
|
10
|
+
// ✅ ios_vibe tool'unu ekle
|
|
11
|
+
registerIosVibeTool(server);
|
|
12
|
+
// ✅ Cursor MCP: stdio transport ile bağlan
|
|
11
13
|
const transport = new StdioServerTransport();
|
|
12
14
|
await server.connect(transport);
|
|
15
|
+
// ⚠️ stdout'a log basma (protocol bozulur). Sadece stderr.
|
|
16
|
+
console.error("ios-vibe-mcp01: connected via stdio");
|
|
13
17
|
}
|
|
14
18
|
main().catch((err) => {
|
|
15
|
-
console.error("
|
|
19
|
+
console.error("ios-vibe-mcp01: startup failed", err);
|
|
16
20
|
process.exit(1);
|
|
17
21
|
});
|
package/dist/iosVibe.js
CHANGED
|
@@ -3,8 +3,8 @@ import { renderFilesForCommand } from "./templates.js";
|
|
|
3
3
|
import { validateWorkflow } from "./rules.js";
|
|
4
4
|
const CommandSchema = z.enum(["plan", "architecture", "coding", "uiux", "test", "review", "ship"]);
|
|
5
5
|
const InputSchema = z.object({
|
|
6
|
-
command: CommandSchema,
|
|
7
|
-
idea: z.string().optional(),
|
|
6
|
+
command: CommandSchema.describe("Which stage of the iOS app workflow to run"),
|
|
7
|
+
idea: z.string().optional().describe("Your app idea (required for plan)"),
|
|
8
8
|
config: z
|
|
9
9
|
.object({
|
|
10
10
|
appName: z.string().default("MyApp"),
|
|
@@ -13,7 +13,8 @@ const InputSchema = z.object({
|
|
|
13
13
|
tone: z.string().default("soft pink"),
|
|
14
14
|
constraints: z.array(z.string()).default(["offline-first", "no firebase", "mvvm", "repository"]),
|
|
15
15
|
})
|
|
16
|
-
.optional()
|
|
16
|
+
.optional()
|
|
17
|
+
.describe("Optional project configuration"),
|
|
17
18
|
state: z
|
|
18
19
|
.object({
|
|
19
20
|
projectBlueprintMd: z.string().optional(),
|
|
@@ -26,14 +27,9 @@ const InputSchema = z.object({
|
|
|
26
27
|
runbookMd: z.string().optional(),
|
|
27
28
|
backlogMd: z.string().optional(),
|
|
28
29
|
})
|
|
29
|
-
.optional()
|
|
30
|
+
.optional()
|
|
31
|
+
.describe("Previous stage outputs (auto-managed)"),
|
|
30
32
|
});
|
|
31
|
-
/**
|
|
32
|
-
* Accepts both:
|
|
33
|
-
* 1) JSON input (object): { command: "plan", idea: "..." }
|
|
34
|
-
* 2) Human text input (string): "plan: ..." or "architecture" etc.
|
|
35
|
-
* Also supports { text: "plan: ..." } shape as a convenience.
|
|
36
|
-
*/
|
|
37
33
|
function normalizeInput(raw) {
|
|
38
34
|
const text = typeof raw === "string"
|
|
39
35
|
? raw
|
|
@@ -43,71 +39,38 @@ function normalizeInput(raw) {
|
|
|
43
39
|
if (!text)
|
|
44
40
|
return raw;
|
|
45
41
|
const t = text.trim();
|
|
46
|
-
// plan: <idea>
|
|
47
42
|
const planMatch = t.match(/^plan\s*:\s*(.+)$/i);
|
|
48
|
-
if (planMatch)
|
|
43
|
+
if (planMatch)
|
|
49
44
|
return { command: "plan", idea: planMatch[1].trim() };
|
|
50
|
-
}
|
|
51
|
-
// Single-word commands
|
|
52
45
|
const lower = t.toLowerCase();
|
|
53
46
|
const allowed = ["architecture", "coding", "uiux", "test", "review", "ship"];
|
|
54
|
-
if (allowed.includes(lower))
|
|
47
|
+
if (allowed.includes(lower))
|
|
55
48
|
return { command: lower };
|
|
56
|
-
|
|
57
|
-
// If user writes just "plan" without idea, let workflow validator handle it
|
|
58
|
-
if (/^plan$/i.test(t)) {
|
|
49
|
+
if (/^plan$/i.test(t))
|
|
59
50
|
return { command: "plan", idea: "" };
|
|
60
|
-
}
|
|
61
|
-
// Fallback: keep original raw so Zod can throw a clear error
|
|
62
51
|
return raw;
|
|
63
52
|
}
|
|
64
53
|
export function registerIosVibeTool(server) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
// or "text" wrappers depending on the client
|
|
68
|
-
command: z.string().optional(),
|
|
69
|
-
idea: z.string().optional(),
|
|
70
|
-
config: z.any().optional(),
|
|
71
|
-
state: z.any().optional(),
|
|
72
|
-
text: z.string().optional(),
|
|
73
|
-
}, async (raw) => {
|
|
54
|
+
// ✅ Use InputSchema.shape for maximum SDK compatibility
|
|
55
|
+
server.tool("ios_vibe", InputSchema.shape, async (raw) => {
|
|
74
56
|
const normalized = normalizeInput(raw);
|
|
75
57
|
const parsed = InputSchema.safeParse(normalized);
|
|
76
58
|
if (!parsed.success) {
|
|
77
|
-
return {
|
|
78
|
-
content: [
|
|
79
|
-
{
|
|
80
|
-
type: "text",
|
|
81
|
-
text: `Invalid input: ${parsed.error.message}`,
|
|
82
|
-
},
|
|
83
|
-
],
|
|
84
|
-
};
|
|
59
|
+
return { content: [{ type: "text", text: `Invalid input: ${parsed.error.message}` }] };
|
|
85
60
|
}
|
|
86
61
|
const input = parsed.data;
|
|
87
|
-
// 1) Workflow gatekeeping
|
|
88
62
|
const flow = validateWorkflow(input);
|
|
89
63
|
if (!flow.ok) {
|
|
90
64
|
return {
|
|
91
65
|
content: [
|
|
92
66
|
{
|
|
93
67
|
type: "text",
|
|
94
|
-
text: `Command blocked: ${flow.reason}\n\n
|
|
95
|
-
`Fix: ${flow.fix}\n\n` +
|
|
96
|
-
`Suggested next: ${flow.suggestedNext}`,
|
|
68
|
+
text: `Command blocked: ${flow.reason}\n\nFix: ${flow.fix}\n\nSuggested next: ${flow.suggestedNext}`,
|
|
97
69
|
},
|
|
98
70
|
],
|
|
99
71
|
};
|
|
100
72
|
}
|
|
101
|
-
// 2) Generate files
|
|
102
73
|
const result = renderFilesForCommand(input);
|
|
103
|
-
|
|
104
|
-
return {
|
|
105
|
-
content: [
|
|
106
|
-
{
|
|
107
|
-
type: "text",
|
|
108
|
-
text: JSON.stringify(result, null, 2),
|
|
109
|
-
},
|
|
110
|
-
],
|
|
111
|
-
};
|
|
74
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
112
75
|
});
|
|
113
76
|
}
|
package/package.json
CHANGED