farseer-cli 1.0.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 +15 -0
- package/README.md +741 -0
- package/dist/commands/app.d.ts +2 -0
- package/dist/commands/app.js +349 -0
- package/dist/commands/app.js.map +7 -0
- package/dist/commands/apps.d.ts +2 -0
- package/dist/commands/apps.js +111 -0
- package/dist/commands/apps.js.map +7 -0
- package/dist/commands/checkout.d.ts +2 -0
- package/dist/commands/checkout.js +166 -0
- package/dist/commands/checkout.js.map +7 -0
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.js +139 -0
- package/dist/commands/config.js.map +7 -0
- package/dist/commands/diff.d.ts +2 -0
- package/dist/commands/diff.js +183 -0
- package/dist/commands/diff.js.map +7 -0
- package/dist/commands/files.js +99 -0
- package/dist/commands/files.js.map +7 -0
- package/dist/commands/install.d.ts +2 -0
- package/dist/commands/install.js +79 -0
- package/dist/commands/install.js.map +7 -0
- package/dist/commands/list.d.ts +2 -0
- package/dist/commands/list.js +92 -0
- package/dist/commands/list.js.map +7 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +134 -0
- package/dist/commands/login.js.map +7 -0
- package/dist/commands/logout.d.ts +2 -0
- package/dist/commands/logout.js +59 -0
- package/dist/commands/logout.js.map +7 -0
- package/dist/commands/mcp-server.d.ts +8 -0
- package/dist/commands/mcp-server.js +41 -0
- package/dist/commands/mcp-server.js.map +7 -0
- package/dist/commands/model.d.ts +2 -0
- package/dist/commands/model.js +189 -0
- package/dist/commands/model.js.map +7 -0
- package/dist/commands/pull.d.ts +2 -0
- package/dist/commands/pull.js +287 -0
- package/dist/commands/pull.js.map +7 -0
- package/dist/commands/push.d.ts +2 -0
- package/dist/commands/push.js +251 -0
- package/dist/commands/push.js.map +7 -0
- package/dist/commands/run.d.ts +2 -0
- package/dist/commands/run.js +246 -0
- package/dist/commands/run.js.map +7 -0
- package/dist/commands/setup.d.ts +2 -0
- package/dist/commands/setup.js +137 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.js +145 -0
- package/dist/commands/status.js.map +7 -0
- package/dist/commands/unsetup.d.ts +2 -0
- package/dist/commands/unsetup.js +122 -0
- package/dist/commands/whoami.d.ts +2 -0
- package/dist/commands/whoami.js +63 -0
- package/dist/commands/whoami.js.map +7 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +135 -0
- package/dist/index.js.map +7 -0
- package/dist/mcp/index.d.ts +7 -0
- package/dist/mcp/index.js +35 -0
- package/dist/mcp/index.js.map +7 -0
- package/dist/mcp/prompts/workflows.d.ts +7 -0
- package/dist/mcp/prompts/workflows.js +374 -0
- package/dist/mcp/prompts/workflows.js.map +7 -0
- package/dist/mcp/resources/documentation.d.ts +8 -0
- package/dist/mcp/resources/documentation.js +167 -0
- package/dist/mcp/resources/documentation.js.map +7 -0
- package/dist/mcp/server.d.ts +7 -0
- package/dist/mcp/server.js +49 -0
- package/dist/mcp/server.js.map +7 -0
- package/dist/mcp/tools/appTools.d.ts +7 -0
- package/dist/mcp/tools/appTools.js +377 -0
- package/dist/mcp/tools/appTools.js.map +7 -0
- package/dist/mcp/tools/authTools.d.ts +7 -0
- package/dist/mcp/tools/authTools.js +158 -0
- package/dist/mcp/tools/authTools.js.map +7 -0
- package/dist/mcp/tools/modelTools.d.ts +7 -0
- package/dist/mcp/tools/modelTools.js +331 -0
- package/dist/mcp/tools/modelTools.js.map +7 -0
- package/dist/mcp/tools/runTools.d.ts +7 -0
- package/dist/mcp/tools/runTools.js +231 -0
- package/dist/mcp/tools/runTools.js.map +7 -0
- package/dist/mcp/tools/syncTools.d.ts +7 -0
- package/dist/mcp/tools/syncTools.js +382 -0
- package/dist/mcp/tools/syncTools.js.map +7 -0
- package/dist/mcp/utils/helpers.d.ts +69 -0
- package/dist/mcp/utils/helpers.js +113 -0
- package/dist/mcp/utils/helpers.js.map +7 -0
- package/dist/services/appSyncService.d.ts +75 -0
- package/dist/services/appSyncService.js +370 -0
- package/dist/services/appSyncService.js.map +7 -0
- package/dist/services/configService.d.ts +39 -0
- package/dist/services/configService.js +196 -0
- package/dist/services/configService.js.map +7 -0
- package/dist/services/farseerApi.d.ts +166 -0
- package/dist/services/farseerApi.js +378 -0
- package/dist/services/farseerApi.js.map +7 -0
- package/dist/services/farseerFactory.d.ts +88 -0
- package/dist/services/farseerFactory.js +179 -0
- package/dist/services/farseerFactory.js.map +7 -0
- package/dist/services/farseerService.d.ts +96 -0
- package/dist/services/farseerService.js +614 -0
- package/dist/services/farseerService.js.map +7 -0
- package/dist/services/gitService.d.ts +31 -0
- package/dist/services/gitService.js +134 -0
- package/dist/services/gitService.js.map +7 -0
- package/dist/services/syncService.d.ts +44 -0
- package/dist/services/syncService.js +320 -0
- package/dist/services/syncService.js.map +7 -0
- package/dist/utils/constants.d.ts +7 -0
- package/dist/utils/constants.js +46 -0
- package/dist/utils/constants.js.map +7 -0
- package/dist/utils/helpers.d.ts +69 -0
- package/dist/utils/helpers.js +413 -0
- package/dist/utils/helpers.js.map +7 -0
- package/dist/utils/logger.d.ts +14 -0
- package/dist/utils/logger.js +76 -0
- package/dist/utils/logger.js.map +7 -0
- package/package.json +62 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
24
|
+
var import_commander = require("commander");
|
|
25
|
+
var import_chalk = __toESM(require("chalk"));
|
|
26
|
+
var import_login = require("./commands/login");
|
|
27
|
+
var import_logout = require("./commands/logout");
|
|
28
|
+
var import_config = require("./commands/config");
|
|
29
|
+
var import_list = require("./commands/list");
|
|
30
|
+
var import_files = require("./commands/files");
|
|
31
|
+
var import_status = require("./commands/status");
|
|
32
|
+
var import_diff = require("./commands/diff");
|
|
33
|
+
var import_pull = require("./commands/pull");
|
|
34
|
+
var import_push = require("./commands/push");
|
|
35
|
+
var import_run = require("./commands/run");
|
|
36
|
+
var import_install = require("./commands/install");
|
|
37
|
+
var import_whoami = require("./commands/whoami");
|
|
38
|
+
var import_app = require("./commands/app");
|
|
39
|
+
var import_model = require("./commands/model");
|
|
40
|
+
var import_checkout = require("./commands/checkout");
|
|
41
|
+
var import_mcp_server = require("./commands/mcp-server");
|
|
42
|
+
const originalEmit = process.emit;
|
|
43
|
+
process.emit = function(name, data, ...args) {
|
|
44
|
+
if (name === "warning" && typeof data === "object" && data !== null && "name" in data && data.name === "DeprecationWarning" && "message" in data && typeof data.message === "string" && data.message.includes("punycode")) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
return originalEmit.apply(process, [name, data, ...args]);
|
|
48
|
+
};
|
|
49
|
+
const program = new import_commander.Command();
|
|
50
|
+
program.configureHelp({
|
|
51
|
+
visibleCommands: () => []
|
|
52
|
+
// Hide all commands from default list
|
|
53
|
+
});
|
|
54
|
+
program.name("farseer").description("CLI tool for syncing Farseer App scripts between local repository and Farseer instances").version("1.0.0").addHelpText("after", `
|
|
55
|
+
${import_chalk.default.bold.underline("Authentication")}
|
|
56
|
+
login Login via browser (OAuth) or use --api-key
|
|
57
|
+
logout [tenant] Logout and remove credentials
|
|
58
|
+
whoami Show login status and configured tenants
|
|
59
|
+
checkout [tenant] Set default tenant (verifies auth & pulls)
|
|
60
|
+
${import_chalk.default.dim("--no-pull")} Skip automatic pull
|
|
61
|
+
|
|
62
|
+
${import_chalk.default.bold.underline("Configuration")} ${import_chalk.default.dim("(farseer config <command>)")}
|
|
63
|
+
config set <tenant> Set API key for a tenant
|
|
64
|
+
${import_chalk.default.dim("--api-key <key>")} API key (required)
|
|
65
|
+
${import_chalk.default.dim("--org <name>")} Organisation if different from tenant
|
|
66
|
+
config remove <tenant> Remove credentials
|
|
67
|
+
config list List all configured tenants
|
|
68
|
+
config show <tenant> Show full credentials (incl. API key)
|
|
69
|
+
config test <tenant> Test connection to tenant
|
|
70
|
+
|
|
71
|
+
${import_chalk.default.bold.underline("Sync Operations")} ${import_chalk.default.dim("(tenant optional if checked out)")}
|
|
72
|
+
pull [tenant] Pull files and apps from remote
|
|
73
|
+
${import_chalk.default.dim("--no-git")} Skip git operations
|
|
74
|
+
${import_chalk.default.dim("--all")} Download all files (not just .ts/.js)
|
|
75
|
+
push [tenant] Push local changes to remote
|
|
76
|
+
${import_chalk.default.dim("-m, --message <msg>")} Commit message (required)
|
|
77
|
+
${import_chalk.default.dim("--no-git")} Skip git operations
|
|
78
|
+
status [tenant] Show sync status (local vs remote)
|
|
79
|
+
${import_chalk.default.dim("--all")} Show all files (not just .ts/.js)
|
|
80
|
+
diff [tenant] [file] Show file differences
|
|
81
|
+
|
|
82
|
+
${import_chalk.default.bold.underline("App Management")} ${import_chalk.default.dim("(tenant optional if checked out)")}
|
|
83
|
+
app list [tenant] List all apps
|
|
84
|
+
${import_chalk.default.dim("--details")} Show details for each app
|
|
85
|
+
app show [tenant] <name> Show app details
|
|
86
|
+
app create [tenant] <name> Create new app
|
|
87
|
+
app configure [tenant] <name> Configure app
|
|
88
|
+
${import_chalk.default.dim("--entrypoint <script>")} Set main script
|
|
89
|
+
${import_chalk.default.dim("--scripts <list>")} Comma-separated scripts
|
|
90
|
+
${import_chalk.default.dim("--add-arg <Name=Value>")} Add argument (repeatable)
|
|
91
|
+
${import_chalk.default.dim("--description <text>")} Set description
|
|
92
|
+
app delete [tenant] <name> Delete app (requires --force)
|
|
93
|
+
|
|
94
|
+
${import_chalk.default.bold.underline("Running & Development")} ${import_chalk.default.dim("(tenant optional if checked out)")}
|
|
95
|
+
run [tenant] <app> Run app locally with injected credentials
|
|
96
|
+
${import_chalk.default.dim("--arg <Name=Value>")} Override argument (repeatable)
|
|
97
|
+
run-script [tenant] <file> Run script directly (no app wrapper)
|
|
98
|
+
install [tenant] Install npm dependencies (npm install)
|
|
99
|
+
|
|
100
|
+
${import_chalk.default.bold.underline("Model Inspection")} ${import_chalk.default.dim("(tenant optional if checked out)")}
|
|
101
|
+
model [tenant] Show model structure (dimensions, variables)
|
|
102
|
+
${import_chalk.default.dim("--variables")} List all variables
|
|
103
|
+
${import_chalk.default.dim("--tables")} List all dimension tables
|
|
104
|
+
${import_chalk.default.dim("--variable <name>")} Show dimensions for variable
|
|
105
|
+
|
|
106
|
+
${import_chalk.default.bold.underline("File Management")} ${import_chalk.default.dim("(farseer files <command>)")}
|
|
107
|
+
files list [tenant] List files on remote
|
|
108
|
+
${import_chalk.default.dim("--all")} Show all files (not just scripts)
|
|
109
|
+
|
|
110
|
+
${import_chalk.default.bold.underline("Examples")}
|
|
111
|
+
${import_chalk.default.green("$")} farseer login ${import_chalk.default.dim("Login via browser")}
|
|
112
|
+
${import_chalk.default.green("$")} farseer config set myco --api-key xxx ${import_chalk.default.dim("Add tenant with API key")}
|
|
113
|
+
${import_chalk.default.green("$")} farseer pull mycompany --no-git ${import_chalk.default.dim("Download scripts & apps")}
|
|
114
|
+
${import_chalk.default.green("$")} farseer push mycompany -m "Fix bug" ${import_chalk.default.dim("Upload changes")}
|
|
115
|
+
${import_chalk.default.green("$")} farseer run mycompany "My App" ${import_chalk.default.dim("Run app locally")}
|
|
116
|
+
${import_chalk.default.green("$")} farseer model mycompany --variables ${import_chalk.default.dim("List all variables")}
|
|
117
|
+
`);
|
|
118
|
+
(0, import_login.registerLoginCommand)(program);
|
|
119
|
+
(0, import_logout.registerLogoutCommand)(program);
|
|
120
|
+
(0, import_checkout.registerCheckoutCommand)(program);
|
|
121
|
+
(0, import_config.registerConfigCommand)(program);
|
|
122
|
+
(0, import_list.registerListCommand)(program);
|
|
123
|
+
(0, import_files.registerFilesCommand)(program);
|
|
124
|
+
(0, import_app.registerAppCommand)(program);
|
|
125
|
+
(0, import_model.registerModelCommand)(program);
|
|
126
|
+
(0, import_status.registerStatusCommand)(program);
|
|
127
|
+
(0, import_diff.registerDiffCommand)(program);
|
|
128
|
+
(0, import_pull.registerPullCommand)(program);
|
|
129
|
+
(0, import_push.registerPushCommand)(program);
|
|
130
|
+
(0, import_run.registerRunCommand)(program);
|
|
131
|
+
(0, import_install.registerInstallCommand)(program);
|
|
132
|
+
(0, import_whoami.registerWhoamiCommand)(program);
|
|
133
|
+
(0, import_mcp_server.registerMcpServerCommand)(program);
|
|
134
|
+
program.parse();
|
|
135
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["#!/usr/bin/env node\n\n// Suppress punycode deprecation warning (comes from dependencies like axios)\nconst originalEmit = process.emit;\n// @ts-expect-error - overriding process.emit\nprocess.emit = function (name: string, data: unknown, ...args: unknown[]) {\n if (name === 'warning' && typeof data === 'object' && data !== null && 'name' in data && data.name === 'DeprecationWarning' && 'message' in data && typeof data.message === 'string' && data.message.includes('punycode')) {\n return false;\n }\n // @ts-expect-error - calling original emit\n return originalEmit.apply(process, [name, data, ...args]);\n};\n\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport { registerLoginCommand } from './commands/login';\nimport { registerLogoutCommand } from './commands/logout';\nimport { registerConfigCommand } from './commands/config';\nimport { registerListCommand } from './commands/list';\nimport { registerFilesCommand } from './commands/files';\nimport { registerStatusCommand } from './commands/status';\nimport { registerDiffCommand } from './commands/diff';\nimport { registerPullCommand } from './commands/pull';\nimport { registerPushCommand } from './commands/push';\nimport { registerRunCommand } from './commands/run';\nimport { registerInstallCommand } from './commands/install';\nimport { registerWhoamiCommand } from './commands/whoami';\nimport { registerAppCommand } from './commands/app';\nimport { registerModelCommand } from './commands/model';\nimport { registerCheckoutCommand } from './commands/checkout';\nimport { registerMcpServerCommand } from './commands/mcp-server';\n\nconst program = new Command();\n\n// Configure help to hide default command list (we show our own custom list)\nprogram.configureHelp({\n visibleCommands: () => [], // Hide all commands from default list\n});\n\nprogram\n .name('farseer')\n .description('CLI tool for syncing Farseer App scripts between local repository and Farseer instances')\n .version('1.0.0')\n .addHelpText('after', `\n${chalk.bold.underline('Authentication')}\n login Login via browser (OAuth) or use --api-key\n logout [tenant] Logout and remove credentials\n whoami Show login status and configured tenants\n checkout [tenant] Set default tenant (verifies auth & pulls)\n ${chalk.dim('--no-pull')} Skip automatic pull\n\n${chalk.bold.underline('Configuration')} ${chalk.dim('(farseer config <command>)')}\n config set <tenant> Set API key for a tenant\n ${chalk.dim('--api-key <key>')} API key (required)\n ${chalk.dim('--org <name>')} Organisation if different from tenant\n config remove <tenant> Remove credentials\n config list List all configured tenants\n config show <tenant> Show full credentials (incl. API key)\n config test <tenant> Test connection to tenant\n\n${chalk.bold.underline('Sync Operations')} ${chalk.dim('(tenant optional if checked out)')}\n pull [tenant] Pull files and apps from remote\n ${chalk.dim('--no-git')} Skip git operations\n ${chalk.dim('--all')} Download all files (not just .ts/.js)\n push [tenant] Push local changes to remote\n ${chalk.dim('-m, --message <msg>')} Commit message (required)\n ${chalk.dim('--no-git')} Skip git operations\n status [tenant] Show sync status (local vs remote)\n ${chalk.dim('--all')} Show all files (not just .ts/.js)\n diff [tenant] [file] Show file differences\n\n${chalk.bold.underline('App Management')} ${chalk.dim('(tenant optional if checked out)')}\n app list [tenant] List all apps\n ${chalk.dim('--details')} Show details for each app\n app show [tenant] <name> Show app details\n app create [tenant] <name> Create new app\n app configure [tenant] <name> Configure app\n ${chalk.dim('--entrypoint <script>')} Set main script\n ${chalk.dim('--scripts <list>')} Comma-separated scripts\n ${chalk.dim('--add-arg <Name=Value>')} Add argument (repeatable)\n ${chalk.dim('--description <text>')} Set description\n app delete [tenant] <name> Delete app (requires --force)\n\n${chalk.bold.underline('Running & Development')} ${chalk.dim('(tenant optional if checked out)')}\n run [tenant] <app> Run app locally with injected credentials\n ${chalk.dim('--arg <Name=Value>')} Override argument (repeatable)\n run-script [tenant] <file> Run script directly (no app wrapper)\n install [tenant] Install npm dependencies (npm install)\n\n${chalk.bold.underline('Model Inspection')} ${chalk.dim('(tenant optional if checked out)')}\n model [tenant] Show model structure (dimensions, variables)\n ${chalk.dim('--variables')} List all variables\n ${chalk.dim('--tables')} List all dimension tables\n ${chalk.dim('--variable <name>')} Show dimensions for variable\n\n${chalk.bold.underline('File Management')} ${chalk.dim('(farseer files <command>)')}\n files list [tenant] List files on remote\n ${chalk.dim('--all')} Show all files (not just scripts)\n\n${chalk.bold.underline('Examples')}\n ${chalk.green('$')} farseer login ${chalk.dim('Login via browser')}\n ${chalk.green('$')} farseer config set myco --api-key xxx ${chalk.dim('Add tenant with API key')}\n ${chalk.green('$')} farseer pull mycompany --no-git ${chalk.dim('Download scripts & apps')}\n ${chalk.green('$')} farseer push mycompany -m \"Fix bug\" ${chalk.dim('Upload changes')}\n ${chalk.green('$')} farseer run mycompany \"My App\" ${chalk.dim('Run app locally')}\n ${chalk.green('$')} farseer model mycompany --variables ${chalk.dim('List all variables')}\n`);\n\n// Register all commands (hidden from default help, shown in custom help above)\nregisterLoginCommand(program);\nregisterLogoutCommand(program);\nregisterCheckoutCommand(program);\nregisterConfigCommand(program);\nregisterListCommand(program);\nregisterFilesCommand(program);\nregisterAppCommand(program);\nregisterModelCommand(program);\nregisterStatusCommand(program);\nregisterDiffCommand(program);\nregisterPullCommand(program);\nregisterPushCommand(program);\nregisterRunCommand(program);\nregisterInstallCommand(program);\nregisterWhoamiCommand(program);\nregisterMcpServerCommand(program);\n\n// Parse arguments\nprogram.parse();\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["chalk"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var mcp_exports = {};
|
|
19
|
+
__export(mcp_exports, {
|
|
20
|
+
startMcpServer: () => startMcpServer
|
|
21
|
+
});
|
|
22
|
+
module.exports = __toCommonJS(mcp_exports);
|
|
23
|
+
var import_server = require("./server");
|
|
24
|
+
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
25
|
+
async function startMcpServer() {
|
|
26
|
+
const server = (0, import_server.createMcpServer)();
|
|
27
|
+
const transport = new import_stdio.StdioServerTransport();
|
|
28
|
+
await server.connect(transport);
|
|
29
|
+
console.error("Farseer MCP server started");
|
|
30
|
+
}
|
|
31
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
32
|
+
0 && (module.exports = {
|
|
33
|
+
startMcpServer
|
|
34
|
+
});
|
|
35
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/mcp/index.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * MCP Server Entry Point\n *\n * Starts the Farseer MCP server for AI assistant integration.\n * Uses stdio transport for CLI compatibility.\n */\n\nimport { createMcpServer } from './server';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\n\nexport async function startMcpServer(): Promise<void> {\n const server = createMcpServer();\n\n // Use stdio transport for CLI integration\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n // Log to stderr since stdout is reserved for MCP protocol\n console.error('Farseer MCP server started');\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,oBAAgC;AAChC,mBAAqC;AAErC,eAAsB,iBAAgC;AAClD,QAAM,aAAS,+BAAgB;AAG/B,QAAM,YAAY,IAAI,kCAAqB;AAC3C,QAAM,OAAO,QAAQ,SAAS;AAG9B,UAAQ,MAAM,4BAA4B;AAC9C;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var workflows_exports = {};
|
|
19
|
+
__export(workflows_exports, {
|
|
20
|
+
registerWorkflowPrompts: () => registerWorkflowPrompts
|
|
21
|
+
});
|
|
22
|
+
module.exports = __toCommonJS(workflows_exports);
|
|
23
|
+
var import_zod = require("zod");
|
|
24
|
+
const setupTenantSchema = {
|
|
25
|
+
tenant: import_zod.z.string().describe("Tenant name to setup")
|
|
26
|
+
};
|
|
27
|
+
const createAppSchema = {
|
|
28
|
+
tenant: import_zod.z.string().describe("Tenant name"),
|
|
29
|
+
appName: import_zod.z.string().describe("Name for the new app"),
|
|
30
|
+
scriptName: import_zod.z.string().optional().describe("Main script filename (default: index.ts)")
|
|
31
|
+
};
|
|
32
|
+
const understandModelSchema = {
|
|
33
|
+
tenant: import_zod.z.string().describe("Tenant name")
|
|
34
|
+
};
|
|
35
|
+
const writeImportScriptSchema = {
|
|
36
|
+
tenant: import_zod.z.string().describe("Tenant name"),
|
|
37
|
+
variableName: import_zod.z.string().describe("Target variable to import into")
|
|
38
|
+
};
|
|
39
|
+
const copyAppSchema = {
|
|
40
|
+
tenant: import_zod.z.string().describe("Tenant name"),
|
|
41
|
+
sourceApp: import_zod.z.string().describe("Name of app to copy"),
|
|
42
|
+
newAppName: import_zod.z.string().describe("Name for the new app")
|
|
43
|
+
};
|
|
44
|
+
const debugSyncSchema = {
|
|
45
|
+
tenant: import_zod.z.string().describe("Tenant name")
|
|
46
|
+
};
|
|
47
|
+
function registerWorkflowPrompts(server) {
|
|
48
|
+
const anyServer = server;
|
|
49
|
+
anyServer.prompt(
|
|
50
|
+
"setup_new_tenant",
|
|
51
|
+
"Guide for setting up a new Farseer tenant: login, checkout, pull, install dependencies.",
|
|
52
|
+
setupTenantSchema,
|
|
53
|
+
async (params) => {
|
|
54
|
+
const { tenant } = params;
|
|
55
|
+
return {
|
|
56
|
+
messages: [
|
|
57
|
+
{
|
|
58
|
+
role: "user",
|
|
59
|
+
content: {
|
|
60
|
+
type: "text",
|
|
61
|
+
text: `You are setting up a new Farseer tenant "${tenant}".
|
|
62
|
+
|
|
63
|
+
Steps to follow:
|
|
64
|
+
|
|
65
|
+
1. First, check authentication status with farseer_whoami
|
|
66
|
+
2. If not logged in, inform the user to run "farseer login" in terminal (MCP cannot do browser login)
|
|
67
|
+
3. Use farseer_checkout to set "${tenant}" as the default tenant (this also pulls files and apps)
|
|
68
|
+
4. Tell user to run "farseer install ${tenant}" in terminal to install npm dependencies
|
|
69
|
+
5. Use farseer_list_apps to show available apps
|
|
70
|
+
6. Use farseer_export_model to understand the data structure
|
|
71
|
+
|
|
72
|
+
After setup, the user can:
|
|
73
|
+
- Run apps with farseer_run_app
|
|
74
|
+
- Edit scripts in apps/${tenant}/files/Scripts/
|
|
75
|
+
- Push changes with farseer_push
|
|
76
|
+
- Check model with farseer_get_variable or farseer_get_table`
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
anyServer.prompt(
|
|
84
|
+
"create_new_app",
|
|
85
|
+
"Guide for creating a new Farseer app from scratch.",
|
|
86
|
+
createAppSchema,
|
|
87
|
+
async (params) => {
|
|
88
|
+
const { tenant, appName, scriptName } = params;
|
|
89
|
+
const script = scriptName || "index.ts";
|
|
90
|
+
return {
|
|
91
|
+
messages: [
|
|
92
|
+
{
|
|
93
|
+
role: "user",
|
|
94
|
+
content: {
|
|
95
|
+
type: "text",
|
|
96
|
+
text: `Creating a new Farseer app "${appName}" for tenant "${tenant}".
|
|
97
|
+
|
|
98
|
+
Steps to follow:
|
|
99
|
+
|
|
100
|
+
1. Check if the script "${script}" exists with farseer_status
|
|
101
|
+
2. If script doesn't exist locally:
|
|
102
|
+
- Create the script file at apps/${tenant}/files/Scripts/${script}
|
|
103
|
+
- Push with farseer_push
|
|
104
|
+
|
|
105
|
+
3. Use farseer_create_app to create the app named "${appName}"
|
|
106
|
+
|
|
107
|
+
4. Use farseer_configure_app to set:
|
|
108
|
+
- entrypoint: "${script}"
|
|
109
|
+
- scripts: ["${script}"]
|
|
110
|
+
- Add arguments if needed
|
|
111
|
+
|
|
112
|
+
5. Test with farseer_run_app
|
|
113
|
+
|
|
114
|
+
Script template to create:
|
|
115
|
+
\`\`\`typescript
|
|
116
|
+
import * as farseer from 'farseer-client';
|
|
117
|
+
|
|
118
|
+
const args = process.argv.slice(2);
|
|
119
|
+
console.log('Arguments:', args);
|
|
120
|
+
|
|
121
|
+
const client = new farseer.FarseerClient();
|
|
122
|
+
|
|
123
|
+
async function main() {
|
|
124
|
+
await client.initTagMap();
|
|
125
|
+
|
|
126
|
+
// Your code here
|
|
127
|
+
console.log('App running successfully');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
main().catch(farseer.handleUnknownError);
|
|
131
|
+
\`\`\``
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
]
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
);
|
|
138
|
+
anyServer.prompt(
|
|
139
|
+
"understand_model",
|
|
140
|
+
"Explore and understand the data model of a Farseer tenant.",
|
|
141
|
+
understandModelSchema,
|
|
142
|
+
async (params) => {
|
|
143
|
+
const { tenant } = params;
|
|
144
|
+
return {
|
|
145
|
+
messages: [
|
|
146
|
+
{
|
|
147
|
+
role: "user",
|
|
148
|
+
content: {
|
|
149
|
+
type: "text",
|
|
150
|
+
text: `Analyzing the data model for tenant "${tenant}".
|
|
151
|
+
|
|
152
|
+
Steps to follow:
|
|
153
|
+
|
|
154
|
+
1. Use farseer_export_model to get the full model structure
|
|
155
|
+
|
|
156
|
+
2. Review dimension tables:
|
|
157
|
+
- Use farseer_list_tables for overview
|
|
158
|
+
- Key dimensions usually include: Products, Regions, Time (Months, Years), Versions
|
|
159
|
+
- Check foreign key relationships between tables
|
|
160
|
+
|
|
161
|
+
3. Review variables:
|
|
162
|
+
- Use farseer_list_variables for overview
|
|
163
|
+
- Use farseer_get_variable for specific variable details
|
|
164
|
+
- Note which dimensions each variable has
|
|
165
|
+
|
|
166
|
+
4. For import scripts, you need to know:
|
|
167
|
+
- Target variable name
|
|
168
|
+
- All dimensions the variable has
|
|
169
|
+
- Valid members for each dimension
|
|
170
|
+
|
|
171
|
+
Key concepts:
|
|
172
|
+
- Dimensions structure the data (Product, Region, Month, Year, Version)
|
|
173
|
+
- Variables store values at dimension intersections
|
|
174
|
+
- Formulas calculate values automatically
|
|
175
|
+
- Roll-up types determine aggregation (SUM, AVERAGE, etc.)
|
|
176
|
+
|
|
177
|
+
Common dimension tables:
|
|
178
|
+
- Months, Years (time)
|
|
179
|
+
- Versions (Plan, Actual, Forecast)
|
|
180
|
+
- Products, Categories, Brands
|
|
181
|
+
- Regions, Entities, Cost Centers`
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
);
|
|
188
|
+
anyServer.prompt(
|
|
189
|
+
"write_import_script",
|
|
190
|
+
"Guide for writing a data import script.",
|
|
191
|
+
writeImportScriptSchema,
|
|
192
|
+
async (params) => {
|
|
193
|
+
const { tenant, variableName } = params;
|
|
194
|
+
return {
|
|
195
|
+
messages: [
|
|
196
|
+
{
|
|
197
|
+
role: "user",
|
|
198
|
+
content: {
|
|
199
|
+
type: "text",
|
|
200
|
+
text: `Writing an import script for variable "${variableName}" in tenant "${tenant}".
|
|
201
|
+
|
|
202
|
+
Steps to follow:
|
|
203
|
+
|
|
204
|
+
1. Use farseer_get_variable to understand the target variable:
|
|
205
|
+
- What dimensions does it have?
|
|
206
|
+
- What is the roll-up type?
|
|
207
|
+
|
|
208
|
+
2. Use farseer_get_table for each dimension to see valid members
|
|
209
|
+
|
|
210
|
+
3. Create the import script with this pattern:
|
|
211
|
+
|
|
212
|
+
\`\`\`typescript
|
|
213
|
+
import * as farseer from 'farseer-client';
|
|
214
|
+
|
|
215
|
+
const client = new farseer.FarseerClient();
|
|
216
|
+
|
|
217
|
+
async function main() {
|
|
218
|
+
await client.initTagMap();
|
|
219
|
+
|
|
220
|
+
// Create import job with column definitions
|
|
221
|
+
const importJob = await client.createImportJob({
|
|
222
|
+
title: 'Import ${variableName}',
|
|
223
|
+
columns: [
|
|
224
|
+
{ type: 'DIMENSION_TABLE', dimensionTableName: 'Product' },
|
|
225
|
+
{ type: 'DIMENSION_TABLE', dimensionTableName: 'Years' },
|
|
226
|
+
{ type: 'DIMENSION_TABLE', dimensionTableName: 'Months' },
|
|
227
|
+
{ type: 'DIMENSION_TABLE', dimensionTableName: 'Versions' },
|
|
228
|
+
{ type: 'VARIABLE', variableName: '${variableName}' },
|
|
229
|
+
],
|
|
230
|
+
labels: ['auto', 'import-${variableName.toLowerCase().replace(/\s+/g, "-")}']
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Add rows - each row matches column order
|
|
234
|
+
const rows = [
|
|
235
|
+
['ProductA', 'Y2025', 'M1', 'Plan', 1000],
|
|
236
|
+
['ProductB', 'Y2025', 'M1', 'Plan', 2000],
|
|
237
|
+
];
|
|
238
|
+
|
|
239
|
+
await importJob.addRows(rows);
|
|
240
|
+
await importJob.flushRows();
|
|
241
|
+
await importJob.undoPrevious(); // Remove previous import
|
|
242
|
+
await importJob.commit();
|
|
243
|
+
|
|
244
|
+
console.log('Import completed!');
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
main().catch(farseer.handleUnknownError);
|
|
248
|
+
\`\`\`
|
|
249
|
+
|
|
250
|
+
4. Save script to apps/${tenant}/files/Scripts/
|
|
251
|
+
5. Push with farseer_push
|
|
252
|
+
6. Create app with farseer_create_app
|
|
253
|
+
7. Configure with farseer_configure_app
|
|
254
|
+
8. Test with farseer_run_app`
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
]
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
);
|
|
261
|
+
anyServer.prompt(
|
|
262
|
+
"copy_app",
|
|
263
|
+
"Guide for copying an existing app to create a new one.",
|
|
264
|
+
copyAppSchema,
|
|
265
|
+
async (params) => {
|
|
266
|
+
const { tenant, sourceApp, newAppName } = params;
|
|
267
|
+
return {
|
|
268
|
+
messages: [
|
|
269
|
+
{
|
|
270
|
+
role: "user",
|
|
271
|
+
content: {
|
|
272
|
+
type: "text",
|
|
273
|
+
text: `Copying app "${sourceApp}" to create "${newAppName}" for tenant "${tenant}".
|
|
274
|
+
|
|
275
|
+
Steps to follow:
|
|
276
|
+
|
|
277
|
+
1. Pull latest with farseer_pull to get current app JSON
|
|
278
|
+
|
|
279
|
+
2. Use farseer_get_app to see the source app configuration
|
|
280
|
+
|
|
281
|
+
3. The app JSON files are in apps/${tenant}/apps/
|
|
282
|
+
|
|
283
|
+
Copy the source JSON file and modify:
|
|
284
|
+
- Change "name" to "${newAppName}"
|
|
285
|
+
- **IMPORTANT: Remove "_remote" field** (this makes it a new app)
|
|
286
|
+
- Modify arguments, description as needed
|
|
287
|
+
|
|
288
|
+
4. JSON format for new app:
|
|
289
|
+
\`\`\`json
|
|
290
|
+
{
|
|
291
|
+
"name": "${newAppName}",
|
|
292
|
+
"description": "Copied from ${sourceApp}",
|
|
293
|
+
"entrypoint": "script.ts",
|
|
294
|
+
"scripts": ["script.ts"],
|
|
295
|
+
"arguments": [
|
|
296
|
+
{ "name": "Year", "defaultValue": "2025" }
|
|
297
|
+
]
|
|
298
|
+
}
|
|
299
|
+
\`\`\`
|
|
300
|
+
|
|
301
|
+
Note: Do NOT include "_remote" for new apps - CLI adds it after first push.
|
|
302
|
+
|
|
303
|
+
5. Push with farseer_push to create the new app
|
|
304
|
+
|
|
305
|
+
6. Test with farseer_run_app`
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
]
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
);
|
|
312
|
+
anyServer.prompt(
|
|
313
|
+
"debug_sync_issues",
|
|
314
|
+
"Troubleshoot synchronization problems between local and remote.",
|
|
315
|
+
debugSyncSchema,
|
|
316
|
+
async (params) => {
|
|
317
|
+
const { tenant } = params;
|
|
318
|
+
return {
|
|
319
|
+
messages: [
|
|
320
|
+
{
|
|
321
|
+
role: "user",
|
|
322
|
+
content: {
|
|
323
|
+
type: "text",
|
|
324
|
+
text: `Debugging sync issues for tenant "${tenant}".
|
|
325
|
+
|
|
326
|
+
Steps to follow:
|
|
327
|
+
|
|
328
|
+
1. Check authentication: farseer_whoami
|
|
329
|
+
- Is JWT valid?
|
|
330
|
+
- Is tenant checked out?
|
|
331
|
+
|
|
332
|
+
2. Check sync status: farseer_status
|
|
333
|
+
- Are there modified files?
|
|
334
|
+
- Are there only-local or only-remote files?
|
|
335
|
+
|
|
336
|
+
3. If files show as modified:
|
|
337
|
+
- Use farseer_diff to see differences
|
|
338
|
+
- Decide: pull (accept remote) or push (upload local)
|
|
339
|
+
|
|
340
|
+
4. Common issues and solutions:
|
|
341
|
+
|
|
342
|
+
**"No credentials found"**
|
|
343
|
+
\u2192 User needs to run "farseer login" in terminal
|
|
344
|
+
\u2192 Or configure API key: "farseer config set ${tenant} --api-key KEY"
|
|
345
|
+
|
|
346
|
+
**"Remote has changes"**
|
|
347
|
+
\u2192 Pull first with farseer_pull
|
|
348
|
+
\u2192 Then push with farseer_push
|
|
349
|
+
|
|
350
|
+
**"Token expired"**
|
|
351
|
+
\u2192 User needs to run "farseer login" again
|
|
352
|
+
|
|
353
|
+
**Apps not syncing**
|
|
354
|
+
\u2192 Need JWT login (browser), not API key
|
|
355
|
+
\u2192 API key only syncs files, not apps
|
|
356
|
+
|
|
357
|
+
5. Force resolution:
|
|
358
|
+
- To accept remote: farseer_pull (overwrites local)
|
|
359
|
+
- To accept local: farseer_push with force=true (overwrites remote)
|
|
360
|
+
|
|
361
|
+
6. Check specific file diff:
|
|
362
|
+
- Use farseer_diff with file parameter to see exact changes`
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
]
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
371
|
+
0 && (module.exports = {
|
|
372
|
+
registerWorkflowPrompts
|
|
373
|
+
});
|
|
374
|
+
//# sourceMappingURL=workflows.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/mcp/prompts/workflows.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Workflow Prompts\n *\n * Reusable prompt templates for common Farseer workflows.\n */\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\n\n// Define schemas outside of prompt registration to avoid deep type instantiation\nconst setupTenantSchema = {\n tenant: z.string().describe('Tenant name to setup'),\n};\n\nconst createAppSchema = {\n tenant: z.string().describe('Tenant name'),\n appName: z.string().describe('Name for the new app'),\n scriptName: z.string().optional().describe('Main script filename (default: index.ts)'),\n};\n\nconst understandModelSchema = {\n tenant: z.string().describe('Tenant name'),\n};\n\nconst writeImportScriptSchema = {\n tenant: z.string().describe('Tenant name'),\n variableName: z.string().describe('Target variable to import into'),\n};\n\nconst copyAppSchema = {\n tenant: z.string().describe('Tenant name'),\n sourceApp: z.string().describe('Name of app to copy'),\n newAppName: z.string().describe('Name for the new app'),\n};\n\nconst debugSyncSchema = {\n tenant: z.string().describe('Tenant name'),\n};\n\nexport function registerWorkflowPrompts(server: McpServer): void {\n // Cast to any to avoid very deep generic type instantiation from the MCP SDK\n const anyServer = server as any;\n // Setup new tenant\n anyServer.prompt(\n 'setup_new_tenant',\n 'Guide for setting up a new Farseer tenant: login, checkout, pull, install dependencies.',\n setupTenantSchema,\n async (params: { tenant: string }) => {\n const { tenant } = params;\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `You are setting up a new Farseer tenant \"${tenant}\".\n\nSteps to follow:\n\n1. First, check authentication status with farseer_whoami\n2. If not logged in, inform the user to run \"farseer login\" in terminal (MCP cannot do browser login)\n3. Use farseer_checkout to set \"${tenant}\" as the default tenant (this also pulls files and apps)\n4. Tell user to run \"farseer install ${tenant}\" in terminal to install npm dependencies\n5. Use farseer_list_apps to show available apps\n6. Use farseer_export_model to understand the data structure\n\nAfter setup, the user can:\n- Run apps with farseer_run_app\n- Edit scripts in apps/${tenant}/files/Scripts/\n- Push changes with farseer_push\n- Check model with farseer_get_variable or farseer_get_table`,\n },\n },\n ],\n };\n },\n );\n\n // Create new app\n anyServer.prompt(\n 'create_new_app',\n 'Guide for creating a new Farseer app from scratch.',\n createAppSchema,\n async (params: { tenant: string; appName: string; scriptName?: string }) => {\n const { tenant, appName, scriptName } = params;\n const script = scriptName || 'index.ts';\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Creating a new Farseer app \"${appName}\" for tenant \"${tenant}\".\n\nSteps to follow:\n\n1. Check if the script \"${script}\" exists with farseer_status\n2. If script doesn't exist locally:\n - Create the script file at apps/${tenant}/files/Scripts/${script}\n - Push with farseer_push\n\n3. Use farseer_create_app to create the app named \"${appName}\"\n\n4. Use farseer_configure_app to set:\n - entrypoint: \"${script}\"\n - scripts: [\"${script}\"]\n - Add arguments if needed\n\n5. Test with farseer_run_app\n\nScript template to create:\n\\`\\`\\`typescript\nimport * as farseer from 'farseer-client';\n\nconst args = process.argv.slice(2);\nconsole.log('Arguments:', args);\n\nconst client = new farseer.FarseerClient();\n\nasync function main() {\n await client.initTagMap();\n\n // Your code here\n console.log('App running successfully');\n}\n\nmain().catch(farseer.handleUnknownError);\n\\`\\`\\``,\n },\n },\n ],\n };\n },\n );\n\n // Understand model\n anyServer.prompt(\n 'understand_model',\n 'Explore and understand the data model of a Farseer tenant.',\n understandModelSchema,\n async (params: { tenant: string }) => {\n const { tenant } = params;\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Analyzing the data model for tenant \"${tenant}\".\n\nSteps to follow:\n\n1. Use farseer_export_model to get the full model structure\n\n2. Review dimension tables:\n - Use farseer_list_tables for overview\n - Key dimensions usually include: Products, Regions, Time (Months, Years), Versions\n - Check foreign key relationships between tables\n\n3. Review variables:\n - Use farseer_list_variables for overview\n - Use farseer_get_variable for specific variable details\n - Note which dimensions each variable has\n\n4. For import scripts, you need to know:\n - Target variable name\n - All dimensions the variable has\n - Valid members for each dimension\n\nKey concepts:\n- Dimensions structure the data (Product, Region, Month, Year, Version)\n- Variables store values at dimension intersections\n- Formulas calculate values automatically\n- Roll-up types determine aggregation (SUM, AVERAGE, etc.)\n\nCommon dimension tables:\n- Months, Years (time)\n- Versions (Plan, Actual, Forecast)\n- Products, Categories, Brands\n- Regions, Entities, Cost Centers`,\n },\n },\n ],\n };\n },\n );\n\n // Write import script\n anyServer.prompt(\n 'write_import_script',\n 'Guide for writing a data import script.',\n writeImportScriptSchema,\n async (params: { tenant: string; variableName: string }) => {\n const { tenant, variableName } = params;\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Writing an import script for variable \"${variableName}\" in tenant \"${tenant}\".\n\nSteps to follow:\n\n1. Use farseer_get_variable to understand the target variable:\n - What dimensions does it have?\n - What is the roll-up type?\n\n2. Use farseer_get_table for each dimension to see valid members\n\n3. Create the import script with this pattern:\n\n\\`\\`\\`typescript\nimport * as farseer from 'farseer-client';\n\nconst client = new farseer.FarseerClient();\n\nasync function main() {\n await client.initTagMap();\n\n // Create import job with column definitions\n const importJob = await client.createImportJob({\n title: 'Import ${variableName}',\n columns: [\n { type: 'DIMENSION_TABLE', dimensionTableName: 'Product' },\n { type: 'DIMENSION_TABLE', dimensionTableName: 'Years' },\n { type: 'DIMENSION_TABLE', dimensionTableName: 'Months' },\n { type: 'DIMENSION_TABLE', dimensionTableName: 'Versions' },\n { type: 'VARIABLE', variableName: '${variableName}' },\n ],\n labels: ['auto', 'import-${variableName.toLowerCase().replace(/\\s+/g, '-')}']\n });\n\n // Add rows - each row matches column order\n const rows = [\n ['ProductA', 'Y2025', 'M1', 'Plan', 1000],\n ['ProductB', 'Y2025', 'M1', 'Plan', 2000],\n ];\n\n await importJob.addRows(rows);\n await importJob.flushRows();\n await importJob.undoPrevious(); // Remove previous import\n await importJob.commit();\n\n console.log('Import completed!');\n}\n\nmain().catch(farseer.handleUnknownError);\n\\`\\`\\`\n\n4. Save script to apps/${tenant}/files/Scripts/\n5. Push with farseer_push\n6. Create app with farseer_create_app\n7. Configure with farseer_configure_app\n8. Test with farseer_run_app`,\n },\n },\n ],\n };\n },\n );\n\n // Copy existing app\n anyServer.prompt(\n 'copy_app',\n 'Guide for copying an existing app to create a new one.',\n copyAppSchema,\n async (params: { tenant: string; sourceApp: string; newAppName: string }) => {\n const { tenant, sourceApp, newAppName } = params;\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Copying app \"${sourceApp}\" to create \"${newAppName}\" for tenant \"${tenant}\".\n\nSteps to follow:\n\n1. Pull latest with farseer_pull to get current app JSON\n\n2. Use farseer_get_app to see the source app configuration\n\n3. The app JSON files are in apps/${tenant}/apps/\n\n Copy the source JSON file and modify:\n - Change \"name\" to \"${newAppName}\"\n - **IMPORTANT: Remove \"_remote\" field** (this makes it a new app)\n - Modify arguments, description as needed\n\n4. JSON format for new app:\n\\`\\`\\`json\n{\n \"name\": \"${newAppName}\",\n \"description\": \"Copied from ${sourceApp}\",\n \"entrypoint\": \"script.ts\",\n \"scripts\": [\"script.ts\"],\n \"arguments\": [\n { \"name\": \"Year\", \"defaultValue\": \"2025\" }\n ]\n}\n\\`\\`\\`\n\nNote: Do NOT include \"_remote\" for new apps - CLI adds it after first push.\n\n5. Push with farseer_push to create the new app\n\n6. Test with farseer_run_app`,\n },\n },\n ],\n };\n },\n );\n\n // Debug sync issues\n anyServer.prompt(\n 'debug_sync_issues',\n 'Troubleshoot synchronization problems between local and remote.',\n debugSyncSchema,\n async (params: { tenant: string }) => {\n const { tenant } = params;\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Debugging sync issues for tenant \"${tenant}\".\n\nSteps to follow:\n\n1. Check authentication: farseer_whoami\n - Is JWT valid?\n - Is tenant checked out?\n\n2. Check sync status: farseer_status\n - Are there modified files?\n - Are there only-local or only-remote files?\n\n3. If files show as modified:\n - Use farseer_diff to see differences\n - Decide: pull (accept remote) or push (upload local)\n\n4. Common issues and solutions:\n\n **\"No credentials found\"**\n \u2192 User needs to run \"farseer login\" in terminal\n \u2192 Or configure API key: \"farseer config set ${tenant} --api-key KEY\"\n\n **\"Remote has changes\"**\n \u2192 Pull first with farseer_pull\n \u2192 Then push with farseer_push\n\n **\"Token expired\"**\n \u2192 User needs to run \"farseer login\" again\n\n **Apps not syncing**\n \u2192 Need JWT login (browser), not API key\n \u2192 API key only syncs files, not apps\n\n5. Force resolution:\n - To accept remote: farseer_pull (overwrites local)\n - To accept local: farseer_push with force=true (overwrites remote)\n\n6. Check specific file diff:\n - Use farseer_diff with file parameter to see exact changes`,\n },\n },\n ],\n };\n },\n );\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Documentation Resources
|
|
3
|
+
*
|
|
4
|
+
* Exposes Farseer documentation as MCP resources for AI assistants.
|
|
5
|
+
* Documentation is bundled as embedded strings to work when CLI is installed globally.
|
|
6
|
+
*/
|
|
7
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
8
|
+
export declare function registerDocumentationResources(server: McpServer): void;
|