@tenonhq/dovetail-core 0.0.85

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 (78) hide show
  1. package/README.md +6 -0
  2. package/dist/FileLogger.js +207 -0
  3. package/dist/FileUtils.js +387 -0
  4. package/dist/Logger.js +88 -0
  5. package/dist/MultiScopeWatcher.js +615 -0
  6. package/dist/PluginManager.js +125 -0
  7. package/dist/_defaultOptionsOLD.js +44 -0
  8. package/dist/allScopesCommands.js +418 -0
  9. package/dist/appUtils.js +929 -0
  10. package/dist/benchmark.js +104 -0
  11. package/dist/bootstrap.js +62 -0
  12. package/dist/claudeCommand.js +60 -0
  13. package/dist/clickupCommands.js +472 -0
  14. package/dist/clickupPushHelper.js +33 -0
  15. package/dist/commander.js +466 -0
  16. package/dist/commands.js +378 -0
  17. package/dist/config.js +697 -0
  18. package/dist/constants.js +15 -0
  19. package/dist/createRecordCommand.js +314 -0
  20. package/dist/dashboardCommand.js +38 -0
  21. package/dist/defaultOptions.js +14 -0
  22. package/dist/deleteRecordCommand.js +282 -0
  23. package/dist/flowDesigner/values.js +55 -0
  24. package/dist/genericUtils.js +189 -0
  25. package/dist/gitUtils.js +99 -0
  26. package/dist/index.js +35 -0
  27. package/dist/initSystem/corePlugin.js +344 -0
  28. package/dist/initSystem/discovery.js +107 -0
  29. package/dist/initSystem/orchestrator.js +408 -0
  30. package/dist/logMessages.js +82 -0
  31. package/dist/loginCommand.js +20 -0
  32. package/dist/migrateCommand.js +123 -0
  33. package/dist/projectFiles.js +32 -0
  34. package/dist/recentEdits.js +66 -0
  35. package/dist/schemaCommand.js +85 -0
  36. package/dist/snClient.js +519 -0
  37. package/dist/tests/benchmarkRefresh.test.js +265 -0
  38. package/dist/tests/clickupCommands.test.js +384 -0
  39. package/dist/tests/clickupPushHelper.test.js +124 -0
  40. package/dist/tests/configFallback.test.js +68 -0
  41. package/dist/tests/cred.test.js +59 -0
  42. package/dist/tests/discovery.test.js +67 -0
  43. package/dist/tests/ensureUpdateSetWarnings.test.js +218 -0
  44. package/dist/tests/errorLogLevels.test.js +273 -0
  45. package/dist/tests/example.test.js +6 -0
  46. package/dist/tests/fileContextSkipReason.test.js +116 -0
  47. package/dist/tests/globalDebounce.test.js +308 -0
  48. package/dist/tests/migrateCommand.test.js +113 -0
  49. package/dist/tests/multi-scope-watcher.test.js +558 -0
  50. package/dist/tests/orchestrator.test.js +23 -0
  51. package/dist/tests/pushFiles.test.js +248 -0
  52. package/dist/tests/rateLimitCoordination.test.js +271 -0
  53. package/dist/tests/resolveConfigReadOnly.test.js +67 -0
  54. package/dist/tests/retryOnHttpErr.test.js +154 -0
  55. package/dist/tests/scopeCaching.test.js +115 -0
  56. package/dist/tests/serializeUpdateSetConfig.test.js +325 -0
  57. package/dist/tests/snClient.fallback.test.js +120 -0
  58. package/dist/tests/syncManifestRefresh.test.js +287 -0
  59. package/dist/tests/syncManifestWhitelist.test.js +192 -0
  60. package/dist/tests/taskClear.test.js +170 -0
  61. package/dist/tests/taskStaleness.test.js +220 -0
  62. package/dist/tests/unwrapSNResponseError.test.js +145 -0
  63. package/dist/tests/v2Values.test.js +79 -0
  64. package/dist/tests/validateTaskId.test.js +304 -0
  65. package/dist/tests/verifyUpdateSetSwitch.test.js +277 -0
  66. package/dist/tests/writeEnvVar.test.js +119 -0
  67. package/dist/updateSetCommands.js +702 -0
  68. package/dist/wizard.js +40 -0
  69. package/package.json +69 -0
  70. package/skills/dove-configure-pipeline.md +158 -0
  71. package/skills/dove-create-plugin.md +174 -0
  72. package/skills/dove-create-record.md +135 -0
  73. package/skills/dove-debug-build.md +117 -0
  74. package/skills/dove-delete-record.md +104 -0
  75. package/skills/dove-manage-tables.md +174 -0
  76. package/skills/dove-manage-update-sets.md +88 -0
  77. package/skills/dove-setup-project.md +154 -0
  78. package/skills/dove-troubleshoot-sync.md +113 -0
package/dist/config.js ADDED
@@ -0,0 +1,697 @@
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.loadConfigs = void 0;
40
+ exports.getConfig = getConfig;
41
+ exports.getConfigPath = getConfigPath;
42
+ exports.checkConfigPath = checkConfigPath;
43
+ exports.getRootDir = getRootDir;
44
+ exports.getManifest = getManifest;
45
+ exports.getManifestPath = getManifestPath;
46
+ exports.getScopeManifestPath = getScopeManifestPath;
47
+ exports.getSourcePath = getSourcePath;
48
+ exports.getSourcePathForScope = getSourcePathForScope;
49
+ exports.getBuildPath = getBuildPath;
50
+ exports.getEnvPath = getEnvPath;
51
+ exports.getDiffPath = getDiffPath;
52
+ exports.getDiffFile = getDiffFile;
53
+ exports.getRefresh = getRefresh;
54
+ exports.getDefaultConfigFile = getDefaultConfigFile;
55
+ exports.generateConfigFile = generateConfigFile;
56
+ exports.loadScopeManifest = loadScopeManifest;
57
+ exports.updateManifest = updateManifest;
58
+ exports.isMultiScopeManifest = isMultiScopeManifest;
59
+ exports.resolveManifestForScope = resolveManifestForScope;
60
+ exports.resolveScopeFromPath = resolveScopeFromPath;
61
+ exports.loadConfigPath = loadConfigPath;
62
+ exports.isDirectiveKey = isDirectiveKey;
63
+ exports.stripDirectiveKeys = stripDirectiveKeys;
64
+ exports.resolveConfigForScope = resolveConfigForScope;
65
+ exports.getReadOnlyTablesForScope = getReadOnlyTablesForScope;
66
+ const path_1 = __importDefault(require("path"));
67
+ const fs_1 = __importStar(require("fs"));
68
+ const Logger_1 = require("./Logger");
69
+ const defaultOptions_1 = require("./defaultOptions");
70
+ // Resolve an artifact path, preferring the dove.* name and falling back to the
71
+ // legacy sinc.* name when only the legacy file exists. Returns the new path if
72
+ // neither exists (so writes default to the new name).
73
+ function resolveDovePath(rootDir, doveName, sincName) {
74
+ const newPath = path_1.default.join(rootDir, doveName);
75
+ const oldPath = path_1.default.join(rootDir, sincName);
76
+ if (fs_1.default.existsSync(newPath))
77
+ return newPath;
78
+ if (fs_1.default.existsSync(oldPath))
79
+ return oldPath;
80
+ return newPath;
81
+ }
82
+ const DEFAULT_CONFIG = {
83
+ sourceDirectory: "src",
84
+ buildDirectory: "build",
85
+ rules: [],
86
+ includes: defaultOptions_1.includes,
87
+ excludes: defaultOptions_1.excludes,
88
+ tableOptions: {},
89
+ refreshInterval: 30,
90
+ scopes: {},
91
+ };
92
+ let root_dir;
93
+ let config;
94
+ let manifest;
95
+ let config_path;
96
+ let source_path;
97
+ let build_path;
98
+ let env_path;
99
+ let manifest_path;
100
+ let diff_path;
101
+ let diff_file;
102
+ let refresh_interval;
103
+ const loadConfigs = async () => {
104
+ try {
105
+ let noConfigPath = false; //Prevents logging error messages during init
106
+ const path = await loadConfigPath();
107
+ if (path)
108
+ config_path = path;
109
+ else
110
+ noConfigPath = true;
111
+ await loadRootDir(noConfigPath);
112
+ const cfg = await loadConfig(noConfigPath);
113
+ if (cfg)
114
+ config = cfg;
115
+ await loadEnvPath();
116
+ await loadSourcePath();
117
+ await loadBuildPath();
118
+ await loadManifestPath();
119
+ await loadManifest();
120
+ await loadDiffPath();
121
+ await loadDiffFile();
122
+ await loadRefresh();
123
+ }
124
+ catch (e) {
125
+ throw e;
126
+ }
127
+ };
128
+ exports.loadConfigs = loadConfigs;
129
+ function getConfig() {
130
+ if (config)
131
+ return config;
132
+ throw new Error("Error getting config");
133
+ }
134
+ function getConfigPath() {
135
+ if (config_path)
136
+ return config_path;
137
+ throw new Error("Error getting config path");
138
+ }
139
+ function checkConfigPath() {
140
+ if (config_path)
141
+ return config_path;
142
+ return false;
143
+ }
144
+ function getRootDir() {
145
+ if (root_dir)
146
+ return root_dir;
147
+ throw new Error("Error getting root directory");
148
+ }
149
+ function getManifest(setup = false) {
150
+ if (manifest)
151
+ return manifest;
152
+ if (!setup)
153
+ throw new Error("Error getting manifest");
154
+ }
155
+ function getManifestPath(scope) {
156
+ if (scope) {
157
+ const rootDir = getRootDir();
158
+ return resolveDovePath(rootDir, `dove.manifest.${scope}.json`, `sinc.manifest.${scope}.json`);
159
+ }
160
+ if (manifest_path)
161
+ return manifest_path;
162
+ throw new Error("Error getting manifest path");
163
+ }
164
+ function getScopeManifestPath(scope) {
165
+ const rootDir = getRootDir();
166
+ return resolveDovePath(rootDir, `dove.manifest.${scope}.json`, `sinc.manifest.${scope}.json`);
167
+ }
168
+ function getSourcePath() {
169
+ if (source_path)
170
+ return source_path;
171
+ throw new Error("Error getting source path");
172
+ }
173
+ function getSourcePathForScope(scopeName) {
174
+ var cfg = getConfig();
175
+ var scopeConfig = cfg.scopes && cfg.scopes[scopeName];
176
+ if (scopeConfig && typeof scopeConfig === "object" && scopeConfig.sourceDirectory) {
177
+ return path_1.default.resolve(getRootDir(), scopeConfig.sourceDirectory);
178
+ }
179
+ return getSourcePath();
180
+ }
181
+ function getBuildPath() {
182
+ if (build_path)
183
+ return build_path;
184
+ throw new Error("Error getting build path");
185
+ }
186
+ function getEnvPath() {
187
+ if (env_path)
188
+ return env_path;
189
+ throw new Error("Error getting env path");
190
+ }
191
+ function getDiffPath() {
192
+ if (diff_path)
193
+ return diff_path;
194
+ throw new Error("Error getting diff path");
195
+ }
196
+ function getDiffFile() {
197
+ if (diff_file)
198
+ return diff_file;
199
+ throw new Error("Error getting diff file");
200
+ }
201
+ function getRefresh() {
202
+ if (refresh_interval)
203
+ return refresh_interval;
204
+ throw new Error("Error getting refresh interval");
205
+ }
206
+ function getDefaultConfigFile() {
207
+ return `
208
+ module.exports = {
209
+ sourceDirectory: "src",
210
+ buildDirectory: "build",
211
+ rules: [],
212
+ excludes:{},
213
+ includes:{},
214
+ tableOptions:{},
215
+ refreshInterval:30
216
+ };
217
+ `.trim();
218
+ }
219
+ /**
220
+ * @description Generates a full dove.config.js with multi-scope support, table whitelist,
221
+ * field type overrides, and plugin rules. Used by `dove init` when creating a new config.
222
+ * @param {Object} params - Configuration parameters
223
+ * @param {Array<{scope: string, sourceDirectory: string}>} params.scopes - Selected scopes with source directories
224
+ * @returns {string} Complete dove.config.js file content
225
+ */
226
+ function generateConfigFile(params) {
227
+ var scopeEntries = params.scopes.map(function (s) {
228
+ return "\t\t" + s.scope + ": {\n\t\t\tsourceDirectory: \"" + s.sourceDirectory + "\",\n\t\t},";
229
+ }).join("\n");
230
+ return "module.exports = {\n" +
231
+ "\tsourceDirectory: \"src\",\n" +
232
+ "\tbuildDirectory: \"build\",\n" +
233
+ "\n" +
234
+ "\t// Plugin Rules Configuration\n" +
235
+ "\trules: [\n" +
236
+ "\t\t{\n" +
237
+ "\t\t\tmatch: /sys_script_include.*\\.ts$/,\n" +
238
+ "\t\t\tplugins: [\n" +
239
+ "\t\t\t\t{\n" +
240
+ "\t\t\t\t\tname: \"@tenonhq/dovetail-typescript-plugin\",\n" +
241
+ "\t\t\t\t\toptions: {\n" +
242
+ "\t\t\t\t\t\ttranspile: true,\n" +
243
+ "\t\t\t\t\t\ttypeCheck: true,\n" +
244
+ "\t\t\t\t\t\ttsconfig: \"./tsconfig.servicenow.json\",\n" +
245
+ "\t\t\t\t\t},\n" +
246
+ "\t\t\t\t},\n" +
247
+ "\t\t\t\t{\n" +
248
+ "\t\t\t\t\tname: \"@tenonhq/dovetail-eslint-plugin\",\n" +
249
+ "\t\t\t\t\toptions: {\n" +
250
+ "\t\t\t\t\t\tconfigFile: \"./.eslintrc.js\",\n" +
251
+ "\t\t\t\t\t\tfix: false,\n" +
252
+ "\t\t\t\t\t\tcache: true,\n" +
253
+ "\t\t\t\t\t},\n" +
254
+ "\t\t\t\t},\n" +
255
+ "\t\t\t\t{\n" +
256
+ "\t\t\t\t\tname: \"@tenonhq/dovetail-babel-plugin\",\n" +
257
+ "\t\t\t\t\toptions: {\n" +
258
+ "\t\t\t\t\t\tconfigFile: \"./.babelrc\",\n" +
259
+ "\t\t\t\t\t},\n" +
260
+ "\t\t\t\t},\n" +
261
+ "\t\t\t\t{\n" +
262
+ "\t\t\t\t\tname: \"@tenonhq/dovetail-prettier-plugin\",\n" +
263
+ "\t\t\t\t\toptions: {\n" +
264
+ "\t\t\t\t\t\tconfigFile: \"./.prettierrc.js\",\n" +
265
+ "\t\t\t\t\t},\n" +
266
+ "\t\t\t\t},\n" +
267
+ "\t\t\t],\n" +
268
+ "\t\t},\n" +
269
+ "\t],\n" +
270
+ "\n" +
271
+ "\tincludes: {\n" +
272
+ "\t\t_tables: [\n" +
273
+ "\t\t\t\"sys_script_include\",\n" +
274
+ "\t\t\t\"sys_script\",\n" +
275
+ "\t\t\t\"sys_ui_script\",\n" +
276
+ "\t\t\t\"sys_ui_page\",\n" +
277
+ "\t\t\t\"sys_ux_client_script\",\n" +
278
+ "\t\t\t\"sys_processor\",\n" +
279
+ "\t\t\t\"sys_ws_operation\",\n" +
280
+ "\t\t\t\"sys_rest_message_fn\",\n" +
281
+ "\t\t\t\"sys_ui_action\",\n" +
282
+ "\t\t\t\"sys_security_acl\",\n" +
283
+ "\t\t\t\"sysevent_script_action\",\n" +
284
+ "\t\t\t\"sys_ux_macroponent\",\n" +
285
+ "\t\t\t\"sys_ux_event\",\n" +
286
+ "\t\t\t\"sys_ux_client_script_include\",\n" +
287
+ "\t\t\t\"sys_ux_screen\",\n" +
288
+ "\t\t\t\"sys_script_fix\",\n" +
289
+ "\t\t],\n" +
290
+ "\t\tsys_script_include: {\n" +
291
+ "\t\t\tscript: { type: \"js\" },\n" +
292
+ "\t\t},\n" +
293
+ "\t\tsys_script: {\n" +
294
+ "\t\t\tscript: { type: \"js\" },\n" +
295
+ "\t\t},\n" +
296
+ "\t\tsys_ui_script: {\n" +
297
+ "\t\t\tscript: { type: \"js\" },\n" +
298
+ "\t\t},\n" +
299
+ "\t\tsys_ui_page: {\n" +
300
+ "\t\t\tprocessing_script: { type: \"js\" },\n" +
301
+ "\t\t\tclient_script: { type: \"js\" },\n" +
302
+ "\t\t\thtml: { type: \"html\" },\n" +
303
+ "\t\t},\n" +
304
+ "\t\tsys_processor: {\n" +
305
+ "\t\t\tscript: { type: \"js\" },\n" +
306
+ "\t\t},\n" +
307
+ "\t\tsys_ws_operation: {\n" +
308
+ "\t\t\toperation_script: { type: \"js\" },\n" +
309
+ "\t\t},\n" +
310
+ "\t\tsys_rest_message_fn: {\n" +
311
+ "\t\t\tcontent: { type: \"txt\" },\n" +
312
+ "\t\t},\n" +
313
+ "\t\tsys_ui_action: {\n" +
314
+ "\t\t\tscript: { type: \"js\" },\n" +
315
+ "\t\t\tclient_script_v2: { type: \"js\" },\n" +
316
+ "\t\t},\n" +
317
+ "\t\tsys_security_acl: {\n" +
318
+ "\t\t\tscript: { type: \"js\" },\n" +
319
+ "\t\t},\n" +
320
+ "\t\tsysevent_script_action: {\n" +
321
+ "\t\t\tscript: { type: \"js\" },\n" +
322
+ "\t\t},\n" +
323
+ "\t\tsys_script_fix: {\n" +
324
+ "\t\t\tscript: { type: \"js\" },\n" +
325
+ "\t\t},\n" +
326
+ "\t\tsys_ux_macroponent: {\n" +
327
+ "\t\t\tcomposition: { type: \"json\" },\n" +
328
+ "\t\t\tprops: { type: \"json\" },\n" +
329
+ "\t\t\tdata: { type: \"json\" },\n" +
330
+ "\t\t\trequired_translations: { type: \"json\" },\n" +
331
+ "\t\t\troot_component_definition: { type: \"json\" },\n" +
332
+ "\t\t\tstate_properties: { type: \"json\" },\n" +
333
+ "\t\t\troot_component_config: { type: \"json\" },\n" +
334
+ "\t\t\tinternal_event_mappings: { type: \"json\" },\n" +
335
+ "\t\t\tstate_persistence_config: { type: \"json\" },\n" +
336
+ "\t\t},\n" +
337
+ "\t\tsys_ux_event: {\n" +
338
+ "\t\t\tdescription: { type: \"txt\" },\n" +
339
+ "\t\t\tevent_name: { type: \"txt\" },\n" +
340
+ "\t\t\tlabel: { type: \"txt\" },\n" +
341
+ "\t\t\tprops: { type: \"json\" },\n" +
342
+ "\t\t\trequired_translations: { type: \"json\" },\n" +
343
+ "\t\t},\n" +
344
+ "\t\tsys_ux_client_script: {\n" +
345
+ "\t\t\tscript: { type: \"js\" },\n" +
346
+ "\t\t\tname: { type: \"txt\" },\n" +
347
+ "\t\t},\n" +
348
+ "\t\tsys_ux_client_script_include: {\n" +
349
+ "\t\t\tscript: { type: \"js\" },\n" +
350
+ "\t\t\tname: { type: \"txt\" },\n" +
351
+ "\t\t},\n" +
352
+ "\t\tsys_ux_screen: {\n" +
353
+ "\t\t\tmacroponent_config: { type: \"json\" },\n" +
354
+ "\t\t\tevent_mappings: { type: \"json\" },\n" +
355
+ "\t\t},\n" +
356
+ "\t\t_scopes: {},\n" +
357
+ "\t},\n" +
358
+ "\n" +
359
+ "\texcludes: {\n" +
360
+ "\t\t_tables: [],\n" +
361
+ "\t},\n" +
362
+ "\n" +
363
+ "\tmanifestOptions: {\n" +
364
+ "\t\tupdateFields: true,\n" +
365
+ "\t\tupdateDependencies: true,\n" +
366
+ "\t},\n" +
367
+ "\n" +
368
+ "\tserver: {\n" +
369
+ "\t\twatchPath: \"./src\",\n" +
370
+ "\t},\n" +
371
+ "\n" +
372
+ "\tscopes: {\n" +
373
+ scopeEntries + "\n" +
374
+ "\t},\n" +
375
+ "};\n";
376
+ }
377
+ async function loadConfig(skipConfigPath = false) {
378
+ if (skipConfigPath) {
379
+ Logger_1.logger.warn("Couldn't find config file. Loading default...");
380
+ return DEFAULT_CONFIG;
381
+ }
382
+ try {
383
+ let configPath = getConfigPath();
384
+ if (configPath) {
385
+ let projectConfig = (await Promise.resolve(`${configPath}`).then(s => __importStar(require(s)))).default;
386
+ // Config is king — no merging with defaults. dove.config.js is the single source of truth.
387
+ var { includes: pIncludes = {}, excludes: pExcludes = {}, tableOptions: pTableOptions = {}, scopes: pScopes = {}, } = projectConfig;
388
+ projectConfig.includes = pIncludes;
389
+ projectConfig.excludes = pExcludes;
390
+ projectConfig.tableOptions = pTableOptions;
391
+ projectConfig.scopes = pScopes;
392
+ return projectConfig;
393
+ }
394
+ else {
395
+ Logger_1.logger.warn("Couldn't find config file. Loading default...");
396
+ return DEFAULT_CONFIG;
397
+ }
398
+ }
399
+ catch (e) {
400
+ let message;
401
+ if (e instanceof Error)
402
+ message = e.message;
403
+ else
404
+ message = String(e);
405
+ Logger_1.logger.warn(message);
406
+ Logger_1.logger.warn("Couldn't find config file. Loading default...");
407
+ return DEFAULT_CONFIG;
408
+ }
409
+ }
410
+ async function loadManifest() {
411
+ try {
412
+ // Try to load legacy single manifest first
413
+ let manifestString = await fs_1.promises.readFile(getManifestPath(), "utf-8");
414
+ manifest = JSON.parse(manifestString);
415
+ }
416
+ catch (e) {
417
+ // If no single manifest, try to load all scope-specific manifests
418
+ manifest = await loadAllScopeManifests();
419
+ }
420
+ }
421
+ async function loadAllScopeManifests() {
422
+ try {
423
+ const rootDir = getRootDir();
424
+ const files = await fs_1.promises.readdir(rootDir);
425
+ const manifestFiles = files.filter(f => ((f.startsWith('dove.manifest.') && f !== 'dove.manifest.json') ||
426
+ (f.startsWith('sinc.manifest.') && f !== 'sinc.manifest.json')) &&
427
+ f.endsWith('.json'));
428
+ if (manifestFiles.length === 0) {
429
+ return undefined;
430
+ }
431
+ // Combine all scope manifests into a single structure for backward compatibility
432
+ const combinedManifest = {};
433
+ for (const file of manifestFiles) {
434
+ const scope = file.replace(/^(dove|sinc)\.manifest\./, '').replace('.json', '');
435
+ const manifestPath = path_1.default.join(rootDir, file);
436
+ try {
437
+ const content = await fs_1.promises.readFile(manifestPath, "utf-8");
438
+ const scopeManifest = JSON.parse(content);
439
+ // If the manifest already has the scope at root level, use it directly
440
+ if (scopeManifest.scope && scopeManifest.tables) {
441
+ combinedManifest[scope] = scopeManifest;
442
+ }
443
+ else {
444
+ // Otherwise wrap it
445
+ combinedManifest[scope] = scopeManifest;
446
+ }
447
+ }
448
+ catch (e) {
449
+ Logger_1.logger.warn(`Failed to load manifest for scope ${scope}: ${e}`);
450
+ }
451
+ }
452
+ return Object.keys(combinedManifest).length > 0 ? combinedManifest : undefined;
453
+ }
454
+ catch (e) {
455
+ return undefined;
456
+ }
457
+ }
458
+ async function loadScopeManifest(scope) {
459
+ try {
460
+ const manifestPath = getScopeManifestPath(scope);
461
+ const content = await fs_1.promises.readFile(manifestPath, "utf-8");
462
+ return JSON.parse(content);
463
+ }
464
+ catch (e) {
465
+ return undefined;
466
+ }
467
+ }
468
+ function updateManifest(man) {
469
+ manifest = man;
470
+ }
471
+ function isMultiScopeManifest(man) {
472
+ return typeof man === "object" && man !== null && !man.scope && !man.tables;
473
+ }
474
+ function resolveManifestForScope(man, scope) {
475
+ if (!isMultiScopeManifest(man)) {
476
+ if (!scope || man.scope === scope) {
477
+ return man;
478
+ }
479
+ return undefined;
480
+ }
481
+ var scopeMan = man[scope];
482
+ if (scopeMan && scopeMan.tables) {
483
+ return scopeMan;
484
+ }
485
+ return undefined;
486
+ }
487
+ function resolveScopeFromPath(filePath) {
488
+ var cfg = getConfig();
489
+ if (!cfg.scopes)
490
+ return undefined;
491
+ var scopeNames = Object.keys(cfg.scopes);
492
+ for (var i = 0; i < scopeNames.length; i++) {
493
+ var scopeSourcePath = getSourcePathForScope(scopeNames[i]);
494
+ if (filePath.indexOf(scopeSourcePath) === 0) {
495
+ return scopeNames[i];
496
+ }
497
+ }
498
+ return undefined;
499
+ }
500
+ // Exported for tests only.
501
+ async function loadConfigPath(pth) {
502
+ if (!pth) {
503
+ pth = process.cwd();
504
+ }
505
+ // check to see if config is found
506
+ let files = await fs_1.promises.readdir(pth);
507
+ if (files.includes("dove.config.js")) {
508
+ return path_1.default.join(pth, "dove.config.js");
509
+ }
510
+ if (files.includes("sinc.config.js")) {
511
+ Logger_1.logger.warn("Found legacy 'sinc.config.js' — please rename to 'dove.config.js' (run 'npx dove migrate'). Continuing with the legacy file.");
512
+ return path_1.default.join(pth, "sinc.config.js");
513
+ }
514
+ if (isRoot(pth)) {
515
+ return false;
516
+ }
517
+ return loadConfigPath(path_1.default.dirname(pth));
518
+ function isRoot(pth) {
519
+ return path_1.default.parse(pth).root === pth;
520
+ }
521
+ }
522
+ async function loadRefresh() {
523
+ let { refreshInterval = 30 } = getConfig();
524
+ refresh_interval = refreshInterval;
525
+ }
526
+ async function loadSourcePath() {
527
+ let rootDir = getRootDir();
528
+ let { sourceDirectory = "src" } = getConfig();
529
+ source_path = path_1.default.join(rootDir, sourceDirectory);
530
+ }
531
+ async function loadBuildPath() {
532
+ let rootDir = getRootDir();
533
+ let { buildDirectory = "build" } = getConfig();
534
+ build_path = path_1.default.join(rootDir, buildDirectory);
535
+ }
536
+ async function loadEnvPath() {
537
+ let rootDir = getRootDir();
538
+ env_path = path_1.default.join(rootDir, ".env");
539
+ }
540
+ async function loadManifestPath() {
541
+ let rootDir = getRootDir();
542
+ manifest_path = resolveDovePath(rootDir, "dove.manifest.json", "sinc.manifest.json");
543
+ }
544
+ async function loadDiffPath() {
545
+ let rootDir = getRootDir();
546
+ diff_path = resolveDovePath(rootDir, "dove.diff.manifest.json", "sinc.diff.manifest.json");
547
+ }
548
+ async function loadDiffFile() {
549
+ try {
550
+ let diffString = await fs_1.promises.readFile(getDiffPath(), "utf-8");
551
+ diff_file = JSON.parse(diffString);
552
+ }
553
+ catch (e) {
554
+ diff_file = undefined;
555
+ }
556
+ }
557
+ async function loadRootDir(skip) {
558
+ if (skip) {
559
+ root_dir = process.cwd();
560
+ return;
561
+ }
562
+ let configPath = getConfigPath();
563
+ if (configPath)
564
+ root_dir = path_1.default.dirname(configPath);
565
+ else
566
+ root_dir = process.cwd();
567
+ }
568
+ function isDirectiveKey(key) {
569
+ return key.charAt(0) === "_";
570
+ }
571
+ function stripDirectiveKeys(obj) {
572
+ var result = {};
573
+ var keys = Object.keys(obj || {});
574
+ for (var i = 0; i < keys.length; i++) {
575
+ if (!isDirectiveKey(keys[i])) {
576
+ result[keys[i]] = obj[keys[i]];
577
+ }
578
+ }
579
+ return result;
580
+ }
581
+ function resolveConfigForScope(scopeName, cfgOverride) {
582
+ var cfg = cfgOverride || getConfig();
583
+ var cfgIncludes = cfg.includes || {};
584
+ var cfgExcludes = cfg.excludes || {};
585
+ // Backward compat: support old "table" key (no underscore)
586
+ var globalTables = cfgIncludes._tables || [];
587
+ if (!cfgIncludes._tables && Array.isArray(cfgIncludes.table)) {
588
+ Logger_1.logger.warn("Deprecation: 'table' key in includes is deprecated. Use '_tables' instead.");
589
+ globalTables = cfgIncludes.table;
590
+ }
591
+ // Resolve scope-specific overrides
592
+ var scopesDirective = cfgIncludes._scopes || {};
593
+ var scopeOverride = scopesDirective[scopeName] || {};
594
+ var scopeTables = scopeOverride._tables || [];
595
+ // Deduplicated union of global + scope tables
596
+ var tableSet = {};
597
+ var i;
598
+ for (i = 0; i < globalTables.length; i++) {
599
+ tableSet[globalTables[i]] = true;
600
+ }
601
+ for (i = 0; i < scopeTables.length; i++) {
602
+ tableSet[scopeTables[i]] = true;
603
+ }
604
+ // Field overrides: global non-_ keys and scope-specific non-_ keys
605
+ var globalFieldOverrides = stripDirectiveKeys(cfgIncludes);
606
+ var scopeFieldOverrides = stripDirectiveKeys(scopeOverride);
607
+ // Implicitly add tables that have field overrides to the whitelist
608
+ var globalOverrideTables = Object.keys(globalFieldOverrides);
609
+ for (i = 0; i < globalOverrideTables.length; i++) {
610
+ if (!tableSet[globalOverrideTables[i]]) {
611
+ tableSet[globalOverrideTables[i]] = true;
612
+ }
613
+ }
614
+ var scopeOverrideTables = Object.keys(scopeFieldOverrides);
615
+ for (i = 0; i < scopeOverrideTables.length; i++) {
616
+ if (!tableSet[scopeOverrideTables[i]]) {
617
+ tableSet[scopeOverrideTables[i]] = true;
618
+ }
619
+ }
620
+ var resolvedTables = Object.keys(tableSet);
621
+ // Resolve excludes _tables
622
+ var excludeTables = cfgExcludes._tables || [];
623
+ if (!cfgExcludes._tables && Array.isArray(cfgExcludes.table)) {
624
+ excludeTables = cfgExcludes.table;
625
+ }
626
+ // Remove excluded tables from the resolved list
627
+ if (excludeTables.length > 0) {
628
+ var excludeSet = {};
629
+ for (i = 0; i < excludeTables.length; i++) {
630
+ excludeSet[excludeTables[i]] = true;
631
+ }
632
+ resolvedTables = resolvedTables.filter(function (t) {
633
+ return !excludeSet[t];
634
+ });
635
+ }
636
+ // Deep merge field overrides: global + scope, scope wins on conflicts per field
637
+ var fieldOverrides = {};
638
+ var allTableKeys = {};
639
+ var gKeys = Object.keys(globalFieldOverrides);
640
+ var sKeys = Object.keys(scopeFieldOverrides);
641
+ for (i = 0; i < gKeys.length; i++) {
642
+ allTableKeys[gKeys[i]] = true;
643
+ }
644
+ for (i = 0; i < sKeys.length; i++) {
645
+ allTableKeys[sKeys[i]] = true;
646
+ }
647
+ for (var tblKey in allTableKeys) {
648
+ var globalEntry = globalFieldOverrides[tblKey];
649
+ var scopeEntry = scopeFieldOverrides[tblKey];
650
+ if (globalEntry && scopeEntry && typeof globalEntry === "object" && typeof scopeEntry === "object") {
651
+ fieldOverrides[tblKey] = Object.assign({}, globalEntry, scopeEntry);
652
+ }
653
+ else {
654
+ fieldOverrides[tblKey] = scopeEntry || globalEntry;
655
+ }
656
+ }
657
+ // API includes: merged field overrides (no _ keys)
658
+ var apiIncludes = Object.assign({}, fieldOverrides);
659
+ // API excludes: strip _ keys
660
+ var apiExcludes = stripDirectiveKeys(cfgExcludes);
661
+ // Read-only tables: union of global _readOnlyTables and scope-level override.
662
+ // A table flagged read-only is still pulled from the instance but pushes are
663
+ // skipped. Default when absent: empty (bidirectional for all tables).
664
+ var globalReadOnly = Array.isArray(cfgIncludes._readOnlyTables)
665
+ ? cfgIncludes._readOnlyTables
666
+ : [];
667
+ var scopeReadOnly = Array.isArray(scopeOverride._readOnlyTables)
668
+ ? scopeOverride._readOnlyTables
669
+ : [];
670
+ var readOnlySet = {};
671
+ for (i = 0; i < globalReadOnly.length; i++) {
672
+ readOnlySet[globalReadOnly[i]] = true;
673
+ }
674
+ for (i = 0; i < scopeReadOnly.length; i++) {
675
+ readOnlySet[scopeReadOnly[i]] = true;
676
+ }
677
+ var resolvedReadOnly = Object.keys(readOnlySet);
678
+ return {
679
+ tables: resolvedTables,
680
+ fieldOverrides: fieldOverrides,
681
+ apiIncludes: apiIncludes,
682
+ apiExcludes: apiExcludes,
683
+ readOnlyTables: resolvedReadOnly,
684
+ };
685
+ }
686
+ // Convenience wrapper for push-side lookups — returns a Set for O(1) membership.
687
+ // Fails safe (empty set = all tables writable) when config isn't available
688
+ // rather than blocking a push over a lookup error.
689
+ function getReadOnlyTablesForScope(scopeName) {
690
+ try {
691
+ var resolved = resolveConfigForScope(scopeName);
692
+ return new Set(resolved.readOnlyTables || []);
693
+ }
694
+ catch (e) {
695
+ return new Set();
696
+ }
697
+ }