@futdevpro/fdp-agent-memory 0.1.0 → 1.1.14

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 (101) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +7 -7
  3. package/build/package.json +6 -5
  4. package/build/src/_cli/_collections/fam-arg.util.js +48 -0
  5. package/build/src/_cli/_collections/fam-cli.const.js +40 -0
  6. package/build/src/_cli/_collections/fam-output.util.js +86 -0
  7. package/build/src/_cli/_collections/fam-project-discovery.util.js +98 -0
  8. package/build/src/_cli/_commands/capture.command.js +73 -0
  9. package/build/src/_cli/_commands/config.command.js +93 -0
  10. package/build/src/_cli/_commands/doctor.command.js +124 -0
  11. package/build/src/_cli/_commands/errors.command.js +66 -0
  12. package/build/src/_cli/_commands/export.command.js +65 -0
  13. package/build/src/_cli/_commands/find-duplicates.command.js +97 -0
  14. package/build/src/_cli/_commands/import.command.js +136 -0
  15. package/build/src/_cli/_commands/init.command.js +147 -0
  16. package/build/src/_cli/_commands/read.command.js +109 -0
  17. package/build/src/_cli/_commands/scan-projects.command.js +138 -0
  18. package/build/src/_cli/_commands/scan.command.js +98 -0
  19. package/build/src/_cli/_commands/seed.command.js +40 -0
  20. package/build/src/_cli/_commands/serve.command.js +373 -0
  21. package/build/src/_cli/_commands/start.command.js +134 -0
  22. package/build/src/_cli/_commands/stats.command.js +54 -0
  23. package/build/src/_cli/_commands/write.command.js +103 -0
  24. package/build/src/_cli/_models/interfaces/fam-cli-global-options.interface.js +2 -0
  25. package/build/src/_cli/_models/interfaces/fam-cli-output.interface.js +9 -0
  26. package/build/src/_cli/_models/interfaces/fam-client-result.interface.js +2 -0
  27. package/build/src/_cli/_services/fam-client.service.js +140 -0
  28. package/build/src/_cli/register-commands.js +86 -0
  29. package/build/src/_collections/config-catalog.const.js +67 -1
  30. package/build/src/_collections/fam-console.util.js +367 -0
  31. package/build/src/_collections/fam-entry-bootstrap.util.js +158 -4
  32. package/build/src/_collections/fam-error-factory.util.js +0 -9
  33. package/build/src/_collections/fam-mcp-bridge.util.js +49 -0
  34. package/build/src/_collections/fam-reference-code.util.js +105 -0
  35. package/build/src/_collections/fam-version.const.js +10 -0
  36. package/build/src/_models/data-models/fam-entry-base-properties.const.js +1 -0
  37. package/build/src/_models/data-models/fam-entry.data-model.js +6 -0
  38. package/build/src/_models/data-models/fam-ingest-run.data-model.js +3 -1
  39. package/build/src/_models/data-models/fam-reference.data-model.js +7 -0
  40. package/build/src/_modules/capture/_collections/fam-capture.const.js +11 -0
  41. package/build/src/_modules/capture/_services/fam-auto-capture.control-service.js +87 -0
  42. package/build/src/_modules/capture/index.js +8 -0
  43. package/build/src/_modules/embedding/_collections/fam-embedding-prefix.util.js +77 -0
  44. package/build/src/_modules/embedding/_services/fam-duplicate-scan.control-service.js +202 -0
  45. package/build/src/_modules/embedding/_services/fam-embedding-pipeline.control-service.js +33 -9
  46. package/build/src/_modules/embedding/_services/fam-embedding.control-service.js +21 -2
  47. package/build/src/_modules/embedding/_services/fam-entry.data-service.js +135 -0
  48. package/build/src/_modules/embedding/_services/fam-vector-search.control-service.js +42 -32
  49. package/build/src/_modules/embedding/index.js +4 -1
  50. package/build/src/_modules/export/_collections/fam-export.const.js +22 -0
  51. package/build/src/_modules/export/_services/fam-export.control-service.js +64 -0
  52. package/build/src/_modules/export/index.js +8 -0
  53. package/build/src/_modules/ingest/_collections/fam-famignore.util.js +83 -0
  54. package/build/src/_modules/ingest/_collections/fam-file-routing.util.js +59 -48
  55. package/build/src/_modules/ingest/_collections/fam-git-repo.util.js +193 -0
  56. package/build/src/_modules/ingest/_collections/fam-project-identity.util.js +134 -0
  57. package/build/src/_modules/ingest/_collections/fam-scan-progress.util.js +57 -0
  58. package/build/src/_modules/ingest/_collections/fam-scan-summary.util.js +60 -0
  59. package/build/src/_modules/ingest/_collections/fam-scan-weight.util.js +53 -0
  60. package/build/src/_modules/ingest/_collections/fam-secret-exclude.util.js +37 -14
  61. package/build/src/_modules/ingest/_collections/fam-sliding-chunker.util.js +34 -0
  62. package/build/src/_modules/ingest/_collections/fam-ts-chunker.util.js +200 -14
  63. package/build/src/_modules/ingest/_services/fam-delta-compare.util.js +4 -1
  64. package/build/src/_modules/ingest/_services/fam-ingest-run.data-service.js +7 -4
  65. package/build/src/_modules/ingest/_services/fam-ingest.control-service.js +349 -17
  66. package/build/src/_modules/ingest/_services/fam-scan.control-service.js +25 -2
  67. package/build/src/_modules/ingest/index.js +3 -1
  68. package/build/src/_modules/mcp/_collections/fam-active-rules.util.js +56 -0
  69. package/build/src/_modules/mcp/_collections/fam-core-tools.const.js +47 -6
  70. package/build/src/_modules/mcp/_services/fam-capabilities-tool.service.js +4 -4
  71. package/build/src/_modules/mcp/_services/fam-capability-registry.service.js +224 -18
  72. package/build/src/_modules/mcp/_services/fam-mcp-adapter.service.js +4 -4
  73. package/build/src/_modules/mcp/_services/fam-mcp-server.service.js +4 -4
  74. package/build/src/_modules/mcp/_services/fam-read-tool.service.js +53 -1
  75. package/build/src/_modules/mcp/_services/fam-write-tool.service.js +104 -8
  76. package/build/src/_modules/mcp/index.js +4 -4
  77. package/build/src/_modules/migration/_collections/fam-claude-mem-normalize.util.js +66 -3
  78. package/build/src/_modules/migration/_collections/fam-prompt-aggregate.util.js +143 -0
  79. package/build/src/_modules/migration/_collections/fam-target-mapping.util.js +19 -0
  80. package/build/src/_modules/migration/_enums/fam-claude-mem-source.type-enum.js +6 -0
  81. package/build/src/_modules/migration/_models/interfaces/fam-claude-mem.interface.js +5 -0
  82. package/build/src/_modules/migration/_services/fam-agent-memory-reader.service.js +125 -0
  83. package/build/src/_modules/migration/_services/fam-claude-mem-import.control-service.js +101 -18
  84. package/build/src/_modules/migration/_services/fam-import-dedup.data-service.js +53 -0
  85. package/build/src/_modules/migration/index.js +3 -1
  86. package/build/src/_modules/retrieval/_services/fam-retrieval-candidate.data-service.js +78 -4
  87. package/build/src/_modules/retrieval/_services/fam-retrieval.control-service.js +293 -50
  88. package/build/src/_modules/scope-reference/_collections/fam-scope-normalize.util.js +6 -3
  89. package/build/src/_modules/scope-reference/_services/fam-reference.data-service.js +18 -0
  90. package/build/src/_modules/scope-reference/_services/fam-scope-resolver.control-service.js +79 -20
  91. package/build/src/_routes/server/api/api.controller.js +34 -2
  92. package/build/src/_routes/server/client-app/client-app.control-service.js +1 -1
  93. package/build/src/_routes/server/server-status/server-status.controller.js +2 -1
  94. package/build/src/app.server.js +13 -1
  95. package/build/src/environments/environment.js +1 -1
  96. package/build/src/index.js +1 -1
  97. package/client-dist/{chunk-GHKRM4SM.js → chunk-I77GXVAQ.js} +1 -1
  98. package/client-dist/{chunk-LMTL7GA3.js → chunk-YXHWCJ5O.js} +1 -1
  99. package/client-dist/index.html +1 -1
  100. package/client-dist/{main-2KWB3QYK.js → main-PJPEDVJT.js} +1 -1
  101. package/package.json +6 -5
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FAM_ScanProjects_Util = void 0;
4
+ const fs_1 = require("fs");
5
+ const commander_1 = require("commander");
6
+ const fam_output_util_1 = require("../_collections/fam-output.util");
7
+ const fam_client_service_1 = require("../_services/fam-client.service");
8
+ const fam_cli_const_1 = require("../_collections/fam-cli.const");
9
+ const fam_project_discovery_util_1 = require("../_collections/fam-project-discovery.util");
10
+ /**
11
+ * `fam scan-projects` — több projekt **SOROS** scan-orchestrátora (robusztus, NINCS konkurrens embed-thrash).
12
+ * A projekt-listát `--config` (explicit JSON) VAGY `--root` (auto-felderítés: `package.json`/`.git` markerek,
13
+ * a scope-név a package.json `name`-jéből) adja. Projektenként: előbb `dryRun` (idő-becslés), majd a VALÓS scan,
14
+ * és VÁRJA a teljes választ, mielőtt a következőre lép. Ez a megfelelő minta a Packages / teljes CURSOR scanhez.
15
+ */
16
+ class FAM_ScanProjects_Util {
17
+ /** A `scan-projects` parancs-deszkriptor. */
18
+ static command() {
19
+ const command = new commander_1.Command('scan-projects');
20
+ command
21
+ .description('Több projekt SOROS scan-je (auto-felderítés --root-tal vagy explicit --config-gal; nincs '
22
+ + 'konkurrens thrash). ⚠️ MINDEN projekt-gyökérbe előbb `.fdpfamignore` + `--dry-run` (lásd lent).')
23
+ .option('--root <dir>', 'projekt-gyökerek auto-felderítése e mappa alatt (package.json/.git markerek)')
24
+ .option('--config <file.json>', 'explicit projekt-lista: [{ path, project, org?, table? }]')
25
+ .option('--depth <n>', 'auto-felderítés max mélysége (default 3)', '3')
26
+ .option('--org <name>', 'default organization az auto-felderítéshez', 'FutDevPro')
27
+ .option('--table <documents|codebase>', 'default cél-tár', 'codebase')
28
+ .option('--dry-run', 'csak becslés MINDEN projektre, NEM ír', false)
29
+ .option('--stop-on-error', 'az első hibánál leáll (default: folytatja a többivel)', false)
30
+ .addHelpText('before', '\n⚠️ TISZTA MULTI-SCAN — ELŐBB minden projektbe IGNORE-FÁJL:\n'
31
+ + ' Mivel ez TÖBB projektet szkennel egyszerre, a junk gyorsan elszaporodik. MINDEN érintett\n'
32
+ + ' projekt-gyökérbe tegyél `.fdpfamignore`-t (a default fedi a node_modules/Library/__pycache__/\n'
33
+ + ' site-packages/dist/build/Logs-féle junkot; a projekt-specifikusat ott add hozzá), és FUTTASD\n'
34
+ + ' ELŐSZÖR `--dry-run`-nal (per-projekt fájl/chunk-becslés). Utólag kitakarítani (törlés +\n'
35
+ + ' re-embed minden projekten) sokkal drágább, mint eleve tisztán szkennelni.\n')
36
+ .action(async () => {
37
+ fam_output_util_1.FAM_Output_Util.exit(await FAM_ScanProjects_Util.run(command));
38
+ });
39
+ return command;
40
+ }
41
+ /** A `scan-projects` futtatása: projekt-lista feloldás → SOROS dryRun+scan → összesítő. */
42
+ static async run(command) {
43
+ const globals = command.optsWithGlobals();
44
+ const local = command.opts();
45
+ let specs;
46
+ try {
47
+ if (local.config) {
48
+ specs = fam_project_discovery_util_1.FAM_ProjectDiscovery_Util.parseConfig((0, fs_1.readFileSync)(local.config, 'utf-8'));
49
+ }
50
+ else if (local.root) {
51
+ specs = fam_project_discovery_util_1.FAM_ProjectDiscovery_Util.discover(local.root, Number(local.depth) || 3, { org: local.org, table: local.table });
52
+ }
53
+ else {
54
+ return fam_output_util_1.FAM_Output_Util.failure({
55
+ options: globals, command: 'scan-projects',
56
+ error: {
57
+ errorCode: 'FAM-CLI-SCANP-001',
58
+ message: '`--root <dir>` (auto-felderítés) VAGY `--config <file.json>` (explicit lista) kötelező.',
59
+ fixHint: 'Pl.: fam scan-projects --root E:/.../NPM-packages vagy --config projects.json',
60
+ },
61
+ });
62
+ }
63
+ }
64
+ catch (error) {
65
+ return fam_output_util_1.FAM_Output_Util.failure({
66
+ options: globals, command: 'scan-projects',
67
+ error: { errorCode: 'FAM-CLI-SCANP-002', message: `A projekt-lista feloldása sikertelen: ${error?.message}` },
68
+ });
69
+ }
70
+ if (!specs.length) {
71
+ return fam_output_util_1.FAM_Output_Util.failure({
72
+ options: globals, command: 'scan-projects',
73
+ error: { errorCode: 'FAM-CLI-SCANP-003', message: 'Nincs felderített/megadott projekt.' },
74
+ exitCode: fam_cli_const_1.FAM_CliExitCode.operationError,
75
+ });
76
+ }
77
+ const client = new fam_client_service_1.FAM_CliClient_Service(globals.serverUrl);
78
+ const projects = [];
79
+ let okCount = 0;
80
+ FAM_ScanProjects_Util.progress(globals, `=== ${specs.length} projekt SOROS scan-je${local.dryRun ? ' (dryRun)' : ''} ===`);
81
+ for (let i = 0; i < specs.length; i++) {
82
+ const spec = specs[i];
83
+ FAM_ScanProjects_Util.progress(globals, `[${i + 1}/${specs.length}] ${spec.project} (${spec.path})`);
84
+ // 1) dryRun — idő-becslés
85
+ const dry = await client.post('/api/write', FAM_ScanProjects_Util.body(spec, true, local));
86
+ const dryScan = dry.ok ? dry.data?.scan : undefined;
87
+ if (dryScan) {
88
+ FAM_ScanProjects_Util.progress(globals, ` becslés: ${dryScan.filesProcessed} fájl, ${dryScan.chunks} chunk, ~${dryScan.estimate?.estimatedSeconds ?? '?'}s embed`);
89
+ }
90
+ if (local.dryRun) {
91
+ projects.push({ project: spec.project, dryRun: dryScan });
92
+ okCount += dry.ok ? 1 : 0;
93
+ continue;
94
+ }
95
+ // 2) VALÓS scan — VÁRJUK a teljes választ (soros, nincs konkurrencia)
96
+ const startedAt = Date.now();
97
+ const real = await client.post('/api/write', FAM_ScanProjects_Util.body(spec, false, local));
98
+ const seconds = Math.round((Date.now() - startedAt) / 1000);
99
+ const realScan = real.ok ? real.data?.scan : undefined;
100
+ if (real.ok && realScan) {
101
+ okCount++;
102
+ FAM_ScanProjects_Util.progress(globals, ` kész: ${realScan.filesProcessed} fájl, ${realScan.chunks} chunk, ${JSON.stringify(realScan.verdicts)}, ${realScan.status} (${seconds}s)`);
103
+ projects.push({ project: spec.project, scan: realScan, seconds: seconds });
104
+ }
105
+ else {
106
+ FAM_ScanProjects_Util.progress(globals, ` HIBA: ${real.error?.message ?? 'ismeretlen scan-hiba'}`);
107
+ projects.push({ project: spec.project, error: real.error });
108
+ if (local.stopOnError) {
109
+ break;
110
+ }
111
+ }
112
+ }
113
+ FAM_ScanProjects_Util.progress(globals, `=== KÉSZ: ${okCount}/${specs.length} ok ===`);
114
+ return fam_output_util_1.FAM_Output_Util.success({
115
+ options: globals, command: 'scan-projects',
116
+ data: { total: specs.length, ok: okCount, projects: projects },
117
+ });
118
+ }
119
+ /** A scan-request body egy projekt-spec-hez (dryRun vagy valós). */
120
+ static body(spec, dryRun, defaults) {
121
+ return {
122
+ table: spec.table ?? defaults.table ?? 'codebase',
123
+ operation: 'scan-project',
124
+ scopePath: [
125
+ { layer: 'organization', rawName: spec.org ?? defaults.org ?? 'FutDevPro' },
126
+ { layer: 'project', rawName: spec.project },
127
+ ],
128
+ scan: { path: spec.path, dryRun: dryRun },
129
+ };
130
+ }
131
+ /** Ember-olvasható haladás-sor a stderr-re (a `--json` stdout-ot nem szennyezi; `--quiet` esetén néma). */
132
+ static progress(globals, line) {
133
+ if (!globals.quiet) {
134
+ process.stderr.write(`${line}\n`);
135
+ }
136
+ }
137
+ }
138
+ exports.FAM_ScanProjects_Util = FAM_ScanProjects_Util;
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FAM_Scan_Util = void 0;
4
+ const fs_1 = require("fs");
5
+ const commander_1 = require("commander");
6
+ const fam_arg_util_1 = require("../_collections/fam-arg.util");
7
+ const fam_output_util_1 = require("../_collections/fam-output.util");
8
+ const fam_client_service_1 = require("../_services/fam-client.service");
9
+ const fam_cli_const_1 = require("../_collections/fam-cli.const");
10
+ /**
11
+ * `fam scan` — a `write --operation scan-*` kényelmi wrapper-e (dsgn-010 §7.3, dsgn-004). A `--path`
12
+ * típusa dönti el a műveletet (file → `scan-file`, dir → `scan-folder`); a `--table` opcionális (megadva
13
+ * mindent oda kényszerít, különben a server-router dönt: docs→documents, code→codebase). A secret-guard
14
+ * MINDIG hozzáadódik az `--exclude`-hoz (`.env`/kulcs/`node_modules`/`.git`; opt-out NEM megengedett).
15
+ */
16
+ class FAM_Scan_Util {
17
+ /** A `scan` parancs-deszkriptor. */
18
+ static command() {
19
+ const command = new commander_1.Command('scan');
20
+ command
21
+ .description('Ingest egy fájlra/mappára (auto-routing docs→documents / code→codebase; dsgn-004). '
22
+ + '⚠️ Mappa-scan ELŐTT: készíts `.fdpfamignore`-t + ellenőrizz `--dry-run`-nal (lásd lent).')
23
+ .requiredOption('--path <file|dir>', 'a scan-elendő fájl vagy mappa')
24
+ .option('--table <documents|codebase>', 'felülírja az auto-routingot (mindent ide)')
25
+ .option('--include <glob,...>', 'include glob-szűrők')
26
+ .option('--exclude <glob,...>', 'exclude glob-szűrők (a secret-guard mellé)')
27
+ .option('--scope <layer=name,...>', 'scope-lánc (KÖTELEZŐ)')
28
+ .option('--dry-run', 'nem ír; tervezett fájl/chunk/verdikt-szám', false)
29
+ .addHelpText('before', '\n⚠️ TISZTA SCAN — ELŐBB az IGNORE-FÁJL:\n'
30
+ + ' 1) Hozz létre `.fdpfamignore`-t a scan-gyökérben (a `.gitignore` mintájára) a projekt-\n'
31
+ + ' specifikus junk-mappákra (a default már fedi: node_modules/Library/__pycache__/\n'
32
+ + ' site-packages/dist/build/coverage/Logs/obj/bin + *.meta/*.csproj/*.sln).\n'
33
+ + ' 2) Futtasd ELŐSZÖR `--dry-run`-nal: ellenőrizd a fájl/chunk-számot.\n'
34
+ + ' A beszkennelt junkot UTÓLAG kitakarítani (törlés + re-embed) sokkal drágább,\n'
35
+ + ' mint eleve tisztán szkennelni.\n')
36
+ .action(async () => {
37
+ fam_output_util_1.FAM_Output_Util.exit(await FAM_Scan_Util.run(command));
38
+ });
39
+ return command;
40
+ }
41
+ /** A `scan` futtatása: path-típus → operation, secret-guard merge, `POST /api/write`. */
42
+ static async run(command) {
43
+ const globals = command.optsWithGlobals();
44
+ const local = command.opts();
45
+ const scopePath = fam_arg_util_1.FAM_Arg_Util.parseScope(local.scope);
46
+ if (!scopePath) {
47
+ return fam_output_util_1.FAM_Output_Util.failure({
48
+ options: globals,
49
+ command: 'scan',
50
+ error: {
51
+ errorCode: 'FAM-CLI-SCAN-001',
52
+ message: 'A scan-hez --scope KÖTELEZŐ (dsgn-002 §3.2).',
53
+ fixHint: 'Add meg pl.: --scope "organization=FutDevPro,project=Adventor"',
54
+ },
55
+ });
56
+ }
57
+ if (!(0, fs_1.existsSync)(local.path)) {
58
+ return fam_output_util_1.FAM_Output_Util.failure({
59
+ options: globals,
60
+ command: 'scan',
61
+ error: {
62
+ errorCode: 'FAM-CLI-SCAN-002',
63
+ message: `A --path nem létezik: ${local.path}.`,
64
+ fixHint: 'Ellenőrizd az útvonalat (abszolút vagy a futtatási mappához relatív).',
65
+ },
66
+ });
67
+ }
68
+ const isDirectory = (0, fs_1.statSync)(local.path).isDirectory();
69
+ const operation = isDirectory ? 'scan-folder' : 'scan-file';
70
+ const exclude = [
71
+ ...(fam_arg_util_1.FAM_Arg_Util.parseList(local.exclude) ?? []),
72
+ ...fam_cli_const_1.FAM_SCAN_SECRET_GUARD,
73
+ ];
74
+ const body = {
75
+ table: local.table ?? 'codebase',
76
+ operation: operation,
77
+ scopePath: scopePath,
78
+ scan: {
79
+ path: local.path,
80
+ include: fam_arg_util_1.FAM_Arg_Util.parseList(local.include),
81
+ exclude: exclude,
82
+ dryRun: local.dryRun === true,
83
+ },
84
+ };
85
+ const client = new fam_client_service_1.FAM_CliClient_Service(globals.serverUrl);
86
+ const result = await client.post('/api/write', body);
87
+ if (!result.ok) {
88
+ return fam_output_util_1.FAM_Output_Util.failure({
89
+ options: globals,
90
+ command: 'scan',
91
+ error: result.error ?? { errorCode: 'FAM-CLI-SCAN-003', message: 'Ismeretlen scan-hiba.' },
92
+ exitCode: result.unreachable ? fam_cli_const_1.FAM_CliExitCode.serverUnreachable : fam_cli_const_1.FAM_CliExitCode.operationError,
93
+ });
94
+ }
95
+ return fam_output_util_1.FAM_Output_Util.success({ options: globals, command: 'scan', data: result.data });
96
+ }
97
+ }
98
+ exports.FAM_Scan_Util = FAM_Scan_Util;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FAM_Seed_Util = void 0;
4
+ const commander_1 = require("commander");
5
+ const fam_output_util_1 = require("../_collections/fam-output.util");
6
+ const fam_client_service_1 = require("../_services/fam-client.service");
7
+ const fam_cli_const_1 = require("../_collections/fam-cli.const");
8
+ /**
9
+ * `fam seed-example` — minta-bejegyzések seed-elése (dsgn-010 §10). A `capabilities.invoke
10
+ * seed_example` eszközre delegál (a server-réteg ezt is discoverable-ként expozeálja); a minta-tartalom
11
+ * + scope a server-oldalon van (a CLI csak triggereli). Nincs külön seed-logika a CLI-ben.
12
+ */
13
+ class FAM_Seed_Util {
14
+ /** A `seed-example` parancs-deszkriptor (a `commandName` a top-level név). */
15
+ static command(commandName) {
16
+ const command = new commander_1.Command(commandName);
17
+ command
18
+ .description('Minta-bejegyzések seed-elése (capabilities.invoke seed_example)')
19
+ .action(async () => {
20
+ fam_output_util_1.FAM_Output_Util.exit(await FAM_Seed_Util.run(command));
21
+ });
22
+ return command;
23
+ }
24
+ /** A seed-trigger: `POST /api/capabilities {action:invoke, name:seed_example}`. */
25
+ static async run(command) {
26
+ const globals = command.optsWithGlobals();
27
+ const client = new fam_client_service_1.FAM_CliClient_Service(globals.serverUrl);
28
+ const result = await client.post('/api/capabilities', { action: 'invoke', name: 'seed_example' });
29
+ if (!result.ok) {
30
+ return fam_output_util_1.FAM_Output_Util.failure({
31
+ options: globals,
32
+ command: 'seed-example',
33
+ error: result.error ?? { errorCode: 'FAM-CLI-SEED-001', message: 'Ismeretlen seed-hiba.' },
34
+ exitCode: result.unreachable ? fam_cli_const_1.FAM_CliExitCode.serverUnreachable : fam_cli_const_1.FAM_CliExitCode.operationError,
35
+ });
36
+ }
37
+ return fam_output_util_1.FAM_Output_Util.success({ options: globals, command: 'seed-example', data: result.data });
38
+ }
39
+ }
40
+ exports.FAM_Seed_Util = FAM_Seed_Util;
@@ -0,0 +1,373 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FAM_Serve_Util = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const child_process_1 = require("child_process");
6
+ const net = tslib_1.__importStar(require("net"));
7
+ const fs_1 = require("fs");
8
+ const os_1 = require("os");
9
+ const path_1 = require("path");
10
+ const commander_1 = require("commander");
11
+ const fam_console_util_1 = require("../../_collections/fam-console.util");
12
+ const fam_output_util_1 = require("../_collections/fam-output.util");
13
+ const fam_cli_const_1 = require("../_collections/fam-cli.const");
14
+ const fam_client_service_1 = require("../_services/fam-client.service");
15
+ /**
16
+ * `fam serve` — **állandó, leválasztott (detached) FAM REST-primary biztosítása** (ensure-szemantika). A
17
+ * core-architektúra javítása (user-direktíva 2026-06-21): a dev-/agent-műveletekhez a szervert NE a hívó
18
+ * (CLI / agent-task) **gyereke**ként futtassuk — mert akkor a hívó futásával együtt MEGHAL (és OOM-nál nincs,
19
+ * ami túlélje). Helyette: **megnézzük, fut-e** (`/api/health`), és ha nem, **külön processzként, leválasztva,
20
+ * saját ablakban** indítjuk, ami **túléli ezt a futást** — legközelebb már csak rácsatlakozunk.
21
+ *
22
+ * **Hogyan illeszkedik a meglévő mintákhoz:**
23
+ * - **FEAT-002** („egy szerver, sok bridge"): ha már fut egy egészséges primary a porton → NEM indítunk
24
+ * másodikat (idempotens reuse). Az MCP-kliensek külön `fam start`-ja úgyis ehhez a REST-primary-hoz
25
+ * bridge-el.
26
+ * - **FEAT-001** (activity-konzol): a detach-olt szerver a saját, látható activity-ablakát nyitja (a
27
+ * `fam-activity-<port>.log` tail-je) → ez a „fixen megnyíló ablak, ami mindig fut". A tee `fs`-sel a
28
+ * fájlba ír, így `stdio:'ignore'` mellett is működik.
29
+ *
30
+ * A boot **REST-only** (a belépő argumentum-nélküli ága): tiszta HTTP-primary, MCP-stdio nélkül (a detach-olt
31
+ * processnek nincs stdin-kliense). A heap-plafon a nagy korpusz boot-hidratálásához emelt (`--max-old-space-size`,
32
+ * default 16 GB; `--heap`/`FAM_MAX_OLD_SPACE_MB`). `--foreground` → attached futás (debug). `--status` → csak
33
+ * ellenőrzés (sosem indít).
34
+ */
35
+ class FAM_Serve_Util {
36
+ /** A REST-primary default portja (a belépő `FAM_SERVER_PORT`-jával egyezik). */
37
+ static DEFAULT_PORT = 39265;
38
+ /** A detach-olt szerver default heap-plafonja MB-ban (a nagy pool-hidratáláshoz; vö. `FAM_Start_Util`). */
39
+ static DEFAULT_HEAP_MB = 16384;
40
+ /** A health-bevárás default felső korlátja (s) — a boot + Mongo-connect + pool-hidratálás ennyi alatt. */
41
+ static DEFAULT_WAIT_SEC = 40;
42
+ /** A health-poll periódusa (ms) a detach-olt boot bevárásakor. */
43
+ static HEALTH_POLL_MS = 1000;
44
+ /** Az utolsó `fam serve` indítás állapot-fájlja (port + db + heap) — a `--restart`/auto-restart innen tudja, mit. */
45
+ static STATE_FILE = (0, path_1.join)((0, os_1.tmpdir)(), 'fam-serve-state.json');
46
+ /** A `serve` parancs-deszkriptor. */
47
+ static command() {
48
+ const command = new commander_1.Command('serve');
49
+ command
50
+ .description('Állandó, leválasztott (detached) FAM REST-szerver biztosítása — fut-e? ha nem, külön ablakban indítja')
51
+ .option('--port <port>', 'REST-port (env: FAM_SERVER_PORT)', undefined)
52
+ .option('--heap <mb>', 'heap-plafon MB (env: FAM_MAX_OLD_SPACE_MB; 0 → node-default)', undefined)
53
+ .option('--wait <seconds>', 'health-bevárás felső korlátja (s)', undefined)
54
+ .option('--status', 'csak ellenőrzés: fut-e? (sosem indít)', false)
55
+ .option('--restart', 'a futó szerver leállítása + újraindítása (dev)', false)
56
+ .option('--foreground', 'attached futás (ne detacheljen, ne nyisson ablakot — debug)', false)
57
+ .option('--mongodb-uri <uri>', 'Mongo connection string (env-felülírás)')
58
+ .option('--db-name <name>', 'Mongo DB-név (env-felülírás)')
59
+ .action(async () => {
60
+ fam_output_util_1.FAM_Output_Util.exit(await FAM_Serve_Util.run(command));
61
+ });
62
+ return command;
63
+ }
64
+ /**
65
+ * A tiszta indítási döntés (a spawn/HTTP ELŐTT, unit-tesztelhető). `--status` SOSEM indít (csak riport:
66
+ * fut → `reuse-running`, nem-fut → `report-down`). Egyébként: ha fut + `--restart` → `restart`; ha fut →
67
+ * `reuse-running` (idempotens); ha nem fut → `spawn` (a `--restart` nem-futó szervernél = sima spawn).
68
+ */
69
+ static decideAction(set) {
70
+ if (set.statusOnly) {
71
+ return set.reachable ? 'reuse-running' : 'report-down';
72
+ }
73
+ if (set.reachable) {
74
+ return set.restart ? 'restart' : 'reuse-running';
75
+ }
76
+ return 'spawn';
77
+ }
78
+ /** A REST-port feloldása (`--port` → `FAM_SERVER_PORT` → default 39265). Érvénytelen → default. */
79
+ static resolvePort(override) {
80
+ const raw = override ?? process.env.FAM_SERVER_PORT;
81
+ if (raw === undefined || String(raw).trim() === '') {
82
+ return FAM_Serve_Util.DEFAULT_PORT;
83
+ }
84
+ const parsed = Number(raw);
85
+ return Number.isInteger(parsed) && parsed > 0 && parsed < 65536 ? parsed : FAM_Serve_Util.DEFAULT_PORT;
86
+ }
87
+ /** A heap-plafon (MB) feloldása (`--heap` → `FAM_MAX_OLD_SPACE_MB` → default 16384). `0`/érvénytelen → 0 (node-default). */
88
+ static resolveHeapMb(override) {
89
+ const raw = override ?? process.env.FAM_MAX_OLD_SPACE_MB;
90
+ if (raw === undefined || String(raw).trim() === '') {
91
+ return FAM_Serve_Util.DEFAULT_HEAP_MB;
92
+ }
93
+ const parsed = Number(raw);
94
+ return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : 0;
95
+ }
96
+ /** A health-bevárás felső korlátja ms-ban (`--wait` s → ms; default 40s). Érvénytelen → default. */
97
+ static resolveWaitMs(override) {
98
+ if (override === undefined || String(override).trim() === '') {
99
+ return FAM_Serve_Util.DEFAULT_WAIT_SEC * 1000;
100
+ }
101
+ const parsed = Number(override);
102
+ return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed * 1000) : FAM_Serve_Util.DEFAULT_WAIT_SEC * 1000;
103
+ }
104
+ /** A teljes parancs-folyamat: health-check → döntés → reuse / status-riport / detached-spawn → health-bevárás. */
105
+ static async run(command) {
106
+ const globals = command.optsWithGlobals();
107
+ const local = command.opts();
108
+ // `--restart` explicit `--port`/env nélkül → az UTOLSÓ indított szerver állapotából (port + db + heap),
109
+ // hogy a `fam serve --restart` (és az opt-in post-commit auto-restart) a HELYES szervert állítsa vissza
110
+ // (nem vakon a default 39265-öt). Az explicit flag-ek mindig győznek.
111
+ const lastState = local.restart && !local.port && !process.env.FAM_SERVER_PORT ? FAM_Serve_Util.loadServeState() : null;
112
+ if (lastState) {
113
+ if (!local.dbName) {
114
+ local.dbName = lastState.dbName;
115
+ }
116
+ if (!local.mongodbUri) {
117
+ local.mongodbUri = lastState.mongodbUri;
118
+ }
119
+ if (!local.heap && lastState.heapMb) {
120
+ local.heap = String(lastState.heapMb);
121
+ }
122
+ }
123
+ const port = lastState?.port ?? FAM_Serve_Util.resolvePort(local.port);
124
+ const healthUrl = `http://127.0.0.1:${port}`;
125
+ const client = new fam_client_service_1.FAM_CliClient_Service(healthUrl);
126
+ const reachable = await client.isReachable();
127
+ const action = FAM_Serve_Util.decideAction({
128
+ reachable: reachable,
129
+ statusOnly: Boolean(local.status),
130
+ restart: Boolean(local.restart),
131
+ });
132
+ if (action === 'reuse-running') {
133
+ const version = await FAM_Serve_Util.fetchVersion(client);
134
+ return fam_output_util_1.FAM_Output_Util.success({
135
+ options: globals,
136
+ command: 'serve',
137
+ data: { running: true, spawned: false, url: healthUrl, port: port, version: version },
138
+ humanFormatter: () => `✓ A FAM szerver MÁR FUT (reuse — nem indítok másodikat): ${healthUrl}${version ? ` — v${version}` : ''}`,
139
+ });
140
+ }
141
+ if (action === 'report-down') {
142
+ return fam_output_util_1.FAM_Output_Util.success({
143
+ options: globals,
144
+ command: 'serve',
145
+ data: { running: false, spawned: false, url: healthUrl, port: port, version: null },
146
+ humanFormatter: () => `• A FAM szerver NEM fut ezen a porton: ${healthUrl} (--status → nem indítok).`,
147
+ });
148
+ }
149
+ if (action === 'restart') {
150
+ fam_output_util_1.FAM_Output_Util.logInfo(globals, `FAM szerver RESTART: a(z) ${port} porton futó szerver leállítása…`);
151
+ await FAM_Serve_Util.stopServerOnPort(port);
152
+ // A health-down NEM elég: az új szerver bind-preflight-je a TÉNYLEGESEN SZABAD (bindolható) portot
153
+ // igényli (a kill utáni process-halál + TIME_WAIT lassú lehet) → a port bindolhatóságát várjuk.
154
+ const freed = await FAM_Serve_Util.waitForPortFree(port, 12000);
155
+ if (!freed) {
156
+ fam_output_util_1.FAM_Output_Util.logInfo(globals, `⚠ a(z) ${port} port 12s alatt nem szabadult fel — az indítás megpróbálom, `
157
+ + 'de ha bind-hiba van, futtasd újra a `fam serve --restart`-ot.');
158
+ }
159
+ }
160
+ return FAM_Serve_Util.spawnServer({ globals: globals, local: local, port: port, healthUrl: healthUrl, client: client });
161
+ }
162
+ /** Az új szerver indítása (detached default, vagy `--foreground`) + a health-bevárás + a riport. */
163
+ static async spawnServer(set) {
164
+ const entry = FAM_Serve_Util.resolveServerEntry();
165
+ if (!entry) {
166
+ return fam_output_util_1.FAM_Output_Util.failure({
167
+ options: set.globals,
168
+ command: 'serve',
169
+ error: {
170
+ errorCode: 'FAM-CLI-SERVE-001',
171
+ message: 'A FAM szerver-belépő nem található (build/src/index.js).',
172
+ fixHint: 'Buildeld a szervert (`cd server && pnpm run build-base`), vagy állítsd be a `FAM_SERVER_ENTRY` env-et.',
173
+ },
174
+ });
175
+ }
176
+ // A window-/foreground-szerver env-override-jai (a többit a szerver a saját `.env`-jéből olvassa):
177
+ // FAM_SHOW_CONSOLE=false → NINCS külön FEAT-001 tail-ablak (a serve-ablak MAGA a látható konzol → nincs
178
+ // dupla ablak; a user-direktíva szerint az Activity Monitor így redundáns).
179
+ const envOverrides = {
180
+ FAM_SERVER_PORT: String(set.port),
181
+ FAM_SHOW_CONSOLE: 'false',
182
+ // File-log → a detached szerver logjai (import-progress is) FÁJLBÓL OLVASHATÓK (tail), ablak nélkül.
183
+ FAM_LOG_FILE: (0, path_1.join)((0, os_1.tmpdir)(), `fam-server-${set.port}.log`),
184
+ };
185
+ if (set.local.mongodbUri) {
186
+ envOverrides.MONGODB_URI = set.local.mongodbUri;
187
+ }
188
+ if (set.local.dbName) {
189
+ envOverrides.MONGODB_DB_NAME = set.local.dbName;
190
+ }
191
+ const heapMb = FAM_Serve_Util.resolveHeapMb(set.local.heap);
192
+ const nodeArgs = heapMb > 0 ? [`--max-old-space-size=${heapMb}`] : [];
193
+ const detached = !set.local.foreground;
194
+ fam_output_util_1.FAM_Output_Util.logInfo(set.globals, `FAM szerver indítása (${detached ? 'DETACHED — külön, látható ablak, túléli a CLI-t' : 'foreground (attached)'}): `
195
+ + `node ${nodeArgs.join(' ')} ${entry} (REST :${set.port}, heap ${heapMb > 0 ? `${heapMb}MB` : 'node-default'}).`);
196
+ if (!detached) {
197
+ // Foreground (debug): a child stdio inherit, a CLI a process-exit-kódját örökli (vö. `FAM_Start_Util`).
198
+ return FAM_Serve_Util.runForeground([...nodeArgs, entry], { ...process.env, ...envOverrides });
199
+ }
200
+ // DETACHED: a szervert egy KÜLÖN, LÁTHATÓ konzol-ablakban indítjuk (a `start`/terminál teljesen leválasztja
201
+ // a CLI-ről → túléli; az ablak a szerver élő stdout/stderr-jét mutatja). REST-only primary (a belépő
202
+ // argumentum-nélküli ága). A FEAT-001 tail-monitort kikapcsoljuk (FAM_SHOW_CONSOLE=false) — nincs dupla ablak.
203
+ try {
204
+ fam_console_util_1.FAM_Console_Util.spawnServerWindow({
205
+ command: process.execPath,
206
+ args: [...nodeArgs, entry],
207
+ envOverrides: envOverrides,
208
+ port: set.port,
209
+ });
210
+ }
211
+ catch (spawnError) {
212
+ return fam_output_util_1.FAM_Output_Util.failure({
213
+ options: set.globals,
214
+ command: 'serve',
215
+ error: {
216
+ errorCode: 'FAM-CLI-SERVE-002',
217
+ message: `A szerver-ablak nem indítható: ${spawnError.message}.`,
218
+ fixHint: 'Futtasd `fam serve --foreground`-dal (attached, ablak nélkül) a hiba láttatásához.',
219
+ },
220
+ });
221
+ }
222
+ const waitMs = FAM_Serve_Util.resolveWaitMs(set.local.wait);
223
+ const healthy = await FAM_Serve_Util.waitForHealthy(set.client, waitMs);
224
+ if (!healthy) {
225
+ return fam_output_util_1.FAM_Output_Util.failure({
226
+ options: set.globals,
227
+ command: 'serve',
228
+ error: {
229
+ errorCode: 'FAM-CLI-SERVE-003',
230
+ message: `Megnyitottam a szerver-ablakot, de ${Math.round(waitMs / 1000)}s alatt nem lett egészséges: ${set.healthUrl}/api/health.`,
231
+ fixHint: 'Nézd a megnyílt szerver-ablakot (a boot-hibák ott láthatók). Gyakori ok: a Mongo nem fut, vagy a pool-hidratálás hosszabb (emeld a `--wait`-et).',
232
+ },
233
+ });
234
+ }
235
+ // Az indítás állapotának mentése → a `fam serve --restart` (és az opt-in post-commit auto-restart)
236
+ // a HELYES portot/db-t/heap-et állítja vissza, nem vakon a default-ot.
237
+ FAM_Serve_Util.writeServeState({
238
+ port: set.port,
239
+ dbName: set.local.dbName,
240
+ mongodbUri: set.local.mongodbUri,
241
+ heapMb: heapMb,
242
+ });
243
+ const version = await FAM_Serve_Util.fetchVersion(set.client);
244
+ return fam_output_util_1.FAM_Output_Util.success({
245
+ options: set.globals,
246
+ command: 'serve',
247
+ data: { running: true, spawned: true, detached: true, url: set.healthUrl, port: set.port, heapMb: heapMb, version: version },
248
+ humanFormatter: () => `✓ FAM szerver elindítva (DETACHED, külön látható ablak${version ? `, v${version}` : ''}): ${set.healthUrl} — túléli ezt a futást, legközelebb csak rácsatlakozom.`,
249
+ });
250
+ }
251
+ /** Attached (`--foreground`) futás: a child stdio inherit, a CLI a process-exit-kódját örökli. */
252
+ static runForeground(args, childEnv) {
253
+ const child = (0, child_process_1.spawn)(process.execPath, args, { stdio: 'inherit', env: childEnv });
254
+ return new Promise((resolvePromise) => {
255
+ child.on('error', (spawnError) => {
256
+ fam_output_util_1.FAM_Output_Util.logError(`✗ A szerver-process nem indítható: ${spawnError.message}`);
257
+ resolvePromise(fam_cli_const_1.FAM_CliExitCode.operationError);
258
+ });
259
+ child.on('exit', (code) => {
260
+ resolvePromise(code === 0 || code === null ? fam_cli_const_1.FAM_CliExitCode.ok : fam_cli_const_1.FAM_CliExitCode.operationError);
261
+ });
262
+ });
263
+ }
264
+ /** A `/api/health` zöldre-fordulásának bevárása (poll), felső korláttal. `true`, ha időben egészséges lett. */
265
+ static async waitForHealthy(client, timeoutMs) {
266
+ const deadline = Date.now() + timeoutMs;
267
+ while (Date.now() < deadline) {
268
+ if (await client.isReachable(1500)) {
269
+ return true;
270
+ }
271
+ await FAM_Serve_Util.sleep(FAM_Serve_Util.HEALTH_POLL_MS);
272
+ }
273
+ return false;
274
+ }
275
+ /** A port LE-állásának bevárása (a `--restart` kill után, mielőtt újraindítunk), felső korláttal. */
276
+ static async waitForPortFree(port, timeoutMs) {
277
+ const deadline = Date.now() + timeoutMs;
278
+ while (Date.now() < deadline) {
279
+ if (await FAM_Serve_Util.isPortFree(port)) {
280
+ return true;
281
+ }
282
+ await FAM_Serve_Util.sleep(FAM_Serve_Util.HEALTH_POLL_MS);
283
+ }
284
+ return false;
285
+ }
286
+ /** Bindolható-e (szabad-e) a port? Egy próba-`listen` a loopbackon, azonnali close — `true`, ha köthető. */
287
+ static isPortFree(port) {
288
+ return new Promise((resolveCheck) => {
289
+ const tester = net.createServer();
290
+ tester.once('error', () => resolveCheck(false));
291
+ tester.once('listening', () => tester.close(() => resolveCheck(true)));
292
+ tester.listen(port, '127.0.0.1');
293
+ });
294
+ }
295
+ /**
296
+ * A megadott porton FIGYELŐ process leállítása (a `--restart` magja). Platform-natív, fail-safe: Windows →
297
+ * `Get-NetTCPConnection`+`Stop-Process`; POSIX → `lsof -ti:<port> | xargs kill`. A hiba nem dob (a respawn
298
+ * a port-bevárással úgyis kezeli, ha mégis él valami).
299
+ */
300
+ static async stopServerOnPort(port) {
301
+ const isWin = process.platform === 'win32';
302
+ const command = isWin ? (process.env.ComSpec ?? 'powershell.exe') : 'sh';
303
+ const psScript = `$ErrorActionPreference='SilentlyContinue';`
304
+ + `(Get-NetTCPConnection -LocalPort ${port} -State Listen).OwningProcess | Select-Object -Unique | `
305
+ + `ForEach-Object { Stop-Process -Id $_ -Force };`
306
+ // A serve-ablakot (a fam-server-<port>.ps1-t futtató powershell) is leállítjuk → nincs árva,
307
+ // „[FAM szerver kilépett]" zombi-ablak a restart után (különben halmozódnak).
308
+ + `Get-CimInstance Win32_Process -Filter "Name='powershell.exe'" | `
309
+ + `Where-Object { $_.CommandLine -like '*fam-server-${port}*' } | `
310
+ + `ForEach-Object { Stop-Process -Id $_.ProcessId -Force }`;
311
+ const args = isWin
312
+ ? ['-NoProfile', '-Command', psScript]
313
+ : ['-c', `lsof -ti tcp:${port} | xargs -r kill -9`];
314
+ const exe = isWin ? 'powershell.exe' : command;
315
+ await new Promise((resolveKill) => {
316
+ try {
317
+ const child = (0, child_process_1.spawn)(exe, args, { stdio: 'ignore' });
318
+ child.on('error', () => resolveKill());
319
+ child.on('exit', () => resolveKill());
320
+ }
321
+ catch {
322
+ resolveKill();
323
+ }
324
+ });
325
+ }
326
+ /** A futó szerver verziója a `GET /api/health` `version` mezőjéből (vagy `null`, ha nem elérhető). Fail-safe. */
327
+ static async fetchVersion(client) {
328
+ const result = await client.get('/api/health');
329
+ return result.ok && result.data && typeof result.data.version === 'string' ? result.data.version : null;
330
+ }
331
+ /** Az indítás-állapot mentése (fail-safe — a state-write SOHA nem dönti meg a parancsot). */
332
+ static writeServeState(state) {
333
+ try {
334
+ (0, fs_1.writeFileSync)(FAM_Serve_Util.STATE_FILE, JSON.stringify(state));
335
+ }
336
+ catch {
337
+ /* a state-fájl hibája nem kritikus (a --restart ekkor a default-ra esik vissza) */
338
+ }
339
+ }
340
+ /** Az utolsó indítás-állapot betöltése (vagy `null`, ha nincs/olvashatatlan). Fail-safe. */
341
+ static loadServeState() {
342
+ try {
343
+ if (!(0, fs_1.existsSync)(FAM_Serve_Util.STATE_FILE)) {
344
+ return null;
345
+ }
346
+ const parsed = JSON.parse((0, fs_1.readFileSync)(FAM_Serve_Util.STATE_FILE, 'utf8'));
347
+ return typeof parsed.port === 'number' && parsed.port > 0 ? parsed : null;
348
+ }
349
+ catch {
350
+ return null;
351
+ }
352
+ }
353
+ /** Egyszerű ms-alvás (a health-poll köze). */
354
+ static sleep(ms) {
355
+ return new Promise((resolveSleep) => setTimeout(resolveSleep, ms));
356
+ }
357
+ /** A szerver-belépő feloldása (env → resolve → repo-relatív; a publikus boundary szerint spawn, nem import). */
358
+ static resolveServerEntry() {
359
+ const fromEnv = process.env.FAM_SERVER_ENTRY;
360
+ if (fromEnv && (0, fs_1.existsSync)(fromEnv)) {
361
+ return fromEnv;
362
+ }
363
+ // A serve a SZERVER-package CLI-jában él: a serve.command.js futás-időben
364
+ // `<server>/build/src/_cli/_commands/`, így a belépő (`<server>/build/src/index.js`) 2 szint feljebb.
365
+ const candidates = [
366
+ (0, path_1.resolve)(__dirname, '../../index.js'),
367
+ (0, path_1.resolve)(process.cwd(), 'build/src/index.js'),
368
+ (0, path_1.resolve)(process.cwd(), 'server/build/src/index.js'),
369
+ ];
370
+ return candidates.find((candidate) => (0, fs_1.existsSync)(candidate));
371
+ }
372
+ }
373
+ exports.FAM_Serve_Util = FAM_Serve_Util;