@forcefield/mcp-server 0.1.7 → 0.1.9

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.
@@ -3,13 +3,15 @@
3
3
  // src/supabase-defaults.ts
4
4
  var PRODUCTION_SUPABASE_URL = "https://ffhwxtbenauaimiwvqed.supabase.co";
5
5
  var PRODUCTION_SUPABASE_PUBLISHABLE_KEY = "sb_publishable_AvzTXmuoTKrIb2mPk4dzdQ_gR7GrpMW";
6
+ var LOCAL_SUPABASE_URL = "http://127.0.0.1:54321";
6
7
  var LOCAL_SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0";
7
8
  var LOCAL_SUPABASE_SERVICE_ROLE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU";
8
9
 
9
10
  export {
10
11
  PRODUCTION_SUPABASE_URL,
11
12
  PRODUCTION_SUPABASE_PUBLISHABLE_KEY,
13
+ LOCAL_SUPABASE_URL,
12
14
  LOCAL_SUPABASE_ANON_KEY,
13
15
  LOCAL_SUPABASE_SERVICE_ROLE_KEY
14
16
  };
15
- //# sourceMappingURL=chunk-6YANB5QT.js.map
17
+ //# sourceMappingURL=chunk-UOMOGP46.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/supabase-defaults.ts"],"sourcesContent":["/**\n * Canonical Supabase defaults for hosted production and local development.\n * Production defaults are used unless local/dev mode is explicitly enabled.\n */\n\nexport const PRODUCTION_SUPABASE_URL = 'https://ffhwxtbenauaimiwvqed.supabase.co';\nexport const PRODUCTION_SUPABASE_PUBLISHABLE_KEY =\n 'sb_publishable_AvzTXmuoTKrIb2mPk4dzdQ_gR7GrpMW';\n\nexport const LOCAL_SUPABASE_URL = 'http://127.0.0.1:54321';\nexport const LOCAL_SUPABASE_ANON_KEY =\n 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0';\nexport const LOCAL_SUPABASE_SERVICE_ROLE_KEY =\n 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU';\n"],"mappings":";;;AAKO,IAAM,0BAA0B;AAChC,IAAM,sCACX;AAGK,IAAM,0BACX;AACK,IAAM,kCACX;","names":[]}
1
+ {"version":3,"sources":["../src/supabase-defaults.ts"],"sourcesContent":["/**\n * Canonical Supabase defaults for hosted production and local development.\n * Production defaults are used unless local/dev mode is explicitly enabled.\n */\n\nexport const PRODUCTION_SUPABASE_URL = 'https://ffhwxtbenauaimiwvqed.supabase.co';\nexport const PRODUCTION_SUPABASE_PUBLISHABLE_KEY =\n 'sb_publishable_AvzTXmuoTKrIb2mPk4dzdQ_gR7GrpMW';\n\nexport const LOCAL_SUPABASE_URL = 'http://127.0.0.1:54321';\nexport const LOCAL_SUPABASE_ANON_KEY =\n 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0';\nexport const LOCAL_SUPABASE_SERVICE_ROLE_KEY =\n 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU';\n"],"mappings":";;;AAKO,IAAM,0BAA0B;AAChC,IAAM,sCACX;AAEK,IAAM,qBAAqB;AAC3B,IAAM,0BACX;AACK,IAAM,kCACX;","names":[]}
@@ -1,25 +1,305 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runMcpCli
4
- } from "../chunk-7XLGRGP6.js";
4
+ } from "../chunk-K464TYAJ.js";
5
5
  import {
6
6
  runSetupCli
7
- } from "../chunk-4FKA7CA3.js";
8
- import "../chunk-6YANB5QT.js";
7
+ } from "../chunk-DGBLHABK.js";
8
+ import {
9
+ LOCAL_SUPABASE_URL,
10
+ PRODUCTION_SUPABASE_PUBLISHABLE_KEY,
11
+ PRODUCTION_SUPABASE_URL
12
+ } from "../chunk-UOMOGP46.js";
9
13
 
10
14
  // cli/index.ts
11
15
  import { pathToFileURL } from "url";
16
+
17
+ // cli/dashboard.ts
18
+ import { spawn } from "child_process";
19
+ import { existsSync } from "fs";
20
+ import { writeFile } from "fs/promises";
21
+ import { join, resolve } from "path";
22
+ import pc from "picocolors";
23
+ var DEFAULT_DIR = "./forcefield-dashboard";
24
+ function npmCmd() {
25
+ return process.platform === "win32" ? "npm.cmd" : "npm";
26
+ }
27
+ function printUsage() {
28
+ console.log(
29
+ [
30
+ "Forcefield Dashboard",
31
+ "",
32
+ "Usage:",
33
+ " forcefield dashboard start [--dir <path>] [--local] [--force] [--no-install] [--no-run]",
34
+ " forcefield dashboard --help",
35
+ "",
36
+ "Examples:",
37
+ " forcefield dashboard start",
38
+ " forcefield dashboard start --dir ./dashboard",
39
+ " forcefield dashboard start --local --force"
40
+ ].join("\n")
41
+ );
42
+ }
43
+ function parseDashboardCommand(args) {
44
+ const defaultOptions = {
45
+ dir: DEFAULT_DIR,
46
+ local: false,
47
+ force: false,
48
+ install: true,
49
+ run: true
50
+ };
51
+ if (args.includes("--help") || args.includes("-h")) {
52
+ return { type: "help", options: defaultOptions };
53
+ }
54
+ const first = args[0];
55
+ const isStart = !first || first === "start";
56
+ if (!isStart) {
57
+ return {
58
+ type: "help",
59
+ invalidCommand: first,
60
+ options: defaultOptions
61
+ };
62
+ }
63
+ const optionArgs = first === "start" ? args.slice(1) : args;
64
+ const options = { ...defaultOptions };
65
+ for (let i = 0; i < optionArgs.length; i += 1) {
66
+ const arg = optionArgs[i];
67
+ if (arg === "--dir" || arg === "-d") {
68
+ const value = optionArgs[i + 1];
69
+ if (!value || value.startsWith("-")) {
70
+ return {
71
+ type: "help",
72
+ parseError: "Missing value for --dir.",
73
+ options: defaultOptions
74
+ };
75
+ }
76
+ options.dir = value;
77
+ i += 1;
78
+ continue;
79
+ }
80
+ if (arg === "--local") {
81
+ options.local = true;
82
+ continue;
83
+ }
84
+ if (arg === "--force" || arg === "-f") {
85
+ options.force = true;
86
+ continue;
87
+ }
88
+ if (arg === "--no-install") {
89
+ options.install = false;
90
+ continue;
91
+ }
92
+ if (arg === "--no-run") {
93
+ options.run = false;
94
+ continue;
95
+ }
96
+ return {
97
+ type: "help",
98
+ parseError: `Unknown option: ${arg}`,
99
+ options: defaultOptions
100
+ };
101
+ }
102
+ return {
103
+ type: "start",
104
+ options
105
+ };
106
+ }
107
+ async function runProcess(command, args, options) {
108
+ return new Promise((resolvePromise, rejectPromise) => {
109
+ const child = spawn(command, args, {
110
+ cwd: options?.cwd,
111
+ env: process.env,
112
+ stdio: options?.capture ? ["ignore", "pipe", "pipe"] : "inherit"
113
+ });
114
+ let stdout = "";
115
+ let stderr = "";
116
+ if (options?.capture) {
117
+ child.stdout.on("data", (chunk) => {
118
+ stdout += String(chunk);
119
+ });
120
+ child.stderr.on("data", (chunk) => {
121
+ stderr += String(chunk);
122
+ });
123
+ }
124
+ child.on("error", (error) => {
125
+ rejectPromise(error);
126
+ });
127
+ child.on("close", (code) => {
128
+ resolvePromise({ code: code ?? 1, stdout, stderr });
129
+ });
130
+ });
131
+ }
132
+ function parseEnvAssignments(raw) {
133
+ const env = {};
134
+ for (const line of raw.split(/\r?\n/)) {
135
+ const trimmed = line.trim();
136
+ if (!trimmed || trimmed.startsWith("#")) continue;
137
+ const match = trimmed.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);
138
+ if (!match) continue;
139
+ const key = match[1];
140
+ let value = match[2] ?? "";
141
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
142
+ value = value.slice(1, -1);
143
+ }
144
+ env[key] = value;
145
+ }
146
+ return env;
147
+ }
148
+ function formatManualFallback(targetDir, force) {
149
+ return [
150
+ "Manual fallback:",
151
+ ` npx -y @forcefield/dashboard-template@beta init --dir ${targetDir}${force ? " --force" : ""}`
152
+ ].join("\n");
153
+ }
154
+ var defaultOps = {
155
+ async scaffoldDashboard(targetDir, force) {
156
+ const args = [
157
+ "exec",
158
+ "--yes",
159
+ "--package=@forcefield/dashboard-template@beta",
160
+ "forcefield-dashboard",
161
+ "--",
162
+ "init",
163
+ "--dir",
164
+ targetDir
165
+ ];
166
+ if (force) {
167
+ args.push("--force");
168
+ }
169
+ try {
170
+ const result = await runProcess(npmCmd(), args);
171
+ if (result.code !== 0) {
172
+ throw new Error(`Scaffold command exited with code ${result.code}.`);
173
+ }
174
+ } catch (error) {
175
+ const message = error instanceof Error ? error.message : String(error);
176
+ throw new Error(
177
+ `Failed to scaffold dashboard automatically: ${message}
178
+ ${formatManualFallback(targetDir, force)}`
179
+ );
180
+ }
181
+ },
182
+ async getLocalEnv() {
183
+ let result;
184
+ try {
185
+ result = await runProcess("supabase", ["status", "-o", "env"], { capture: true });
186
+ } catch (error) {
187
+ const message = error instanceof Error ? error.message : String(error);
188
+ throw new Error(
189
+ `Could not run 'supabase status -o env': ${message}. Install Supabase CLI and run ${pc.cyan("supabase start")}, or remove ${pc.cyan("--local")}.`
190
+ );
191
+ }
192
+ if (result.code !== 0) {
193
+ const detail = (result.stderr || result.stdout).trim() || `exit code ${result.code}`;
194
+ throw new Error(
195
+ `Local Supabase is unavailable (${detail}). Run ${pc.cyan("supabase start")} first, or remove ${pc.cyan("--local")}.`
196
+ );
197
+ }
198
+ const env = parseEnvAssignments(result.stdout);
199
+ const supabaseUrl = env.SUPABASE_URL || LOCAL_SUPABASE_URL;
200
+ const anonKey = env.SUPABASE_ANON_KEY || env.ANON_KEY;
201
+ if (!anonKey) {
202
+ throw new Error(
203
+ `Could not find an anon key from ${pc.cyan("supabase status -o env")}. Ensure local stack is running, or remove ${pc.cyan("--local")}.`
204
+ );
205
+ }
206
+ return { supabaseUrl, anonKey };
207
+ },
208
+ async installDependencies(targetDir) {
209
+ const result = await runProcess(npmCmd(), ["install"], { cwd: targetDir });
210
+ if (result.code !== 0) {
211
+ throw new Error(`Dependency install failed (exit ${result.code}).`);
212
+ }
213
+ },
214
+ async startDevServer(targetDir) {
215
+ const result = await runProcess(npmCmd(), ["run", "dev"], { cwd: targetDir });
216
+ if (result.code !== 0) {
217
+ throw new Error(`Dashboard dev server exited with code ${result.code}.`);
218
+ }
219
+ }
220
+ };
221
+ async function writeDashboardEnv(targetDir, env, force) {
222
+ const envPath = join(targetDir, ".env.local");
223
+ if (existsSync(envPath) && !force) {
224
+ return { path: envPath, wrote: false };
225
+ }
226
+ const content = [
227
+ `NEXT_PUBLIC_SUPABASE_URL=${env.supabaseUrl}`,
228
+ `NEXT_PUBLIC_SUPABASE_ANON_KEY=${env.anonKey}`,
229
+ ""
230
+ ].join("\n");
231
+ await writeFile(envPath, content, "utf-8");
232
+ return { path: envPath, wrote: true };
233
+ }
234
+ async function runDashboardStart(options, ops = defaultOps) {
235
+ const targetDir = resolve(process.cwd(), options.dir);
236
+ console.log(pc.bold("Forcefield Dashboard Bootstrap"));
237
+ console.log(`Target: ${pc.cyan(targetDir)}`);
238
+ await ops.scaffoldDashboard(targetDir, options.force);
239
+ const env = options.local ? await ops.getLocalEnv() : {
240
+ supabaseUrl: PRODUCTION_SUPABASE_URL,
241
+ anonKey: PRODUCTION_SUPABASE_PUBLISHABLE_KEY
242
+ };
243
+ const envWrite = await writeDashboardEnv(targetDir, env, options.force);
244
+ if (envWrite.wrote) {
245
+ console.log(`${pc.green("\u2713")} Wrote ${pc.cyan(envWrite.path)} (${options.local ? "local" : "hosted"} backend).`);
246
+ } else {
247
+ console.log(`${pc.yellow("\u2022")} Preserved existing ${pc.cyan(envWrite.path)} (use ${pc.cyan("--force")} to overwrite).`);
248
+ }
249
+ if (options.install) {
250
+ console.log(`${pc.dim("\u2192")} Installing dashboard dependencies...`);
251
+ await ops.installDependencies(targetDir);
252
+ } else {
253
+ console.log(`${pc.yellow("\u2022")} Skipped dependency install (${pc.cyan("--no-install")}).`);
254
+ }
255
+ if (options.run) {
256
+ console.log(`${pc.dim("\u2192")} Starting dashboard dev server...`);
257
+ console.log(pc.dim("Press Ctrl+C to stop."));
258
+ await ops.startDevServer(targetDir);
259
+ return;
260
+ }
261
+ console.log(`${pc.yellow("\u2022")} Skipped dev server startup (${pc.cyan("--no-run")}).`);
262
+ console.log("");
263
+ console.log("Next steps:");
264
+ console.log(` cd ${targetDir}`);
265
+ if (!options.install) {
266
+ console.log(" npm install");
267
+ }
268
+ console.log(" npm run dev");
269
+ console.log("");
270
+ console.log("Then open http://localhost:3000 and sign in.");
271
+ }
272
+ async function runDashboardCli(args) {
273
+ const parsed = parseDashboardCommand(args);
274
+ if (parsed.type === "help") {
275
+ if (parsed.invalidCommand) {
276
+ console.error(pc.red(`Unknown dashboard subcommand: ${parsed.invalidCommand}`));
277
+ }
278
+ if (parsed.parseError) {
279
+ console.error(pc.red(parsed.parseError));
280
+ }
281
+ printUsage();
282
+ if (parsed.invalidCommand || parsed.parseError) {
283
+ process.exitCode = 1;
284
+ }
285
+ return;
286
+ }
287
+ await runDashboardStart(parsed.options);
288
+ }
289
+
290
+ // cli/index.ts
12
291
  function parseForcefieldCommand(argv) {
13
292
  const cmd = argv[2];
14
293
  const rest = argv.slice(3);
15
294
  if (!cmd || cmd === "setup") return { command: "setup", rest };
16
295
  if (cmd === "doctor") return { command: "doctor", rest };
17
296
  if (cmd === "status") return { command: "status", rest };
297
+ if (cmd === "dashboard") return { command: "dashboard", rest };
18
298
  if (cmd === "mcp") return { command: "mcp", rest };
19
299
  if (cmd === "help" || cmd === "--help" || cmd === "-h") return { command: "help", rest };
20
300
  return { command: "help", rest: [cmd, ...rest] };
21
301
  }
22
- function printUsage() {
302
+ function printUsage2() {
23
303
  console.log(
24
304
  [
25
305
  "Forcefield CLI",
@@ -28,11 +308,13 @@ function printUsage() {
28
308
  " forcefield setup Run interactive setup wizard",
29
309
  " forcefield doctor Validate setup + MCP connectivity",
30
310
  " forcefield status Show setup status in current project",
311
+ " forcefield dashboard start Scaffold + run local dashboard (hosted backend by default)",
31
312
  " forcefield mcp Start MCP server process (stdio)",
32
313
  " forcefield help Show this help",
33
314
  "",
34
315
  "One-off without global install:",
35
- " npx -y forcefield setup",
316
+ " npx -y @forcefield/forcefield setup",
317
+ " npx -y @forcefield/forcefield dashboard start",
36
318
  "",
37
319
  "Direct runtime package path (equivalent):",
38
320
  " npx -y -p @forcefield/mcp-server forcefield setup"
@@ -42,7 +324,7 @@ function printUsage() {
42
324
  async function runForcefieldCli(argv = process.argv) {
43
325
  const { command, rest } = parseForcefieldCommand(argv);
44
326
  if (command === "help") {
45
- printUsage();
327
+ printUsage2();
46
328
  if (rest.length > 0) {
47
329
  process.exitCode = 1;
48
330
  }
@@ -52,6 +334,10 @@ async function runForcefieldCli(argv = process.argv) {
52
334
  await runMcpCli();
53
335
  return;
54
336
  }
337
+ if (command === "dashboard") {
338
+ await runDashboardCli(rest);
339
+ return;
340
+ }
55
341
  const setupArgv = ["node", "forcefield-setup"];
56
342
  if (command === "doctor") setupArgv.push("--doctor");
57
343
  if (command === "status") setupArgv.push("--status");
@@ -1 +1 @@
1
- {"version":3,"sources":["../../cli/index.ts"],"sourcesContent":["/**\n * Unified Forcefield CLI entrypoint.\n *\n * Gives users a single command surface:\n * forcefield setup\n * forcefield doctor\n * forcefield status\n * forcefield mcp\n */\n\nimport { pathToFileURL } from 'node:url';\nimport { runSetupCli } from '../setup/index.js';\nimport { runMcpCli } from '../src/index.js';\n\ntype ForcefieldCommand = 'setup' | 'doctor' | 'status' | 'mcp' | 'help';\n\nexport function parseForcefieldCommand(argv: string[]): { command: ForcefieldCommand; rest: string[] } {\n const cmd = argv[2];\n const rest = argv.slice(3);\n\n if (!cmd || cmd === 'setup') return { command: 'setup', rest };\n if (cmd === 'doctor') return { command: 'doctor', rest };\n if (cmd === 'status') return { command: 'status', rest };\n if (cmd === 'mcp') return { command: 'mcp', rest };\n if (cmd === 'help' || cmd === '--help' || cmd === '-h') return { command: 'help', rest };\n\n return { command: 'help', rest: [cmd, ...rest] };\n}\n\nfunction printUsage(): void {\n console.log(\n [\n 'Forcefield CLI',\n '',\n 'Usage:',\n ' forcefield setup Run interactive setup wizard',\n ' forcefield doctor Validate setup + MCP connectivity',\n ' forcefield status Show setup status in current project',\n ' forcefield mcp Start MCP server process (stdio)',\n ' forcefield help Show this help',\n '',\n 'One-off without global install:',\n ' npx -y forcefield setup',\n '',\n 'Direct runtime package path (equivalent):',\n ' npx -y -p @forcefield/mcp-server forcefield setup',\n ].join('\\n'),\n );\n}\n\nexport async function runForcefieldCli(argv: string[] = process.argv): Promise<void> {\n const { command, rest } = parseForcefieldCommand(argv);\n\n if (command === 'help') {\n printUsage();\n if (rest.length > 0) {\n process.exitCode = 1;\n }\n return;\n }\n\n if (command === 'mcp') {\n await runMcpCli();\n return;\n }\n\n const setupArgv = ['node', 'forcefield-setup'];\n if (command === 'doctor') setupArgv.push('--doctor');\n if (command === 'status') setupArgv.push('--status');\n setupArgv.push(...rest);\n await runSetupCli(setupArgv);\n}\n\nfunction isExecutedDirectly(metaUrl: string): boolean {\n const entryPath = process.argv[1];\n if (!entryPath) return false;\n return metaUrl === pathToFileURL(entryPath).href;\n}\n\nif (isExecutedDirectly(import.meta.url)) {\n void runForcefieldCli();\n}\n"],"mappings":";;;;;;;;;;AAUA,SAAS,qBAAqB;AAMvB,SAAS,uBAAuB,MAAgE;AACrG,QAAM,MAAM,KAAK,CAAC;AAClB,QAAM,OAAO,KAAK,MAAM,CAAC;AAEzB,MAAI,CAAC,OAAO,QAAQ,QAAS,QAAO,EAAE,SAAS,SAAS,KAAK;AAC7D,MAAI,QAAQ,SAAU,QAAO,EAAE,SAAS,UAAU,KAAK;AACvD,MAAI,QAAQ,SAAU,QAAO,EAAE,SAAS,UAAU,KAAK;AACvD,MAAI,QAAQ,MAAO,QAAO,EAAE,SAAS,OAAO,KAAK;AACjD,MAAI,QAAQ,UAAU,QAAQ,YAAY,QAAQ,KAAM,QAAO,EAAE,SAAS,QAAQ,KAAK;AAEvF,SAAO,EAAE,SAAS,QAAQ,MAAM,CAAC,KAAK,GAAG,IAAI,EAAE;AACjD;AAEA,SAAS,aAAmB;AAC1B,UAAQ;AAAA,IACN;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AACF;AAEA,eAAsB,iBAAiB,OAAiB,QAAQ,MAAqB;AACnF,QAAM,EAAE,SAAS,KAAK,IAAI,uBAAuB,IAAI;AAErD,MAAI,YAAY,QAAQ;AACtB,eAAW;AACX,QAAI,KAAK,SAAS,GAAG;AACnB,cAAQ,WAAW;AAAA,IACrB;AACA;AAAA,EACF;AAEA,MAAI,YAAY,OAAO;AACrB,UAAM,UAAU;AAChB;AAAA,EACF;AAEA,QAAM,YAAY,CAAC,QAAQ,kBAAkB;AAC7C,MAAI,YAAY,SAAU,WAAU,KAAK,UAAU;AACnD,MAAI,YAAY,SAAU,WAAU,KAAK,UAAU;AACnD,YAAU,KAAK,GAAG,IAAI;AACtB,QAAM,YAAY,SAAS;AAC7B;AAEA,SAAS,mBAAmB,SAA0B;AACpD,QAAM,YAAY,QAAQ,KAAK,CAAC;AAChC,MAAI,CAAC,UAAW,QAAO;AACvB,SAAO,YAAY,cAAc,SAAS,EAAE;AAC9C;AAEA,IAAI,mBAAmB,YAAY,GAAG,GAAG;AACvC,OAAK,iBAAiB;AACxB;","names":[]}
1
+ {"version":3,"sources":["../../cli/index.ts","../../cli/dashboard.ts"],"sourcesContent":["/**\n * Unified Forcefield CLI entrypoint.\n *\n * Gives users a single command surface:\n * forcefield setup\n * forcefield doctor\n * forcefield status\n * forcefield dashboard start\n * forcefield mcp\n */\n\nimport { pathToFileURL } from 'node:url';\nimport { runSetupCli } from '../setup/index.js';\nimport { runMcpCli } from '../src/index.js';\nimport { runDashboardCli } from './dashboard.js';\n\ntype ForcefieldCommand = 'setup' | 'doctor' | 'status' | 'dashboard' | 'mcp' | 'help';\n\nexport function parseForcefieldCommand(argv: string[]): { command: ForcefieldCommand; rest: string[] } {\n const cmd = argv[2];\n const rest = argv.slice(3);\n\n if (!cmd || cmd === 'setup') return { command: 'setup', rest };\n if (cmd === 'doctor') return { command: 'doctor', rest };\n if (cmd === 'status') return { command: 'status', rest };\n if (cmd === 'dashboard') return { command: 'dashboard', rest };\n if (cmd === 'mcp') return { command: 'mcp', rest };\n if (cmd === 'help' || cmd === '--help' || cmd === '-h') return { command: 'help', rest };\n\n return { command: 'help', rest: [cmd, ...rest] };\n}\n\nfunction printUsage(): void {\n console.log(\n [\n 'Forcefield CLI',\n '',\n 'Usage:',\n ' forcefield setup Run interactive setup wizard',\n ' forcefield doctor Validate setup + MCP connectivity',\n ' forcefield status Show setup status in current project',\n ' forcefield dashboard start Scaffold + run local dashboard (hosted backend by default)',\n ' forcefield mcp Start MCP server process (stdio)',\n ' forcefield help Show this help',\n '',\n 'One-off without global install:',\n ' npx -y @forcefield/forcefield setup',\n ' npx -y @forcefield/forcefield dashboard start',\n '',\n 'Direct runtime package path (equivalent):',\n ' npx -y -p @forcefield/mcp-server forcefield setup',\n ].join('\\n'),\n );\n}\n\nexport async function runForcefieldCli(argv: string[] = process.argv): Promise<void> {\n const { command, rest } = parseForcefieldCommand(argv);\n\n if (command === 'help') {\n printUsage();\n if (rest.length > 0) {\n process.exitCode = 1;\n }\n return;\n }\n\n if (command === 'mcp') {\n await runMcpCli();\n return;\n }\n\n if (command === 'dashboard') {\n await runDashboardCli(rest);\n return;\n }\n\n const setupArgv = ['node', 'forcefield-setup'];\n if (command === 'doctor') setupArgv.push('--doctor');\n if (command === 'status') setupArgv.push('--status');\n setupArgv.push(...rest);\n await runSetupCli(setupArgv);\n}\n\nfunction isExecutedDirectly(metaUrl: string): boolean {\n const entryPath = process.argv[1];\n if (!entryPath) return false;\n return metaUrl === pathToFileURL(entryPath).href;\n}\n\nif (isExecutedDirectly(import.meta.url)) {\n void runForcefieldCli();\n}\n","import { spawn } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { writeFile } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\nimport pc from 'picocolors';\nimport {\n LOCAL_SUPABASE_URL,\n PRODUCTION_SUPABASE_PUBLISHABLE_KEY,\n PRODUCTION_SUPABASE_URL,\n} from '../src/supabase-defaults.js';\n\nconst DEFAULT_DIR = './forcefield-dashboard';\n\nexport interface DashboardStartOptions {\n dir: string;\n local: boolean;\n force: boolean;\n install: boolean;\n run: boolean;\n}\n\ninterface DashboardCommand {\n type: 'start' | 'help';\n options: DashboardStartOptions;\n invalidCommand?: string;\n parseError?: string;\n}\n\ninterface DashboardEnv {\n supabaseUrl: string;\n anonKey: string;\n}\n\ninterface DashboardOps {\n scaffoldDashboard(targetDir: string, force: boolean): Promise<void>;\n getLocalEnv(): Promise<DashboardEnv>;\n installDependencies(targetDir: string): Promise<void>;\n startDevServer(targetDir: string): Promise<void>;\n}\n\nfunction npmCmd(): string {\n return process.platform === 'win32' ? 'npm.cmd' : 'npm';\n}\n\nfunction printUsage(): void {\n console.log(\n [\n 'Forcefield Dashboard',\n '',\n 'Usage:',\n ' forcefield dashboard start [--dir <path>] [--local] [--force] [--no-install] [--no-run]',\n ' forcefield dashboard --help',\n '',\n 'Examples:',\n ' forcefield dashboard start',\n ' forcefield dashboard start --dir ./dashboard',\n ' forcefield dashboard start --local --force',\n ].join('\\n'),\n );\n}\n\nexport function parseDashboardCommand(args: string[]): DashboardCommand {\n const defaultOptions: DashboardStartOptions = {\n dir: DEFAULT_DIR,\n local: false,\n force: false,\n install: true,\n run: true,\n };\n\n if (args.includes('--help') || args.includes('-h')) {\n return { type: 'help', options: defaultOptions };\n }\n\n const first = args[0];\n const isStart = !first || first === 'start';\n if (!isStart) {\n return {\n type: 'help',\n invalidCommand: first,\n options: defaultOptions,\n };\n }\n\n const optionArgs = first === 'start' ? args.slice(1) : args;\n const options = { ...defaultOptions };\n\n for (let i = 0; i < optionArgs.length; i += 1) {\n const arg = optionArgs[i];\n if (arg === '--dir' || arg === '-d') {\n const value = optionArgs[i + 1];\n if (!value || value.startsWith('-')) {\n return {\n type: 'help',\n parseError: 'Missing value for --dir.',\n options: defaultOptions,\n };\n }\n options.dir = value;\n i += 1;\n continue;\n }\n\n if (arg === '--local') {\n options.local = true;\n continue;\n }\n\n if (arg === '--force' || arg === '-f') {\n options.force = true;\n continue;\n }\n\n if (arg === '--no-install') {\n options.install = false;\n continue;\n }\n\n if (arg === '--no-run') {\n options.run = false;\n continue;\n }\n\n return {\n type: 'help',\n parseError: `Unknown option: ${arg}`,\n options: defaultOptions,\n };\n }\n\n return {\n type: 'start',\n options,\n };\n}\n\nasync function runProcess(\n command: string,\n args: string[],\n options?: { cwd?: string; capture?: boolean },\n): Promise<{ code: number; stdout: string; stderr: string }> {\n return new Promise((resolvePromise, rejectPromise) => {\n const child = spawn(command, args, {\n cwd: options?.cwd,\n env: process.env,\n stdio: options?.capture ? ['ignore', 'pipe', 'pipe'] : 'inherit',\n });\n\n let stdout = '';\n let stderr = '';\n\n if (options?.capture) {\n child.stdout.on('data', (chunk) => {\n stdout += String(chunk);\n });\n child.stderr.on('data', (chunk) => {\n stderr += String(chunk);\n });\n }\n\n child.on('error', (error) => {\n rejectPromise(error);\n });\n\n child.on('close', (code) => {\n resolvePromise({ code: code ?? 1, stdout, stderr });\n });\n });\n}\n\nfunction parseEnvAssignments(raw: string): Record<string, string> {\n const env: Record<string, string> = {};\n for (const line of raw.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const match = trimmed.match(/^(?:export\\s+)?([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);\n if (!match) continue;\n const key = match[1]!;\n let value = match[2] ?? '';\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n env[key] = value;\n }\n return env;\n}\n\nfunction formatManualFallback(targetDir: string, force: boolean): string {\n return [\n 'Manual fallback:',\n ` npx -y @forcefield/dashboard-template@beta init --dir ${targetDir}${force ? ' --force' : ''}`,\n ].join('\\n');\n}\n\nconst defaultOps: DashboardOps = {\n async scaffoldDashboard(targetDir, force) {\n const args = [\n 'exec',\n '--yes',\n '--package=@forcefield/dashboard-template@beta',\n 'forcefield-dashboard',\n '--',\n 'init',\n '--dir',\n targetDir,\n ];\n if (force) {\n args.push('--force');\n }\n\n try {\n const result = await runProcess(npmCmd(), args);\n if (result.code !== 0) {\n throw new Error(`Scaffold command exited with code ${result.code}.`);\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to scaffold dashboard automatically: ${message}\\n${formatManualFallback(targetDir, force)}`,\n );\n }\n },\n\n async getLocalEnv() {\n let result;\n try {\n result = await runProcess('supabase', ['status', '-o', 'env'], { capture: true });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Could not run 'supabase status -o env': ${message}. Install Supabase CLI and run ${pc.cyan('supabase start')}, or remove ${pc.cyan('--local')}.`,\n );\n }\n\n if (result.code !== 0) {\n const detail = (result.stderr || result.stdout).trim() || `exit code ${result.code}`;\n throw new Error(\n `Local Supabase is unavailable (${detail}). Run ${pc.cyan('supabase start')} first, or remove ${pc.cyan('--local')}.`,\n );\n }\n\n const env = parseEnvAssignments(result.stdout);\n const supabaseUrl = env.SUPABASE_URL || LOCAL_SUPABASE_URL;\n const anonKey = env.SUPABASE_ANON_KEY || env.ANON_KEY;\n\n if (!anonKey) {\n throw new Error(\n `Could not find an anon key from ${pc.cyan('supabase status -o env')}. Ensure local stack is running, or remove ${pc.cyan('--local')}.`,\n );\n }\n\n return { supabaseUrl, anonKey };\n },\n\n async installDependencies(targetDir) {\n const result = await runProcess(npmCmd(), ['install'], { cwd: targetDir });\n if (result.code !== 0) {\n throw new Error(`Dependency install failed (exit ${result.code}).`);\n }\n },\n\n async startDevServer(targetDir) {\n const result = await runProcess(npmCmd(), ['run', 'dev'], { cwd: targetDir });\n if (result.code !== 0) {\n throw new Error(`Dashboard dev server exited with code ${result.code}.`);\n }\n },\n};\n\nasync function writeDashboardEnv(\n targetDir: string,\n env: DashboardEnv,\n force: boolean,\n): Promise<{ path: string; wrote: boolean }> {\n const envPath = join(targetDir, '.env.local');\n\n if (existsSync(envPath) && !force) {\n return { path: envPath, wrote: false };\n }\n\n const content = [\n `NEXT_PUBLIC_SUPABASE_URL=${env.supabaseUrl}`,\n `NEXT_PUBLIC_SUPABASE_ANON_KEY=${env.anonKey}`,\n '',\n ].join('\\n');\n\n await writeFile(envPath, content, 'utf-8');\n return { path: envPath, wrote: true };\n}\n\nexport async function runDashboardStart(\n options: DashboardStartOptions,\n ops: DashboardOps = defaultOps,\n): Promise<void> {\n const targetDir = resolve(process.cwd(), options.dir);\n\n console.log(pc.bold('Forcefield Dashboard Bootstrap'));\n console.log(`Target: ${pc.cyan(targetDir)}`);\n\n await ops.scaffoldDashboard(targetDir, options.force);\n\n const env = options.local\n ? await ops.getLocalEnv()\n : {\n supabaseUrl: PRODUCTION_SUPABASE_URL,\n anonKey: PRODUCTION_SUPABASE_PUBLISHABLE_KEY,\n };\n\n const envWrite = await writeDashboardEnv(targetDir, env, options.force);\n if (envWrite.wrote) {\n console.log(`${pc.green('✓')} Wrote ${pc.cyan(envWrite.path)} (${options.local ? 'local' : 'hosted'} backend).`);\n } else {\n console.log(`${pc.yellow('•')} Preserved existing ${pc.cyan(envWrite.path)} (use ${pc.cyan('--force')} to overwrite).`);\n }\n\n if (options.install) {\n console.log(`${pc.dim('→')} Installing dashboard dependencies...`);\n await ops.installDependencies(targetDir);\n } else {\n console.log(`${pc.yellow('•')} Skipped dependency install (${pc.cyan('--no-install')}).`);\n }\n\n if (options.run) {\n console.log(`${pc.dim('→')} Starting dashboard dev server...`);\n console.log(pc.dim('Press Ctrl+C to stop.'));\n await ops.startDevServer(targetDir);\n return;\n }\n\n console.log(`${pc.yellow('•')} Skipped dev server startup (${pc.cyan('--no-run')}).`);\n console.log('');\n console.log('Next steps:');\n console.log(` cd ${targetDir}`);\n if (!options.install) {\n console.log(' npm install');\n }\n console.log(' npm run dev');\n console.log('');\n console.log('Then open http://localhost:3000 and sign in.');\n}\n\nexport async function runDashboardCli(args: string[]): Promise<void> {\n const parsed = parseDashboardCommand(args);\n\n if (parsed.type === 'help') {\n if (parsed.invalidCommand) {\n console.error(pc.red(`Unknown dashboard subcommand: ${parsed.invalidCommand}`));\n }\n if (parsed.parseError) {\n console.error(pc.red(parsed.parseError));\n }\n printUsage();\n if (parsed.invalidCommand || parsed.parseError) {\n process.exitCode = 1;\n }\n return;\n }\n\n await runDashboardStart(parsed.options);\n}\n\nexport { parseEnvAssignments };\n"],"mappings":"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","names":["printUsage"]}
package/build/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runMcpCli
4
- } from "./chunk-7XLGRGP6.js";
5
- import "./chunk-6YANB5QT.js";
4
+ } from "./chunk-K464TYAJ.js";
5
+ import "./chunk-UOMOGP46.js";
6
6
  export {
7
7
  runMcpCli
8
8
  };
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  parseArgs,
4
4
  runSetupCli
5
- } from "../chunk-4FKA7CA3.js";
6
- import "../chunk-6YANB5QT.js";
5
+ } from "../chunk-DGBLHABK.js";
6
+ import "../chunk-UOMOGP46.js";
7
7
  export {
8
8
  parseArgs,
9
9
  runSetupCli
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forcefield/mcp-server",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "AI-powered corporate compliance MCP server",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -116,7 +116,7 @@ Based on the compliance state, suggest the most relevant next action:
116
116
  - This workflow has **no prerequisites** — it works even before onboarding
117
117
  - Primary entrypoint is `/ff-onboard`. `/ff-start` is optional for troubleshooting/connection checks.
118
118
  - If `ff_system(action: "health")` fails, show the command reference only and suggest:
119
- 1. run `forcefield-setup` in terminal
119
+ 1. run `forcefield setup` in terminal
120
120
  2. restart/reload coding agent chat
121
121
  3. run `/mcp` in Claude Code and confirm `forcefield` is connected
122
122
  - Check whether suggested commands are implemented before showing them. If a command is not yet available, append "(coming soon)" to its description
@@ -36,7 +36,7 @@ Call `ff_system(action: "health")`.
36
36
  If health fails, show this exact recovery flow:
37
37
 
38
38
  1. "Open a terminal in your project repo."
39
- 2. "Run `forcefield-setup`."
39
+ 2. "Run `forcefield setup`."
40
40
  3. "Restart/reload your coding agent chat."
41
41
  4. "In Claude Code, run `/mcp` and confirm `forcefield` is connected."
42
42
  5. "Run `/ff-start` again."