@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
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.CONCURRENCY_BUILD = exports.CONCURRENCY_PUSH = exports.CONCURRENCY_FILES = exports.CONCURRENCY_RECORDS = exports.CONCURRENCY_TABLES = exports.PUSH_RETRY_LIMIT = exports.PUSH_RETRY_WAIT = exports.PATH_DELIMITER = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ exports.PATH_DELIMITER = `${path_1.default.delimiter}${path_1.default.delimiter}`;
9
+ exports.PUSH_RETRY_WAIT = 3000;
10
+ exports.PUSH_RETRY_LIMIT = 3;
11
+ exports.CONCURRENCY_TABLES = 2;
12
+ exports.CONCURRENCY_RECORDS = 5;
13
+ exports.CONCURRENCY_FILES = 10;
14
+ exports.CONCURRENCY_PUSH = 3;
15
+ exports.CONCURRENCY_BUILD = 5;
@@ -0,0 +1,314 @@
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.createRecordCommand = createRecordCommand;
40
+ const fs_1 = __importDefault(require("fs"));
41
+ const path_1 = __importDefault(require("path"));
42
+ const inquirer_1 = __importDefault(require("inquirer"));
43
+ const chalk_1 = __importDefault(require("chalk"));
44
+ const snClient_1 = require("./snClient");
45
+ const Logger_1 = require("./Logger");
46
+ const FileLogger_1 = require("./FileLogger");
47
+ const commands_1 = require("./commands");
48
+ const ConfigManager = __importStar(require("./config"));
49
+ const AppUtils = __importStar(require("./appUtils"));
50
+ const projectFiles_1 = require("./projectFiles");
51
+ const getUpdateSetConfig = () => {
52
+ const configPath = (0, projectFiles_1.getUpdateSetsConfigPath)();
53
+ try {
54
+ if (fs_1.default.existsSync(configPath)) {
55
+ return JSON.parse(fs_1.default.readFileSync(configPath, "utf8"));
56
+ }
57
+ }
58
+ catch (e) {
59
+ // Ignore parse errors
60
+ }
61
+ return {};
62
+ };
63
+ /**
64
+ * Parses --field flag values from "key=value" format into an object.
65
+ */
66
+ function parseFieldFlags(fieldArgs) {
67
+ const fields = {};
68
+ for (var i = 0; i < fieldArgs.length; i++) {
69
+ var arg = fieldArgs[i];
70
+ var eqIndex = arg.indexOf("=");
71
+ if (eqIndex === -1) {
72
+ Logger_1.logger.warn("Skipping invalid --field value (expected key=value): " + arg);
73
+ continue;
74
+ }
75
+ var key = arg.substring(0, eqIndex);
76
+ var value = arg.substring(eqIndex + 1);
77
+ fields[key] = value;
78
+ }
79
+ return fields;
80
+ }
81
+ /**
82
+ * Loads field values from a JSON file.
83
+ */
84
+ function loadFieldsFromFile(filePath) {
85
+ var resolvedPath = path_1.default.resolve(process.cwd(), filePath);
86
+ if (!fs_1.default.existsSync(resolvedPath)) {
87
+ throw new Error("File not found: " + resolvedPath);
88
+ }
89
+ var content = fs_1.default.readFileSync(resolvedPath, "utf8");
90
+ var parsed = JSON.parse(content);
91
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
92
+ throw new Error("JSON file must contain an object with field key-value pairs");
93
+ }
94
+ return parsed;
95
+ }
96
+ /**
97
+ * Resolves the target scope from args, manifest, or user prompt.
98
+ */
99
+ async function resolveScope(args) {
100
+ if (args.scope) {
101
+ return args.scope;
102
+ }
103
+ // Try to get scope from current manifest
104
+ try {
105
+ var manifest = ConfigManager.getManifest();
106
+ if (manifest && !ConfigManager.isMultiScopeManifest(manifest) && manifest.scope) {
107
+ return manifest.scope;
108
+ }
109
+ }
110
+ catch (e) {
111
+ // No manifest available
112
+ }
113
+ // Try to get scopes from config
114
+ try {
115
+ var config = ConfigManager.getConfig();
116
+ if (config.scopes) {
117
+ var scopeNames = Object.keys(config.scopes);
118
+ if (scopeNames.length === 1) {
119
+ return scopeNames[0];
120
+ }
121
+ if (scopeNames.length > 1 && !args.ci) {
122
+ var choices = scopeNames.map(function (s) {
123
+ return { name: s, value: s };
124
+ });
125
+ var answers = await inquirer_1.default.prompt([
126
+ {
127
+ type: "list",
128
+ name: "scope",
129
+ message: "Select target scope:",
130
+ choices: choices,
131
+ },
132
+ ]);
133
+ return answers.scope;
134
+ }
135
+ }
136
+ }
137
+ catch (e) {
138
+ // No config available
139
+ }
140
+ if (args.ci) {
141
+ throw new Error("Scope is required in CI mode. Use --scope flag.");
142
+ }
143
+ var scopeAnswer = await inquirer_1.default.prompt([
144
+ {
145
+ type: "input",
146
+ name: "scope",
147
+ message: "Target scope (e.g., x_cadso_core):",
148
+ validate: function (input) {
149
+ if (!input || input.trim() === "") {
150
+ return "Scope is required";
151
+ }
152
+ return true;
153
+ },
154
+ },
155
+ ]);
156
+ return scopeAnswer.scope;
157
+ }
158
+ /**
159
+ * Main create record command handler.
160
+ */
161
+ async function createRecordCommand(args) {
162
+ (0, commands_1.setLogLevel)(args);
163
+ var typedArgs = args;
164
+ try {
165
+ var table = typedArgs.table;
166
+ if (!table) {
167
+ Logger_1.logger.error("Table name is required");
168
+ process.exit(1);
169
+ }
170
+ FileLogger_1.fileLogger.debug("Create record: table=" + table);
171
+ // 1. Build field values from all sources
172
+ var fields = {};
173
+ // Load from JSON file if provided
174
+ if (typedArgs.from) {
175
+ Logger_1.logger.info("Loading fields from " + typedArgs.from);
176
+ var fileFields = loadFieldsFromFile(typedArgs.from);
177
+ Object.assign(fields, fileFields);
178
+ }
179
+ // Merge inline --field values (override JSON)
180
+ if (typedArgs.field && typedArgs.field.length > 0) {
181
+ var flagFields = parseFieldFlags(typedArgs.field);
182
+ Object.assign(fields, flagFields);
183
+ }
184
+ // Add --name to fields if provided
185
+ if (typedArgs.name) {
186
+ fields.name = typedArgs.name;
187
+ }
188
+ // 2. Prompt for missing required fields
189
+ if (!fields.name && !typedArgs.ci) {
190
+ var nameAnswer = await inquirer_1.default.prompt([
191
+ {
192
+ type: "input",
193
+ name: "name",
194
+ message: "Record name:",
195
+ validate: function (input) {
196
+ if (!input || input.trim() === "") {
197
+ return "Record name is required";
198
+ }
199
+ return true;
200
+ },
201
+ },
202
+ ]);
203
+ fields.name = nameAnswer.name;
204
+ }
205
+ if (!fields.name) {
206
+ Logger_1.logger.error("Record name is required. Use --name or --from with a JSON file.");
207
+ process.exit(1);
208
+ }
209
+ // 3. Resolve scope
210
+ var scope = await resolveScope(typedArgs);
211
+ Logger_1.logger.info("Scope: " + chalk_1.default.cyan(scope));
212
+ // 4. Check update set configuration
213
+ var updateSetConfig = getUpdateSetConfig();
214
+ var updateSet = updateSetConfig[scope];
215
+ var updateSetSysId;
216
+ if (updateSet) {
217
+ Logger_1.logger.info("Update set: " + chalk_1.default.cyan(updateSet.name));
218
+ updateSetSysId = updateSet.sys_id;
219
+ }
220
+ // 5. Confirmation prompt
221
+ if (!typedArgs.ci) {
222
+ Logger_1.logger.info("");
223
+ Logger_1.logger.info(chalk_1.default.bold("Create Record Summary:"));
224
+ Logger_1.logger.info(" Table: " + chalk_1.default.cyan(table));
225
+ Logger_1.logger.info(" Name: " + chalk_1.default.cyan(fields.name));
226
+ Logger_1.logger.info(" Scope: " + chalk_1.default.cyan(scope));
227
+ if (updateSet) {
228
+ Logger_1.logger.info(" Update Set: " + chalk_1.default.cyan(updateSet.name));
229
+ }
230
+ var fieldNames = Object.keys(fields).filter(function (f) {
231
+ return f !== "name";
232
+ });
233
+ if (fieldNames.length > 0) {
234
+ Logger_1.logger.info(" Fields: " + fieldNames.join(", "));
235
+ }
236
+ Logger_1.logger.info("");
237
+ var confirmAnswer = await inquirer_1.default.prompt([
238
+ {
239
+ type: "confirm",
240
+ name: "confirmed",
241
+ message: "Create this record on " +
242
+ (process.env.SN_INSTANCE || "the instance") +
243
+ "?",
244
+ default: true,
245
+ },
246
+ ]);
247
+ if (!confirmAnswer.confirmed) {
248
+ Logger_1.logger.info("Cancelled.");
249
+ return;
250
+ }
251
+ }
252
+ // 6. Call the create endpoint
253
+ Logger_1.logger.info("Creating record...");
254
+ FileLogger_1.fileLogger.debug("Create request:", JSON.stringify({
255
+ table: table,
256
+ fields: fields,
257
+ scope: scope,
258
+ update_set_sys_id: updateSetSysId,
259
+ }));
260
+ var client = (0, snClient_1.defaultClient)();
261
+ var createResponse = await client.createRecord({
262
+ table: table,
263
+ fields: fields,
264
+ scope: scope,
265
+ update_set_sys_id: updateSetSysId,
266
+ });
267
+ var result = createResponse.data;
268
+ // Handle wrapped response
269
+ if (result && result.result) {
270
+ result = result.result;
271
+ }
272
+ var resultData = result;
273
+ if (resultData.error) {
274
+ Logger_1.logger.error("Failed to create record: " + resultData.error);
275
+ process.exit(1);
276
+ }
277
+ var newSysId = resultData.sys_id;
278
+ var recordName = resultData.name || fields.name;
279
+ Logger_1.logger.success(chalk_1.default.green("Record created: ") +
280
+ chalk_1.default.bold(recordName) +
281
+ " (" +
282
+ newSysId +
283
+ ")");
284
+ // 7. Full round-trip: pull the record back locally
285
+ Logger_1.logger.info("Syncing record to local files...");
286
+ FileLogger_1.fileLogger.debug("Starting manifest sync for scope:", scope);
287
+ try {
288
+ await AppUtils.syncManifest(scope);
289
+ var sourcePath = ConfigManager.getSourcePath();
290
+ var localPath = path_1.default.join(sourcePath, table, recordName);
291
+ Logger_1.logger.success(chalk_1.default.green("Local files created at: ") + localPath);
292
+ }
293
+ catch (syncErr) {
294
+ Logger_1.logger.warn("Record created on instance but local sync failed.");
295
+ Logger_1.logger.warn("Run 'npx dove refresh' to pull the record locally.");
296
+ if (syncErr instanceof Error) {
297
+ FileLogger_1.fileLogger.error("Sync error:", syncErr.message);
298
+ }
299
+ }
300
+ }
301
+ catch (e) {
302
+ Logger_1.logger.error("Failed to create record");
303
+ if (e instanceof Error) {
304
+ Logger_1.logger.error(e.message);
305
+ if (e.response) {
306
+ var respStatus = e.response.status;
307
+ var respData = e.response.data;
308
+ Logger_1.logger.error("Server responded with status " + respStatus);
309
+ FileLogger_1.fileLogger.error("Create failed — status: " + respStatus + ", response: " + JSON.stringify(respData));
310
+ }
311
+ }
312
+ process.exit(1);
313
+ }
314
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dashboardCommand = dashboardCommand;
4
+ const commands_1 = require("./commands");
5
+ const Logger_1 = require("./Logger");
6
+ const child_process_1 = require("child_process");
7
+ async function dashboardCommand(args) {
8
+ (0, commands_1.setLogLevel)(args);
9
+ let serverPath;
10
+ try {
11
+ serverPath = require.resolve("@tenonhq/dovetail-dashboard/server.js");
12
+ }
13
+ catch (e) {
14
+ throw new Error("Dashboard package not installed. Run: npm install @tenonhq/dovetail-dashboard");
15
+ }
16
+ var port = args.port ? String(args.port) : (process.env.DASHBOARD_PORT || "3456");
17
+ Logger_1.logger.info("Starting Update Set Dashboard...");
18
+ const server = (0, child_process_1.spawn)("node", [serverPath], {
19
+ cwd: process.cwd(),
20
+ stdio: "inherit",
21
+ env: { ...process.env, DASHBOARD_PORT: port },
22
+ });
23
+ // Open browser after a short delay
24
+ setTimeout(() => {
25
+ const url = "http://localhost:" + port;
26
+ (0, child_process_1.spawn)("open", [url]);
27
+ }, 1000);
28
+ server.on("close", (code) => {
29
+ process.exit(code || 0);
30
+ });
31
+ // Forward signals
32
+ process.on("SIGINT", () => {
33
+ server.kill("SIGINT");
34
+ });
35
+ process.on("SIGTERM", () => {
36
+ server.kill("SIGTERM");
37
+ });
38
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tableOptions = exports.scopes = exports.includes = exports.excludes = void 0;
4
+ // INTENTIONALLY EMPTY — dove.config.js is the single source of truth.
5
+ // Legacy defaults (26 excluded tables + content_css include) were removed
6
+ // during the config-as-king overhaul. See Claude memory for the preserved list.
7
+ let excludes = {};
8
+ exports.excludes = excludes;
9
+ let includes = {};
10
+ exports.includes = includes;
11
+ let tableOptions = {};
12
+ exports.tableOptions = tableOptions;
13
+ let scopes = {};
14
+ exports.scopes = scopes;
@@ -0,0 +1,282 @@
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.deleteRecordCommand = deleteRecordCommand;
40
+ const fs_1 = __importDefault(require("fs"));
41
+ const path_1 = __importDefault(require("path"));
42
+ const inquirer_1 = __importDefault(require("inquirer"));
43
+ const chalk_1 = __importDefault(require("chalk"));
44
+ const snClient_1 = require("./snClient");
45
+ const Logger_1 = require("./Logger");
46
+ const FileLogger_1 = require("./FileLogger");
47
+ const commands_1 = require("./commands");
48
+ const ConfigManager = __importStar(require("./config"));
49
+ const FileUtils = __importStar(require("./FileUtils"));
50
+ /**
51
+ * Resolves the target scope from args, manifest, or user prompt.
52
+ */
53
+ async function resolveScope(args) {
54
+ if (args.scope) {
55
+ return args.scope;
56
+ }
57
+ // Try to get scope from current manifest
58
+ try {
59
+ var manifest = ConfigManager.getManifest();
60
+ if (manifest && !ConfigManager.isMultiScopeManifest(manifest) && manifest.scope) {
61
+ return manifest.scope;
62
+ }
63
+ }
64
+ catch (e) {
65
+ // No manifest available
66
+ }
67
+ // Try to get scopes from config
68
+ try {
69
+ var config = ConfigManager.getConfig();
70
+ if (config.scopes) {
71
+ var scopeNames = Object.keys(config.scopes);
72
+ if (scopeNames.length === 1) {
73
+ return scopeNames[0];
74
+ }
75
+ if (scopeNames.length > 1 && !args.ci) {
76
+ var choices = scopeNames.map(function (s) {
77
+ return { name: s, value: s };
78
+ });
79
+ var answers = await inquirer_1.default.prompt([
80
+ {
81
+ type: "list",
82
+ name: "scope",
83
+ message: "Select target scope:",
84
+ choices: choices,
85
+ },
86
+ ]);
87
+ return answers.scope;
88
+ }
89
+ }
90
+ }
91
+ catch (e) {
92
+ // No config available
93
+ }
94
+ if (args.ci) {
95
+ throw new Error("Scope is required in CI mode. Use --scope flag.");
96
+ }
97
+ var scopeAnswer = await inquirer_1.default.prompt([
98
+ {
99
+ type: "input",
100
+ name: "scope",
101
+ message: "Target scope (e.g., x_cadso_core):",
102
+ validate: function (input) {
103
+ if (!input || input.trim() === "") {
104
+ return "Scope is required";
105
+ }
106
+ return true;
107
+ },
108
+ },
109
+ ]);
110
+ return scopeAnswer.scope;
111
+ }
112
+ /**
113
+ * Main delete record command handler.
114
+ */
115
+ async function deleteRecordCommand(args) {
116
+ (0, commands_1.setLogLevel)(args);
117
+ var typedArgs = args;
118
+ try {
119
+ var table = typedArgs.table;
120
+ if (!table) {
121
+ Logger_1.logger.error("Table name is required");
122
+ process.exit(1);
123
+ }
124
+ var name = typedArgs.name;
125
+ var sysId = typedArgs.sysid;
126
+ if (!name && !sysId) {
127
+ if (typedArgs.ci) {
128
+ Logger_1.logger.error("Record name or --sysid is required. Use positional name or --sysid flag.");
129
+ process.exit(1);
130
+ }
131
+ var nameAnswer = await inquirer_1.default.prompt([
132
+ {
133
+ type: "input",
134
+ name: "name",
135
+ message: "Record name to delete:",
136
+ validate: function (input) {
137
+ if (!input || input.trim() === "") {
138
+ return "Record name is required";
139
+ }
140
+ return true;
141
+ },
142
+ },
143
+ ]);
144
+ name = nameAnswer.name;
145
+ }
146
+ FileLogger_1.fileLogger.debug("Delete record: table=" + table + " name=" + (name || "n/a") + " sysId=" + (sysId || "from manifest"));
147
+ // 1. Resolve scope
148
+ var scope = await resolveScope(typedArgs);
149
+ Logger_1.logger.info("Scope: " + chalk_1.default.cyan(scope));
150
+ // 2. Resolve sys_id from manifest if not provided
151
+ if (!sysId) {
152
+ var scopeManifest = await ConfigManager.loadScopeManifest(scope);
153
+ if (!scopeManifest ||
154
+ !scopeManifest.tables ||
155
+ !scopeManifest.tables[table] ||
156
+ !scopeManifest.tables[table].records ||
157
+ !scopeManifest.tables[table].records[name]) {
158
+ Logger_1.logger.error("Record not found in manifest: " +
159
+ table +
160
+ "/" +
161
+ name +
162
+ " (scope: " +
163
+ scope +
164
+ ")");
165
+ Logger_1.logger.error("Use --sysid to delete by sys_id directly.");
166
+ process.exit(1);
167
+ }
168
+ sysId = scopeManifest.tables[table].records[name].sys_id;
169
+ Logger_1.logger.info("Resolved sys_id: " + chalk_1.default.cyan(sysId));
170
+ }
171
+ // 3. Confirmation prompt
172
+ if (!typedArgs.ci) {
173
+ Logger_1.logger.info("");
174
+ Logger_1.logger.info(chalk_1.default.bold.red("Delete Record:"));
175
+ Logger_1.logger.info(" Table: " + chalk_1.default.cyan(table));
176
+ if (name) {
177
+ Logger_1.logger.info(" Name: " + chalk_1.default.cyan(name));
178
+ }
179
+ Logger_1.logger.info(" Scope: " + chalk_1.default.cyan(scope));
180
+ Logger_1.logger.info(" Sys ID: " + chalk_1.default.cyan(sysId));
181
+ if (typedArgs.keepLocal) {
182
+ Logger_1.logger.info(" Keep Local: " + chalk_1.default.yellow("yes (local files will be preserved)"));
183
+ }
184
+ Logger_1.logger.info("");
185
+ var confirmAnswer = await inquirer_1.default.prompt([
186
+ {
187
+ type: "confirm",
188
+ name: "confirmed",
189
+ message: chalk_1.default.red("DELETE") +
190
+ " this record from " +
191
+ (process.env.SN_INSTANCE || "the instance") +
192
+ "?",
193
+ default: false,
194
+ },
195
+ ]);
196
+ if (!confirmAnswer.confirmed) {
197
+ Logger_1.logger.info("Cancelled.");
198
+ return;
199
+ }
200
+ }
201
+ // 4. Call the delete endpoint
202
+ Logger_1.logger.info("Deleting " + table + "/" + (name || sysId) + " from " + (process.env.SN_INSTANCE || "instance") + "...");
203
+ var client = (0, snClient_1.defaultClient)();
204
+ var deleteResponse = await client.deleteRecord({
205
+ table: table,
206
+ sys_id: sysId,
207
+ scope: scope,
208
+ });
209
+ var result = deleteResponse.data;
210
+ // Handle wrapped response
211
+ if (result && result.result) {
212
+ result = result.result;
213
+ }
214
+ var resultData = result;
215
+ if (resultData.error) {
216
+ Logger_1.logger.error("Failed to delete record: " + resultData.error);
217
+ process.exit(1);
218
+ }
219
+ var recordName = resultData.name || name || sysId;
220
+ Logger_1.logger.success(chalk_1.default.green("Record deleted: ") +
221
+ chalk_1.default.bold(recordName) +
222
+ " (" +
223
+ sysId +
224
+ ")");
225
+ // 5. Local cleanup
226
+ if (!typedArgs.keepLocal) {
227
+ Logger_1.logger.info("Cleaning up local files...");
228
+ try {
229
+ // Remove local record directory
230
+ var sourcePath = ConfigManager.getSourcePath();
231
+ var recordDir = path_1.default.join(sourcePath, table, name || recordName);
232
+ if (fs_1.default.existsSync(recordDir)) {
233
+ fs_1.default.rmSync(recordDir, { recursive: true, force: true });
234
+ Logger_1.logger.success(chalk_1.default.green("Removed: ") + recordDir);
235
+ }
236
+ else {
237
+ FileLogger_1.fileLogger.debug("Local directory not found: " + recordDir);
238
+ }
239
+ // Update manifest
240
+ var manifest = await ConfigManager.loadScopeManifest(scope);
241
+ if (manifest &&
242
+ manifest.tables &&
243
+ manifest.tables[table] &&
244
+ manifest.tables[table].records) {
245
+ var recordKey = name || recordName;
246
+ if (manifest.tables[table].records[recordKey]) {
247
+ delete manifest.tables[table].records[recordKey];
248
+ // Remove table entry if no records remain
249
+ if (Object.keys(manifest.tables[table].records).length === 0) {
250
+ delete manifest.tables[table];
251
+ }
252
+ await FileUtils.writeScopeManifest(scope, manifest);
253
+ Logger_1.logger.success(chalk_1.default.green("Manifest updated"));
254
+ }
255
+ }
256
+ }
257
+ catch (cleanupErr) {
258
+ Logger_1.logger.warn("Record deleted on instance but local cleanup failed.");
259
+ Logger_1.logger.warn("Run 'npx dove refresh' to sync local files.");
260
+ if (cleanupErr instanceof Error) {
261
+ FileLogger_1.fileLogger.error("Cleanup error:", cleanupErr.message);
262
+ }
263
+ }
264
+ }
265
+ else {
266
+ Logger_1.logger.info(chalk_1.default.yellow("Local files preserved (--keep-local)"));
267
+ }
268
+ }
269
+ catch (e) {
270
+ Logger_1.logger.error("Failed to delete record");
271
+ if (e instanceof Error) {
272
+ Logger_1.logger.error(e.message);
273
+ if (e.response) {
274
+ var respStatus = e.response.status;
275
+ var respData = e.response.data;
276
+ Logger_1.logger.error("Server responded with status " + respStatus);
277
+ FileLogger_1.fileLogger.error("Delete failed — status: " + respStatus + ", response: " + JSON.stringify(respData));
278
+ }
279
+ }
280
+ process.exit(1);
281
+ }
282
+ }