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.
Files changed (120) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +741 -0
  3. package/dist/commands/app.d.ts +2 -0
  4. package/dist/commands/app.js +349 -0
  5. package/dist/commands/app.js.map +7 -0
  6. package/dist/commands/apps.d.ts +2 -0
  7. package/dist/commands/apps.js +111 -0
  8. package/dist/commands/apps.js.map +7 -0
  9. package/dist/commands/checkout.d.ts +2 -0
  10. package/dist/commands/checkout.js +166 -0
  11. package/dist/commands/checkout.js.map +7 -0
  12. package/dist/commands/config.d.ts +2 -0
  13. package/dist/commands/config.js +139 -0
  14. package/dist/commands/config.js.map +7 -0
  15. package/dist/commands/diff.d.ts +2 -0
  16. package/dist/commands/diff.js +183 -0
  17. package/dist/commands/diff.js.map +7 -0
  18. package/dist/commands/files.js +99 -0
  19. package/dist/commands/files.js.map +7 -0
  20. package/dist/commands/install.d.ts +2 -0
  21. package/dist/commands/install.js +79 -0
  22. package/dist/commands/install.js.map +7 -0
  23. package/dist/commands/list.d.ts +2 -0
  24. package/dist/commands/list.js +92 -0
  25. package/dist/commands/list.js.map +7 -0
  26. package/dist/commands/login.d.ts +2 -0
  27. package/dist/commands/login.js +134 -0
  28. package/dist/commands/login.js.map +7 -0
  29. package/dist/commands/logout.d.ts +2 -0
  30. package/dist/commands/logout.js +59 -0
  31. package/dist/commands/logout.js.map +7 -0
  32. package/dist/commands/mcp-server.d.ts +8 -0
  33. package/dist/commands/mcp-server.js +41 -0
  34. package/dist/commands/mcp-server.js.map +7 -0
  35. package/dist/commands/model.d.ts +2 -0
  36. package/dist/commands/model.js +189 -0
  37. package/dist/commands/model.js.map +7 -0
  38. package/dist/commands/pull.d.ts +2 -0
  39. package/dist/commands/pull.js +287 -0
  40. package/dist/commands/pull.js.map +7 -0
  41. package/dist/commands/push.d.ts +2 -0
  42. package/dist/commands/push.js +251 -0
  43. package/dist/commands/push.js.map +7 -0
  44. package/dist/commands/run.d.ts +2 -0
  45. package/dist/commands/run.js +246 -0
  46. package/dist/commands/run.js.map +7 -0
  47. package/dist/commands/setup.d.ts +2 -0
  48. package/dist/commands/setup.js +137 -0
  49. package/dist/commands/status.d.ts +2 -0
  50. package/dist/commands/status.js +145 -0
  51. package/dist/commands/status.js.map +7 -0
  52. package/dist/commands/unsetup.d.ts +2 -0
  53. package/dist/commands/unsetup.js +122 -0
  54. package/dist/commands/whoami.d.ts +2 -0
  55. package/dist/commands/whoami.js +63 -0
  56. package/dist/commands/whoami.js.map +7 -0
  57. package/dist/index.d.ts +2 -0
  58. package/dist/index.js +135 -0
  59. package/dist/index.js.map +7 -0
  60. package/dist/mcp/index.d.ts +7 -0
  61. package/dist/mcp/index.js +35 -0
  62. package/dist/mcp/index.js.map +7 -0
  63. package/dist/mcp/prompts/workflows.d.ts +7 -0
  64. package/dist/mcp/prompts/workflows.js +374 -0
  65. package/dist/mcp/prompts/workflows.js.map +7 -0
  66. package/dist/mcp/resources/documentation.d.ts +8 -0
  67. package/dist/mcp/resources/documentation.js +167 -0
  68. package/dist/mcp/resources/documentation.js.map +7 -0
  69. package/dist/mcp/server.d.ts +7 -0
  70. package/dist/mcp/server.js +49 -0
  71. package/dist/mcp/server.js.map +7 -0
  72. package/dist/mcp/tools/appTools.d.ts +7 -0
  73. package/dist/mcp/tools/appTools.js +377 -0
  74. package/dist/mcp/tools/appTools.js.map +7 -0
  75. package/dist/mcp/tools/authTools.d.ts +7 -0
  76. package/dist/mcp/tools/authTools.js +158 -0
  77. package/dist/mcp/tools/authTools.js.map +7 -0
  78. package/dist/mcp/tools/modelTools.d.ts +7 -0
  79. package/dist/mcp/tools/modelTools.js +331 -0
  80. package/dist/mcp/tools/modelTools.js.map +7 -0
  81. package/dist/mcp/tools/runTools.d.ts +7 -0
  82. package/dist/mcp/tools/runTools.js +231 -0
  83. package/dist/mcp/tools/runTools.js.map +7 -0
  84. package/dist/mcp/tools/syncTools.d.ts +7 -0
  85. package/dist/mcp/tools/syncTools.js +382 -0
  86. package/dist/mcp/tools/syncTools.js.map +7 -0
  87. package/dist/mcp/utils/helpers.d.ts +69 -0
  88. package/dist/mcp/utils/helpers.js +113 -0
  89. package/dist/mcp/utils/helpers.js.map +7 -0
  90. package/dist/services/appSyncService.d.ts +75 -0
  91. package/dist/services/appSyncService.js +370 -0
  92. package/dist/services/appSyncService.js.map +7 -0
  93. package/dist/services/configService.d.ts +39 -0
  94. package/dist/services/configService.js +196 -0
  95. package/dist/services/configService.js.map +7 -0
  96. package/dist/services/farseerApi.d.ts +166 -0
  97. package/dist/services/farseerApi.js +378 -0
  98. package/dist/services/farseerApi.js.map +7 -0
  99. package/dist/services/farseerFactory.d.ts +88 -0
  100. package/dist/services/farseerFactory.js +179 -0
  101. package/dist/services/farseerFactory.js.map +7 -0
  102. package/dist/services/farseerService.d.ts +96 -0
  103. package/dist/services/farseerService.js +614 -0
  104. package/dist/services/farseerService.js.map +7 -0
  105. package/dist/services/gitService.d.ts +31 -0
  106. package/dist/services/gitService.js +134 -0
  107. package/dist/services/gitService.js.map +7 -0
  108. package/dist/services/syncService.d.ts +44 -0
  109. package/dist/services/syncService.js +320 -0
  110. package/dist/services/syncService.js.map +7 -0
  111. package/dist/utils/constants.d.ts +7 -0
  112. package/dist/utils/constants.js +46 -0
  113. package/dist/utils/constants.js.map +7 -0
  114. package/dist/utils/helpers.d.ts +69 -0
  115. package/dist/utils/helpers.js +413 -0
  116. package/dist/utils/helpers.js.map +7 -0
  117. package/dist/utils/logger.d.ts +14 -0
  118. package/dist/utils/logger.js +76 -0
  119. package/dist/utils/logger.js.map +7 -0
  120. package/package.json +62 -0
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.registerSetupCommand = registerSetupCommand;
37
+ const logger_1 = require("../utils/logger");
38
+ const configService_1 = require("../services/configService");
39
+ const helpers_1 = require("../utils/helpers");
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ function registerSetupCommand(program) {
43
+ program
44
+ .command('setup <tenant> [file]')
45
+ .description('Inject credentials into script(s) for local development')
46
+ .option('--all', 'Inject credentials into all scripts')
47
+ .action(async (tenant, file, options) => {
48
+ const credential = (0, configService_1.getCredential)(tenant);
49
+ if (!credential) {
50
+ logger_1.logger.error(`No credentials found for tenant: ${tenant}`);
51
+ logger_1.logger.dim((0, helpers_1.getCredentialsHint)(tenant));
52
+ process.exit(1);
53
+ }
54
+ const srcDir = (0, helpers_1.getTenantSrcDir)(tenant);
55
+ if (!fs.existsSync(srcDir)) {
56
+ logger_1.logger.error(`Source folder not found: apps/${tenant}/src/`);
57
+ logger_1.logger.dim('Run "farseer pull <tenant>" first.');
58
+ process.exit(1);
59
+ }
60
+ // Must specify either a file or --all
61
+ if (!file && !options.all) {
62
+ logger_1.logger.error('Please specify a file or use --all for all files.');
63
+ logger_1.logger.dim('Usage: farseer setup <tenant> <file>');
64
+ logger_1.logger.dim(' or: farseer setup <tenant> --all');
65
+ process.exit(1);
66
+ }
67
+ const credentialConfig = {
68
+ basePath: credential.basePath,
69
+ tenantId: credential.tenantId,
70
+ apiKey: credential.apiKey,
71
+ };
72
+ if (options.all) {
73
+ // Process all files
74
+ const files = (0, helpers_1.getAllFiles)(srcDir);
75
+ let injectedCount = 0;
76
+ let alreadySetup = 0;
77
+ let noClientFound = 0;
78
+ for (const f of files) {
79
+ const filePath = path.join(srcDir, f);
80
+ const content = fs.readFileSync(filePath, 'utf-8');
81
+ const modified = (0, helpers_1.injectCredentials)(content, credentialConfig);
82
+ if (modified !== content) {
83
+ fs.writeFileSync(filePath, modified);
84
+ injectedCount++;
85
+ logger_1.logger.success(`Setup: ${f}`);
86
+ }
87
+ else if (content.includes('X-API-KEY')) {
88
+ alreadySetup++;
89
+ }
90
+ else if (!content.includes('FarseerClient')) {
91
+ // No FarseerClient in this file - skip silently
92
+ }
93
+ else {
94
+ noClientFound++;
95
+ }
96
+ }
97
+ console.log();
98
+ if (injectedCount > 0) {
99
+ logger_1.logger.success(`Injected credentials into ${injectedCount} file(s).`);
100
+ }
101
+ if (alreadySetup > 0) {
102
+ logger_1.logger.dim(`${alreadySetup} file(s) already have credentials.`);
103
+ }
104
+ if (injectedCount === 0 && alreadySetup === 0) {
105
+ logger_1.logger.warning('No FarseerClient() found to inject credentials into.');
106
+ logger_1.logger.dim('Looking for: const farseerClient = new farseer.FarseerClient();');
107
+ logger_1.logger.dim(' or: const fClient = new farseer.FarseerClient();');
108
+ }
109
+ }
110
+ else {
111
+ // Process single file
112
+ const filePath = path.join(srcDir, file);
113
+ if (!fs.existsSync(filePath)) {
114
+ logger_1.logger.error(`File not found: ${filePath}`);
115
+ process.exit(1);
116
+ }
117
+ const content = fs.readFileSync(filePath, 'utf-8');
118
+ // Check if already has credentials
119
+ if (content.includes('X-API-KEY')) {
120
+ logger_1.logger.warning(`File already has credentials: ${file}`);
121
+ logger_1.logger.dim('Use "farseer unsetup" first if you want to re-inject.');
122
+ return;
123
+ }
124
+ const modified = (0, helpers_1.injectCredentials)(content, credentialConfig);
125
+ if (modified === content) {
126
+ logger_1.logger.warning('No FarseerClient() found to inject credentials into.');
127
+ logger_1.logger.dim('Looking for: const farseerClient = new farseer.FarseerClient();');
128
+ logger_1.logger.dim(' or: const fClient = new farseer.FarseerClient();');
129
+ return;
130
+ }
131
+ fs.writeFileSync(filePath, modified);
132
+ logger_1.logger.success(`Credentials injected into: ${file}`);
133
+ logger_1.logger.dim('You can now run and debug this script locally.');
134
+ logger_1.logger.dim(`Run "farseer unsetup ${tenant} ${file}" before pushing.`);
135
+ }
136
+ });
137
+ }
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerStatusCommand(program: Command): void;
@@ -0,0 +1,145 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var status_exports = {};
29
+ __export(status_exports, {
30
+ registerStatusCommand: () => registerStatusCommand
31
+ });
32
+ module.exports = __toCommonJS(status_exports);
33
+ var import_chalk = __toESM(require("chalk"));
34
+ var import_logger = require("../utils/logger");
35
+ var import_farseerFactory = require("../services/farseerFactory");
36
+ var import_syncService = require("../services/syncService");
37
+ var import_appSyncService = require("../services/appSyncService");
38
+ var import_helpers = require("../utils/helpers");
39
+ var fs = __toESM(require("fs"));
40
+ function registerStatusCommand(program) {
41
+ program.command("status [arg1] [arg2]").description("Show sync status between local and remote\n\nUsage: status <org> <tenant> OR status <tenant> (if org is known)").option("--all", "Show status for all files (default: only scripts .ts, .js)").action(async (arg1, arg2, options) => {
42
+ const { organisation, tenant } = (0, import_helpers.resolveTenantWithOrgMapping)(arg1, arg2);
43
+ const clientResult = await (0, import_farseerFactory.getFarseerClientWithFallback)(organisation, tenant);
44
+ if (!clientResult) {
45
+ (0, import_farseerFactory.showLoginPrompt)(tenant);
46
+ process.exit(1);
47
+ }
48
+ const filesDir = (0, import_helpers.getTenantFilesDir)(tenant);
49
+ if (!fs.existsSync(filesDir)) {
50
+ import_logger.logger.warning(`Local folder not found: apps/${tenant}/files/`);
51
+ import_logger.logger.dim('Run "farseer pull <tenant>" to download files from the instance.');
52
+ return;
53
+ }
54
+ import_logger.logger.info(`Comparing local (apps/${tenant}/files/) with remote (Files/)...`);
55
+ console.log();
56
+ const syncService = new import_syncService.SyncService(tenant, clientResult.client);
57
+ try {
58
+ const status = await syncService.getStatus({ all: options.all });
59
+ const hasChanges = status.modifiedLocally.length > 0 || status.modifiedRemotely.length > 0 || status.onlyLocal.length > 0 || status.onlyRemote.length > 0;
60
+ if (!hasChanges) {
61
+ import_logger.logger.success("Everything is in sync!");
62
+ import_logger.logger.dim(`${status.inSync.length} file(s) synchronized.`);
63
+ return;
64
+ }
65
+ if (status.modifiedLocally.length > 0) {
66
+ console.log(import_chalk.default.yellow("Modified locally:"));
67
+ for (const file of status.modifiedLocally) {
68
+ console.log(import_chalk.default.yellow(` M ${file}`));
69
+ }
70
+ console.log();
71
+ }
72
+ if (status.modifiedRemotely.length > 0) {
73
+ console.log(import_chalk.default.cyan("Modified on remote:"));
74
+ const syncState = syncService.loadSyncState();
75
+ for (const file of status.modifiedRemotely) {
76
+ const metadata = syncState.files[file]?.metadata;
77
+ const uploaderInfo = metadata?.uploaderName ? ` (by ${metadata.uploaderName})` : metadata?.uploaderEmail ? ` (by ${metadata.uploaderEmail})` : "";
78
+ console.log(import_chalk.default.cyan(` M ${file}`) + import_chalk.default.dim(uploaderInfo));
79
+ }
80
+ console.log();
81
+ }
82
+ if (status.onlyLocal.length > 0) {
83
+ console.log(import_chalk.default.green("Only local (new):"));
84
+ for (const file of status.onlyLocal) {
85
+ console.log(import_chalk.default.green(` + ${file}`));
86
+ }
87
+ console.log();
88
+ }
89
+ if (status.onlyRemote.length > 0) {
90
+ console.log(import_chalk.default.red("Only on remote:"));
91
+ for (const file of status.onlyRemote) {
92
+ console.log(import_chalk.default.red(` - ${file}`));
93
+ }
94
+ console.log();
95
+ }
96
+ const appSyncService = new import_appSyncService.AppSyncService(tenant, clientResult.client);
97
+ const appStatus = await appSyncService.getStatus();
98
+ const hasAppChanges = appStatus.newLocal.length > 0 || appStatus.newRemote.length > 0 || appStatus.modified.length > 0;
99
+ if (hasAppChanges) {
100
+ console.log(import_chalk.default.bold("Apps:"));
101
+ console.log();
102
+ if (appStatus.newLocal.length > 0) {
103
+ console.log(import_chalk.default.green("New local apps (to be created on remote):"));
104
+ for (const app of appStatus.newLocal) {
105
+ console.log(import_chalk.default.green(` + ${app}`));
106
+ }
107
+ console.log();
108
+ }
109
+ if (appStatus.newRemote.length > 0) {
110
+ console.log(import_chalk.default.cyan("New remote apps (to be downloaded):"));
111
+ for (const app of appStatus.newRemote) {
112
+ console.log(import_chalk.default.cyan(` + ${app}`));
113
+ }
114
+ console.log();
115
+ }
116
+ if (appStatus.modified.length > 0) {
117
+ console.log(import_chalk.default.yellow("Modified apps:"));
118
+ for (const app of appStatus.modified) {
119
+ console.log(import_chalk.default.yellow(` ~ ${app}`));
120
+ }
121
+ console.log();
122
+ }
123
+ if (appStatus.synced.length > 0) {
124
+ import_logger.logger.dim(`${appStatus.synced.length} app(s) in sync.`);
125
+ }
126
+ } else if (appStatus.synced.length > 0) {
127
+ import_logger.logger.dim(`${appStatus.synced.length} app(s) in sync.`);
128
+ }
129
+ console.log();
130
+ import_logger.logger.dim('Use "farseer push <tenant>" to upload local changes.');
131
+ import_logger.logger.dim('Use "farseer pull <tenant>" to download remote changes.');
132
+ } catch (error) {
133
+ import_logger.logger.error("Failed to check status.");
134
+ if (error instanceof Error) {
135
+ import_logger.logger.dim(error.message);
136
+ }
137
+ process.exit(1);
138
+ }
139
+ });
140
+ }
141
+ // Annotate the CommonJS export names for ESM import in node:
142
+ 0 && (module.exports = {
143
+ registerStatusCommand
144
+ });
145
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/commands/status.ts"],
4
+ "sourcesContent": ["import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { logger } from '../utils/logger';\nimport { getFarseerClientWithFallback, showLoginPrompt } from '../services/farseerFactory';\nimport { SyncService } from '../services/syncService';\nimport { AppSyncService } from '../services/appSyncService';\nimport { getTenantFilesDir, resolveTenantWithOrgMapping } from '../utils/helpers';\nimport * as fs from 'fs';\n\nexport function registerStatusCommand(program: Command): void {\n program\n .command('status [arg1] [arg2]')\n .description('Show sync status between local and remote\\n\\nUsage: status <org> <tenant> OR status <tenant> (if org is known)')\n .option('--all', 'Show status for all files (default: only scripts .ts, .js)')\n .action(async (arg1, arg2, options) => {\n const { organisation, tenant } = resolveTenantWithOrgMapping(arg1, arg2);\n const clientResult = await getFarseerClientWithFallback(organisation, tenant);\n\n if (!clientResult) {\n showLoginPrompt(tenant);\n process.exit(1);\n }\n\n const filesDir = getTenantFilesDir(tenant);\n\n if (!fs.existsSync(filesDir)) {\n logger.warning(`Local folder not found: apps/${tenant}/files/`);\n logger.dim('Run \"farseer pull <tenant>\" to download files from the instance.');\n return;\n }\n\n logger.info(`Comparing local (apps/${tenant}/files/) with remote (Files/)...`);\n console.log();\n\n const syncService = new SyncService(tenant, clientResult.client);\n\n try {\n const status = await syncService.getStatus({ all: options.all });\n\n const hasChanges =\n status.modifiedLocally.length > 0 ||\n status.modifiedRemotely.length > 0 ||\n status.onlyLocal.length > 0 ||\n status.onlyRemote.length > 0;\n\n if (!hasChanges) {\n logger.success('Everything is in sync!');\n logger.dim(`${status.inSync.length} file(s) synchronized.`);\n return;\n }\n\n // Modified locally\n if (status.modifiedLocally.length > 0) {\n console.log(chalk.yellow('Modified locally:'));\n for (const file of status.modifiedLocally) {\n console.log(chalk.yellow(` M ${file}`));\n }\n console.log();\n }\n\n // Modified remotely\n if (status.modifiedRemotely.length > 0) {\n console.log(chalk.cyan('Modified on remote:'));\n const syncState = syncService.loadSyncState();\n\n for (const file of status.modifiedRemotely) {\n const metadata = syncState.files[file]?.metadata;\n const uploaderInfo = metadata?.uploaderName\n ? ` (by ${metadata.uploaderName})`\n : metadata?.uploaderEmail\n ? ` (by ${metadata.uploaderEmail})`\n : '';\n\n console.log(chalk.cyan(` M ${file}`) + chalk.dim(uploaderInfo));\n }\n console.log();\n }\n\n // Only local (new files)\n if (status.onlyLocal.length > 0) {\n console.log(chalk.green('Only local (new):'));\n for (const file of status.onlyLocal) {\n console.log(chalk.green(` + ${file}`));\n }\n console.log();\n }\n\n // Only remote (not downloaded)\n if (status.onlyRemote.length > 0) {\n console.log(chalk.red('Only on remote:'));\n for (const file of status.onlyRemote) {\n console.log(chalk.red(` - ${file}`));\n }\n console.log();\n }\n\n // Apps status (works with both JWT and API key)\n const appSyncService = new AppSyncService(tenant, clientResult.client);\n const appStatus = await appSyncService.getStatus();\n\n const hasAppChanges =\n appStatus.newLocal.length > 0 ||\n appStatus.newRemote.length > 0 ||\n appStatus.modified.length > 0;\n\n if (hasAppChanges) {\n console.log(chalk.bold('Apps:'));\n console.log();\n\n if (appStatus.newLocal.length > 0) {\n console.log(chalk.green('New local apps (to be created on remote):'));\n for (const app of appStatus.newLocal) {\n console.log(chalk.green(` + ${app}`));\n }\n console.log();\n }\n\n if (appStatus.newRemote.length > 0) {\n console.log(chalk.cyan('New remote apps (to be downloaded):'));\n for (const app of appStatus.newRemote) {\n console.log(chalk.cyan(` + ${app}`));\n }\n console.log();\n }\n\n if (appStatus.modified.length > 0) {\n console.log(chalk.yellow('Modified apps:'));\n for (const app of appStatus.modified) {\n console.log(chalk.yellow(` ~ ${app}`));\n }\n console.log();\n }\n\n if (appStatus.synced.length > 0) {\n logger.dim(`${appStatus.synced.length} app(s) in sync.`);\n }\n } else if (appStatus.synced.length > 0) {\n logger.dim(`${appStatus.synced.length} app(s) in sync.`);\n }\n\n // Summary\n console.log();\n logger.dim('Use \"farseer push <tenant>\" to upload local changes.');\n logger.dim('Use \"farseer pull <tenant>\" to download remote changes.');\n } catch (error) {\n logger.error('Failed to check status.');\n if (error instanceof Error) {\n logger.dim(error.message);\n }\n process.exit(1);\n }\n });\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["chalk"]
7
+ }
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerUnsetupCommand(program: Command): void;
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.registerUnsetupCommand = registerUnsetupCommand;
37
+ const logger_1 = require("../utils/logger");
38
+ const configService_1 = require("../services/configService");
39
+ const helpers_1 = require("../utils/helpers");
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ function registerUnsetupCommand(program) {
43
+ program
44
+ .command('unsetup <tenant> [file]')
45
+ .description('Remove credentials from script(s) before pushing')
46
+ .option('--all', 'Remove credentials from all scripts')
47
+ .action(async (tenant, file, options) => {
48
+ const credential = (0, configService_1.getCredential)(tenant);
49
+ if (!credential) {
50
+ logger_1.logger.error(`No credentials found for tenant: ${tenant}`);
51
+ logger_1.logger.dim((0, helpers_1.getCredentialsHint)(tenant));
52
+ process.exit(1);
53
+ }
54
+ const srcDir = (0, helpers_1.getTenantSrcDir)(tenant);
55
+ if (!fs.existsSync(srcDir)) {
56
+ logger_1.logger.error(`Source folder not found: apps/${tenant}/src/`);
57
+ logger_1.logger.dim('Run "farseer pull <tenant>" first.');
58
+ process.exit(1);
59
+ }
60
+ // Must specify either a file or --all
61
+ if (!file && !options.all) {
62
+ logger_1.logger.error('Please specify a file or use --all for all files.');
63
+ logger_1.logger.dim('Usage: farseer unsetup <tenant> <file>');
64
+ logger_1.logger.dim(' or: farseer unsetup <tenant> --all');
65
+ process.exit(1);
66
+ }
67
+ if (options.all) {
68
+ // Process all files
69
+ const files = (0, helpers_1.getAllFiles)(srcDir);
70
+ let strippedCount = 0;
71
+ let alreadyClean = 0;
72
+ for (const f of files) {
73
+ const filePath = path.join(srcDir, f);
74
+ const content = fs.readFileSync(filePath, 'utf-8');
75
+ const modified = (0, helpers_1.stripCredentials)(content);
76
+ if (modified !== content) {
77
+ fs.writeFileSync(filePath, modified);
78
+ strippedCount++;
79
+ logger_1.logger.success(`Unsetup: ${f}`);
80
+ }
81
+ else if (content.includes('FarseerClient()')) {
82
+ alreadyClean++;
83
+ }
84
+ }
85
+ console.log();
86
+ if (strippedCount > 0) {
87
+ logger_1.logger.success(`Removed credentials from ${strippedCount} file(s).`);
88
+ logger_1.logger.dim('Files are now ready to push.');
89
+ }
90
+ if (alreadyClean > 0) {
91
+ logger_1.logger.dim(`${alreadyClean} file(s) already clean (no credentials).`);
92
+ }
93
+ if (strippedCount === 0 && alreadyClean === 0) {
94
+ logger_1.logger.info('No files with injected credentials found.');
95
+ }
96
+ }
97
+ else {
98
+ // Process single file
99
+ const filePath = path.join(srcDir, file);
100
+ if (!fs.existsSync(filePath)) {
101
+ logger_1.logger.error(`File not found: ${filePath}`);
102
+ process.exit(1);
103
+ }
104
+ const content = fs.readFileSync(filePath, 'utf-8');
105
+ // Check if has credentials to remove
106
+ if (!content.includes('X-API-KEY')) {
107
+ logger_1.logger.info(`File has no injected credentials: ${file}`);
108
+ logger_1.logger.dim('Nothing to unsetup.');
109
+ return;
110
+ }
111
+ const modified = (0, helpers_1.stripCredentials)(content);
112
+ if (modified === content) {
113
+ logger_1.logger.warning('Could not find credentials pattern to remove.');
114
+ logger_1.logger.dim('The file may have been manually modified.');
115
+ return;
116
+ }
117
+ fs.writeFileSync(filePath, modified);
118
+ logger_1.logger.success(`Credentials removed from: ${file}`);
119
+ logger_1.logger.dim('File is now ready to push.');
120
+ }
121
+ });
122
+ }
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerWhoamiCommand(program: Command): void;
@@ -0,0 +1,63 @@
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 whoami_exports = {};
19
+ __export(whoami_exports, {
20
+ registerWhoamiCommand: () => registerWhoamiCommand
21
+ });
22
+ module.exports = __toCommonJS(whoami_exports);
23
+ var import_logger = require("../utils/logger");
24
+ var import_configService = require("../services/configService");
25
+ function registerWhoamiCommand(program) {
26
+ program.command("whoami").description("Show current login status and configured tenants").action(async () => {
27
+ import_logger.logger.header("Farseer Status");
28
+ const userAuth = (0, import_configService.getUserAuth)();
29
+ if (userAuth) {
30
+ if ((0, import_configService.isUserAuthValid)()) {
31
+ const expiresAt = new Date(userAuth.expiresAt);
32
+ import_logger.logger.success("Logged in via browser");
33
+ import_logger.logger.dim(`Token expires: ${expiresAt.toLocaleString()}`);
34
+ } else {
35
+ import_logger.logger.warning("Browser login expired");
36
+ import_logger.logger.dim("Run: farseer login");
37
+ }
38
+ } else {
39
+ import_logger.logger.dim("Not logged in via browser");
40
+ }
41
+ console.log();
42
+ const credentials = (0, import_configService.listCredentials)();
43
+ const tenants = Object.keys(credentials);
44
+ if (tenants.length > 0) {
45
+ import_logger.logger.info(`Configured tenants (${tenants.length}):`);
46
+ for (const tenant of tenants) {
47
+ const cred = credentials[tenant];
48
+ const keyPreview = cred.apiKey.substring(0, 8) + "...";
49
+ console.log(` ${tenant}`);
50
+ console.log(` Base: ${cred.basePath}`);
51
+ console.log(` Key: ${keyPreview}`);
52
+ }
53
+ } else {
54
+ import_logger.logger.dim("No tenants configured");
55
+ import_logger.logger.dim("Run: farseer config set <tenant> --api-key <key>");
56
+ }
57
+ });
58
+ }
59
+ // Annotate the CommonJS export names for ESM import in node:
60
+ 0 && (module.exports = {
61
+ registerWhoamiCommand
62
+ });
63
+ //# sourceMappingURL=whoami.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/commands/whoami.ts"],
4
+ "sourcesContent": ["import { Command } from 'commander';\nimport { logger } from '../utils/logger';\nimport { getUserAuth, isUserAuthValid, listCredentials } from '../services/configService';\n\nexport function registerWhoamiCommand(program: Command): void {\n program\n .command('whoami')\n .description('Show current login status and configured tenants')\n .action(async () => {\n logger.header('Farseer Status');\n\n // Check user auth (browser login)\n const userAuth = getUserAuth();\n if (userAuth) {\n if (isUserAuthValid()) {\n const expiresAt = new Date(userAuth.expiresAt);\n logger.success('Logged in via browser');\n logger.dim(`Token expires: ${expiresAt.toLocaleString()}`);\n } else {\n logger.warning('Browser login expired');\n logger.dim('Run: farseer login');\n }\n } else {\n logger.dim('Not logged in via browser');\n }\n\n console.log();\n\n // List configured tenants (API key)\n const credentials = listCredentials();\n const tenants = Object.keys(credentials);\n\n if (tenants.length > 0) {\n logger.info(`Configured tenants (${tenants.length}):`);\n for (const tenant of tenants) {\n const cred = credentials[tenant];\n const keyPreview = cred.apiKey.substring(0, 8) + '...';\n console.log(` ${tenant}`);\n console.log(` Base: ${cred.basePath}`);\n console.log(` Key: ${keyPreview}`);\n }\n } else {\n logger.dim('No tenants configured');\n logger.dim('Run: farseer config set <tenant> --api-key <key>');\n }\n });\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,oBAAuB;AACvB,2BAA8D;AAEvD,SAAS,sBAAsB,SAAwB;AAC1D,UACK,QAAQ,QAAQ,EAChB,YAAY,kDAAkD,EAC9D,OAAO,YAAY;AAChB,yBAAO,OAAO,gBAAgB;AAG9B,UAAM,eAAW,kCAAY;AAC7B,QAAI,UAAU;AACV,cAAI,sCAAgB,GAAG;AACnB,cAAM,YAAY,IAAI,KAAK,SAAS,SAAS;AAC7C,6BAAO,QAAQ,uBAAuB;AACtC,6BAAO,IAAI,kBAAkB,UAAU,eAAe,CAAC,EAAE;AAAA,MAC7D,OAAO;AACH,6BAAO,QAAQ,uBAAuB;AACtC,6BAAO,IAAI,oBAAoB;AAAA,MACnC;AAAA,IACJ,OAAO;AACH,2BAAO,IAAI,2BAA2B;AAAA,IAC1C;AAEA,YAAQ,IAAI;AAGZ,UAAM,kBAAc,sCAAgB;AACpC,UAAM,UAAU,OAAO,KAAK,WAAW;AAEvC,QAAI,QAAQ,SAAS,GAAG;AACpB,2BAAO,KAAK,uBAAuB,QAAQ,MAAM,IAAI;AACrD,iBAAW,UAAU,SAAS;AAC1B,cAAM,OAAO,YAAY,MAAM;AAC/B,cAAM,aAAa,KAAK,OAAO,UAAU,GAAG,CAAC,IAAI;AACjD,gBAAQ,IAAI,KAAK,MAAM,EAAE;AACzB,gBAAQ,IAAI,aAAa,KAAK,QAAQ,EAAE;AACxC,gBAAQ,IAAI,aAAa,UAAU,EAAE;AAAA,MACzC;AAAA,IACJ,OAAO;AACH,2BAAO,IAAI,uBAAuB;AAClC,2BAAO,IAAI,kDAAkD;AAAA,IACjE;AAAA,EACJ,CAAC;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};