@weavix/cli 0.1.0-dev

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 (47) hide show
  1. package/README.md +94 -0
  2. package/build/index.js +2568 -0
  3. package/build/templates/.arcignore +35 -0
  4. package/build/templates/_shared/.arcignore +20 -0
  5. package/build/templates/_shared/.prettierrc.js +6 -0
  6. package/build/templates/_shared/.stylelintrc +3 -0
  7. package/build/templates/_shared/eslint.config.js +12 -0
  8. package/build/templates/_shared/manifest.schema.json +438 -0
  9. package/build/templates/_shared/marketplace/README.md +12 -0
  10. package/build/templates/_shared/npmrc.template +2 -0
  11. package/build/templates/_shared/package.json +69 -0
  12. package/build/templates/_shared/public/README.md +12 -0
  13. package/build/templates/_shared/public/fonts/ys-text-display-wide-110.woff +0 -0
  14. package/build/templates/_shared/public/fonts/ys-text-display-wide-110.woff2 +0 -0
  15. package/build/templates/_shared/src/main.tsx +21 -0
  16. package/build/templates/_shared/src/reset.css +55 -0
  17. package/build/templates/_shared/src/styles-360.scss +81 -0
  18. package/build/templates/_shared/src/styles-gravity.scss +249 -0
  19. package/build/templates/_shared/src/vite-env.d.ts +2 -0
  20. package/build/templates/_shared/tsconfig.json +16 -0
  21. package/build/templates/_shared/vite.config.ts +66 -0
  22. package/build/templates/attachment.viewer.action/index.html +14 -0
  23. package/build/templates/attachment.viewer.action/src/App.tsx +59 -0
  24. package/build/templates/default/index.html +14 -0
  25. package/build/templates/default/src/App.tsx +10 -0
  26. package/build/templates/goal.action/index.html +14 -0
  27. package/build/templates/goal.action/src/App.tsx +39 -0
  28. package/build/templates/issue.action/index.html +14 -0
  29. package/build/templates/issue.action/src/App.tsx +36 -0
  30. package/build/templates/issue.block/index.html +14 -0
  31. package/build/templates/issue.block/src/App.tsx +34 -0
  32. package/build/templates/issue.comment.action/index.html +14 -0
  33. package/build/templates/issue.comment.action/src/App.tsx +33 -0
  34. package/build/templates/issue.floatingbottom.action/index.html +14 -0
  35. package/build/templates/issue.floatingbottom.action/src/App.tsx +28 -0
  36. package/build/templates/issue.tab/index.html +14 -0
  37. package/build/templates/issue.tab/src/App.tsx +36 -0
  38. package/build/templates/navigation/index.html +14 -0
  39. package/build/templates/navigation/src/App.tsx +15 -0
  40. package/build/templates/portfolio.action/index.html +14 -0
  41. package/build/templates/portfolio.action/src/App.tsx +44 -0
  42. package/build/templates/project.action/index.html +14 -0
  43. package/build/templates/project.action/src/App.tsx +44 -0
  44. package/build/templates/trigger.action/index.html +14 -0
  45. package/build/templates/trigger.action/src/App.scss +46 -0
  46. package/build/templates/trigger.action/src/App.tsx +153 -0
  47. package/package.json +35 -0
package/build/index.js ADDED
@@ -0,0 +1,2568 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf, __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: !0 });
14
+ }, __copyProps = (to, from, except, desc) => {
15
+ if (from && typeof from == "object" || typeof from == "function")
16
+ for (let key of __getOwnPropNames(from))
17
+ !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: !0 }) : target,
26
+ mod
27
+ )), __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: !0 }), mod);
28
+
29
+ // src/distributions/external/meta.ts
30
+ var meta_exports = {};
31
+ __export(meta_exports, {
32
+ CLI_DESCRIPTION: () => CLI_DESCRIPTION,
33
+ CLI_HELP_TEXT: () => CLI_HELP_TEXT,
34
+ CLI_NAME: () => CLI_NAME
35
+ });
36
+ var CLI_NAME, CLI_DESCRIPTION, CLI_HELP_TEXT, init_meta = __esm({
37
+ "src/distributions/external/meta.ts"() {
38
+ "use strict";
39
+ CLI_NAME = "weavix", CLI_DESCRIPTION = "Weavix CLI", CLI_HELP_TEXT = "";
40
+ }
41
+ });
42
+
43
+ // src/utils/logger.ts
44
+ function success(message) {
45
+ console.info(import_picocolors.default.green(`\u2705 ${message}`)), newLine();
46
+ }
47
+ function error(messageOrErr, err) {
48
+ let message = messageOrErr instanceof Error ? messageOrErr.message : messageOrErr;
49
+ console.error(import_picocolors.default.red(`\u274C ${message}`)), err instanceof Error && console.error(import_picocolors.default.red(err.message)), newLine();
50
+ }
51
+ function warning(message) {
52
+ console.warn(import_picocolors.default.yellow(`\u26A0\uFE0F ${message}`)), newLine();
53
+ }
54
+ function info(message) {
55
+ console.info(message), newLine();
56
+ }
57
+ function suggest(command) {
58
+ console.info(`Run: ${command}`), newLine();
59
+ }
60
+ function newLine(count = 1) {
61
+ console.info(`
62
+ `.repeat(count - 1));
63
+ }
64
+ function separator(char = "\u2500", length = 60) {
65
+ console.info(import_picocolors.default.dim(char.repeat(length))), newLine();
66
+ }
67
+ function commands(title, data) {
68
+ newLine(), console.info(import_picocolors.default.bold(import_picocolors.default.cyan(`${title}:`))), newLine(), data.forEach((cmd) => {
69
+ console.info(import_picocolors.default.dim(" $ ") + import_picocolors.default.white(cmd));
70
+ }), newLine();
71
+ }
72
+ var import_picocolors, logger, logger_default, init_logger = __esm({
73
+ "src/utils/logger.ts"() {
74
+ "use strict";
75
+ import_picocolors = __toESM(require("picocolors"));
76
+ logger = {
77
+ success,
78
+ error,
79
+ warning,
80
+ info,
81
+ suggest,
82
+ newLine,
83
+ separator,
84
+ commands
85
+ }, logger_default = logger;
86
+ }
87
+ });
88
+
89
+ // src/distributions/external/configStore.ts
90
+ async function readConfig() {
91
+ if (!(0, import_fs.existsSync)(CONFIG_FILE))
92
+ return null;
93
+ let raw = await (0, import_promises.readFile)(CONFIG_FILE, "utf-8");
94
+ return JSON.parse(raw);
95
+ }
96
+ async function writeConfig(config) {
97
+ (0, import_fs.existsSync)(CONFIG_DIR) || (0, import_fs.mkdirSync)(CONFIG_DIR, { recursive: !0, mode: 448 }), await (0, import_promises.writeFile)(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 384 });
98
+ }
99
+ async function clearConfig() {
100
+ (0, import_fs.existsSync)(CONFIG_FILE) && await (0, import_promises.unlink)(CONFIG_FILE);
101
+ }
102
+ var import_fs, import_promises, os, import_path, CONFIG_DIR, CONFIG_FILE, CONFIG_FILE_PATH, init_configStore = __esm({
103
+ "src/distributions/external/configStore.ts"() {
104
+ "use strict";
105
+ import_fs = require("fs"), import_promises = require("fs/promises"), os = __toESM(require("os")), import_path = __toESM(require("path")), CONFIG_DIR = import_path.default.join(os.homedir(), ".tracker-cli"), CONFIG_FILE = import_path.default.join(CONFIG_DIR, "config.json"), CONFIG_FILE_PATH = CONFIG_FILE;
106
+ }
107
+ });
108
+
109
+ // src/distributions/external/configCommand.ts
110
+ function withErrorHandling(fn) {
111
+ return async (...args) => {
112
+ try {
113
+ await fn(...args);
114
+ } catch (error2) {
115
+ error2 instanceof Error && error2.name === "ExitPromptError" && process.exit(0), logger_default.error(error2), process.exit(1);
116
+ }
117
+ };
118
+ }
119
+ async function configSet() {
120
+ let current = await readConfig(), awsEndpoint = await (0, import_prompts.input)({
121
+ message: "S3 endpoint (e.g. https://s3.amazonaws.com):",
122
+ default: current?.awsEndpoint,
123
+ validate: (v) => v.trim() ? !0 : "required"
124
+ }), awsRegion = await (0, import_prompts.input)({
125
+ message: "S3 region:",
126
+ default: current?.awsRegion,
127
+ validate: (v) => v.trim() ? !0 : "required"
128
+ }), staticBucket = await (0, import_prompts.input)({
129
+ message: "Bucket for plugin files:",
130
+ default: current?.staticBucket,
131
+ validate: (v) => v.trim() ? !0 : "required"
132
+ }), configBucket = await (0, import_prompts.input)({
133
+ message: "Bucket for plugins config.json:",
134
+ default: current?.configBucket,
135
+ validate: (v) => v.trim() ? !0 : "required"
136
+ }), mdsEndpoint = await (0, import_prompts.input)({
137
+ message: "MDS endpoint (optional, defaults to S3 endpoint):",
138
+ default: current?.mdsEndpoint || ""
139
+ }), platformApiUrl = await (0, import_prompts.input)({
140
+ message: "Platform API URL (optional):",
141
+ default: current?.platformApiUrl || ""
142
+ }), trackerApiUrl = await (0, import_prompts.input)({
143
+ message: "Tracker API URL (optional):",
144
+ default: current?.trackerApiUrl || ""
145
+ }), config = {
146
+ awsEndpoint: awsEndpoint.trim(),
147
+ awsRegion: awsRegion.trim(),
148
+ staticBucket: staticBucket.trim(),
149
+ configBucket: configBucket.trim()
150
+ };
151
+ mdsEndpoint.trim() && (config.mdsEndpoint = mdsEndpoint.trim()), platformApiUrl.trim() && (config.platformApiUrl = platformApiUrl.trim()), trackerApiUrl.trim() && (config.trackerApiUrl = trackerApiUrl.trim()), await writeConfig(config), logger_default.success(`Configuration saved to ${CONFIG_FILE_PATH}`);
152
+ }
153
+ async function configShow() {
154
+ let cfg = await readConfig();
155
+ if (!cfg) {
156
+ logger_default.info("No configuration. Run: tracker-cli config set");
157
+ return;
158
+ }
159
+ logger_default.info(JSON.stringify(cfg, null, 2));
160
+ }
161
+ async function configClear() {
162
+ if (!await readConfig()) {
163
+ logger_default.info("No configuration to clear.");
164
+ return;
165
+ }
166
+ if (!await (0, import_prompts.confirm)({
167
+ message: `Remove configuration at ${CONFIG_FILE_PATH}?`,
168
+ default: !1
169
+ })) {
170
+ logger_default.info("Cancelled.");
171
+ return;
172
+ }
173
+ await clearConfig(), logger_default.success("Configuration removed.");
174
+ }
175
+ function registerConfigCommand(program) {
176
+ let config = program.command("config").description("manage CLI configuration (S3 endpoints, buckets, API URLs)");
177
+ config.command("set").description("set configuration interactively").action(withErrorHandling(configSet)), config.command("show").description("show current configuration").action(withErrorHandling(configShow)), config.command("clear").description("remove configuration").action(withErrorHandling(configClear));
178
+ }
179
+ var import_prompts, init_configCommand = __esm({
180
+ "src/distributions/external/configCommand.ts"() {
181
+ "use strict";
182
+ import_prompts = require("@inquirer/prompts");
183
+ init_logger();
184
+ init_configStore();
185
+ }
186
+ });
187
+
188
+ // src/distributions/external/registerCommands.ts
189
+ var registerCommands_exports = {};
190
+ __export(registerCommands_exports, {
191
+ registerDistributionCommands: () => registerDistributionCommands
192
+ });
193
+ function registerDistributionCommands(program) {
194
+ registerConfigCommand(program);
195
+ }
196
+ var init_registerCommands = __esm({
197
+ "src/distributions/external/registerCommands.ts"() {
198
+ "use strict";
199
+ init_configCommand();
200
+ }
201
+ });
202
+
203
+ // src/distributions/external/auth.ts
204
+ var auth_exports = {};
205
+ __export(auth_exports, {
206
+ getNpmUpdateUrl: () => getNpmUpdateUrl,
207
+ getOAuthTokenUrl: () => getOAuthTokenUrl
208
+ });
209
+ async function getOAuthTokenUrl() {
210
+ }
211
+ async function getNpmUpdateUrl() {
212
+ }
213
+ var init_auth = __esm({
214
+ "src/distributions/external/auth.ts"() {
215
+ "use strict";
216
+ }
217
+ });
218
+
219
+ // src/distributions/external/apiUrls.ts
220
+ var apiUrls_exports = {};
221
+ __export(apiUrls_exports, {
222
+ getPlatformApiUrl: () => getPlatformApiUrl,
223
+ getTrackerApiUrl: () => getTrackerApiUrl
224
+ });
225
+ async function getPlatformApiUrl() {
226
+ let cfg = await readConfig();
227
+ if (!cfg?.platformApiUrl)
228
+ throw new Error("Platform API URL is not configured. Run: tracker-cli config set");
229
+ return cfg.platformApiUrl;
230
+ }
231
+ async function getTrackerApiUrl() {
232
+ let cfg = await readConfig();
233
+ if (!cfg?.trackerApiUrl)
234
+ throw new Error("Tracker API URL is not configured. Run: tracker-cli config set");
235
+ return cfg.trackerApiUrl;
236
+ }
237
+ var init_apiUrls = __esm({
238
+ "src/distributions/external/apiUrls.ts"() {
239
+ "use strict";
240
+ init_configStore();
241
+ }
242
+ });
243
+
244
+ // src/distributions/external/promptEnvironment.ts
245
+ var promptEnvironment_exports = {};
246
+ __export(promptEnvironment_exports, {
247
+ promptEnvironment: () => promptEnvironment
248
+ });
249
+ async function promptEnvironment() {
250
+ return "";
251
+ }
252
+ var init_promptEnvironment = __esm({
253
+ "src/distributions/external/promptEnvironment.ts"() {
254
+ "use strict";
255
+ }
256
+ });
257
+
258
+ // src/distributions/external/storage.ts
259
+ var storage_exports = {};
260
+ __export(storage_exports, {
261
+ DEFAULT_ENVIRONMENT: () => DEFAULT_ENVIRONMENT,
262
+ getStorageSettings: () => getStorageSettings,
263
+ listEnvironments: () => listEnvironments
264
+ });
265
+ async function getStorageSettings(_environment) {
266
+ let cfg = await readConfig();
267
+ if (!cfg)
268
+ throw new Error("CLI is not configured. Run: tracker-cli config set");
269
+ return {
270
+ awsEndpoint: cfg.awsEndpoint,
271
+ awsRegion: cfg.awsRegion,
272
+ mdsEndpoint: cfg.mdsEndpoint ?? cfg.awsEndpoint,
273
+ configBucket: cfg.configBucket,
274
+ staticBucket: cfg.staticBucket
275
+ };
276
+ }
277
+ async function listEnvironments() {
278
+ return [];
279
+ }
280
+ var DEFAULT_ENVIRONMENT, init_storage = __esm({
281
+ "src/distributions/external/storage.ts"() {
282
+ "use strict";
283
+ init_configStore();
284
+ DEFAULT_ENVIRONMENT = "";
285
+ }
286
+ });
287
+
288
+ // src/index.ts
289
+ var import_commander = require("commander");
290
+
291
+ // src/distribution/meta.ts
292
+ var impl = (init_meta(), __toCommonJS(meta_exports)), { CLI_NAME: CLI_NAME2, CLI_DESCRIPTION: CLI_DESCRIPTION2, CLI_HELP_TEXT: CLI_HELP_TEXT2 } = impl;
293
+
294
+ // src/distribution/registerCommands.ts
295
+ var impl2 = (init_registerCommands(), __toCommonJS(registerCommands_exports)), { registerDistributionCommands: registerDistributionCommands2 } = impl2;
296
+
297
+ // src/utils/checkUpdate.ts
298
+ var import_node_fetch = __toESM(require("node-fetch"));
299
+
300
+ // src/distribution/auth.ts
301
+ var impl3 = (init_auth(), __toCommonJS(auth_exports)), { getOAuthTokenUrl: getOAuthTokenUrl2, getNpmUpdateUrl: getNpmUpdateUrl2 } = impl3;
302
+
303
+ // src/utils/checkUpdate.ts
304
+ init_logger();
305
+ var checkUpdate = async (version) => {
306
+ try {
307
+ let registryUrl = await getNpmUpdateUrl2();
308
+ if (!registryUrl)
309
+ return;
310
+ let response = await (0, import_node_fetch.default)(`${registryUrl}/@yandex-data-ui/tracker-cli/latest`);
311
+ if (!response.ok)
312
+ return;
313
+ let latest = await response.json();
314
+ latest.version !== version && (logger_default.newLine(), logger_default.info(
315
+ `\u{1F514} Update available ${version} \u2192 ${latest.version}
316
+ Run: npm i -g @yandex-data-ui/tracker-cli@latest --registry=${registryUrl}`
317
+ ));
318
+ } catch {
319
+ }
320
+ };
321
+
322
+ // src/utils/execCommand.ts
323
+ var import_execa = require("execa"), execCommand = async (command, cwd = process.cwd()) => {
324
+ await (0, import_execa.execa)(command, {
325
+ cwd,
326
+ shell: !0,
327
+ stdio: "inherit"
328
+ });
329
+ };
330
+
331
+ // src/commands/build.ts
332
+ init_logger();
333
+
334
+ // src/commands/constants/templateCommands.ts
335
+ var pluginCmd = {
336
+ install: "npm install",
337
+ build: "npm run build",
338
+ dev: "npm run dev",
339
+ lint: "npm run lint"
340
+ };
341
+
342
+ // src/commands/build.ts
343
+ var build = async ({ environment = "production" } = {}) => {
344
+ logger_default.info("\u{1F528} Building project..."), await execCommand(pluginCmd.install), await execCommand(
345
+ environment ? `VITE_DEPLOY_ENV=${environment} ${pluginCmd.build}` : pluginCmd.build
346
+ );
347
+ };
348
+
349
+ // src/api/tracker.ts
350
+ var import_form_data = __toESM(require("form-data"));
351
+
352
+ // src/api/trackerApiRequest.ts
353
+ var import_node_fetch2 = __toESM(require("node-fetch"));
354
+
355
+ // src/core/auth/authManager.ts
356
+ var fs = __toESM(require("fs")), os2 = __toESM(require("os")), path2 = __toESM(require("path")), authDir = path2.join(os2.homedir(), ".tracker-cli"), authFile = path2.join(authDir, "auth.json"), getData = () => {
357
+ try {
358
+ if (!fs.existsSync(authFile))
359
+ return null;
360
+ let data = fs.readFileSync(authFile, "utf-8");
361
+ return JSON.parse(data);
362
+ } catch {
363
+ return null;
364
+ }
365
+ }, getAuthHeader = () => {
366
+ let authData = getData();
367
+ return authData ? `OAuth ${authData.token}` : null;
368
+ }, saveAuthData = (token) => {
369
+ let authData = {
370
+ token
371
+ };
372
+ fs.existsSync(authDir) || fs.mkdirSync(authDir, { recursive: !0, mode: 448 }), fs.writeFileSync(authFile, JSON.stringify(authData, null, 2), {
373
+ mode: 384
374
+ });
375
+ }, removeAuthData = () => {
376
+ fs.existsSync(authFile) && fs.unlinkSync(authFile);
377
+ }, authManager = {
378
+ get authHeader() {
379
+ return getAuthHeader();
380
+ },
381
+ get data() {
382
+ return getData();
383
+ },
384
+ saveAuthData,
385
+ removeAuthData
386
+ };
387
+
388
+ // src/distribution/apiUrls.ts
389
+ var impl4 = (init_apiUrls(), __toCommonJS(apiUrls_exports)), { getPlatformApiUrl: getPlatformApiUrl2, getTrackerApiUrl: getTrackerApiUrl2 } = impl4;
390
+
391
+ // src/api/trackerApiRequest.ts
392
+ function buildQueryString(queryParams) {
393
+ if (!queryParams || Object.keys(queryParams).length === 0)
394
+ return "";
395
+ let params = new URLSearchParams();
396
+ return Object.entries(queryParams).forEach(([key, value]) => {
397
+ params.append(key, String(value));
398
+ }), `?${params.toString()}`;
399
+ }
400
+ async function parseResponse(response) {
401
+ return response.status === 204 || response.headers.get("content-length") === "0" ? void 0 : response.headers.get("content-type")?.includes("application/json") ? await response.json() : await response.text();
402
+ }
403
+ async function trackerApiRequest(endpoint, options = {}) {
404
+ let { method = "GET", body, headers = {}, formData, queryParams } = options, authHeader = authManager.authHeader;
405
+ if (!authHeader)
406
+ throw new Error('Not authenticated. Run "tracker-cli login" first.');
407
+ let requestHeaders = {
408
+ Authorization: authHeader,
409
+ Accept: "application/json",
410
+ ...headers
411
+ }, requestBody;
412
+ if (formData) {
413
+ let formHeaders = formData.getHeaders?.();
414
+ Object.assign(requestHeaders, formHeaders), requestBody = formData;
415
+ } else body && method !== "GET" && (requestHeaders["Content-Type"] = "application/json", requestBody = JSON.stringify(body));
416
+ let queryString = buildQueryString(queryParams), url = `${await getTrackerApiUrl2()}${endpoint}${queryString}`, response = await (0, import_node_fetch2.default)(url, {
417
+ method,
418
+ headers: requestHeaders,
419
+ body: requestBody
420
+ });
421
+ if (!response.ok) {
422
+ let errorText = await response.text(), errorMessage = `Tracker API error ${response.status}: ${errorText}`;
423
+ try {
424
+ let errorJson = JSON.parse(errorText);
425
+ errorJson.message && (errorMessage = `Tracker API error ${response.status}: ${errorJson.message}`);
426
+ } catch {
427
+ }
428
+ throw new Error(errorMessage);
429
+ }
430
+ return parseResponse(response);
431
+ }
432
+
433
+ // src/api/tracker.ts
434
+ var PLUGINMOD_QUEUE = "PLUGINMOD";
435
+ function buildIssueSummary(slug) {
436
+ return `Plugin: ${slug}`;
437
+ }
438
+ function buildIssueDescription(params) {
439
+ let { pluginId, slug, version, manifestJson, catalogName, catalogDescription, catalogTags } = params, lines = [
440
+ `**Plugin UUID:** ${pluginId}`,
441
+ `**Slug:** ${slug}`,
442
+ `**Version:** ${version}`
443
+ ];
444
+ return catalogName && lines.push(`**Name:** ${catalogName}`), catalogDescription && lines.push(`**Description:** ${catalogDescription}`), catalogTags && catalogTags.length > 0 && lines.push(`**Tags:** ${catalogTags.join(", ")}`), lines.push("", "**Manifest:**", "```json", manifestJson, "```"), lines.join(`
445
+ `);
446
+ }
447
+ async function createPluginIssue(params) {
448
+ let { slug, pluginId, version, manifestJson } = params, body = {
449
+ queue: PLUGINMOD_QUEUE,
450
+ summary: buildIssueSummary(slug),
451
+ description: buildIssueDescription({ pluginId, slug, version, manifestJson }),
452
+ tags: ["tracker-plugin"]
453
+ };
454
+ return trackerApiRequest("/issues", {
455
+ method: "POST",
456
+ body
457
+ });
458
+ }
459
+ async function updatePluginIssue(issueKey, params) {
460
+ return trackerApiRequest(`/issues/${issueKey}`, {
461
+ method: "PATCH",
462
+ body: params
463
+ });
464
+ }
465
+ async function attachFileToIssue(issueKey, fileBuffer, fileName) {
466
+ let formData = new import_form_data.default();
467
+ return formData.append("file", fileBuffer, {
468
+ filename: fileName,
469
+ contentType: "application/zip"
470
+ }), trackerApiRequest(`/issues/${issueKey}/attachments`, {
471
+ method: "POST",
472
+ formData
473
+ });
474
+ }
475
+ async function getIssueAttachments(issueKey) {
476
+ return trackerApiRequest(`/issues/${issueKey}/attachments`, {
477
+ method: "GET"
478
+ });
479
+ }
480
+ async function getIssueTransitions(issueKey) {
481
+ return trackerApiRequest(`/issues/${issueKey}/transitions`, {
482
+ method: "GET"
483
+ });
484
+ }
485
+ async function executeIssueTransition(issueKey, transitionId) {
486
+ await trackerApiRequest(`/issues/${issueKey}/transitions/${transitionId}/_execute`, {
487
+ method: "POST",
488
+ body: {}
489
+ });
490
+ }
491
+ async function getIssue(issueKey) {
492
+ return trackerApiRequest(`/issues/${issueKey}`, {
493
+ method: "GET"
494
+ });
495
+ }
496
+ async function getMyPluginIssues() {
497
+ return trackerApiRequest("/issues/_search", {
498
+ method: "POST",
499
+ body: {
500
+ filter: {
501
+ queue: PLUGINMOD_QUEUE,
502
+ createdBy: "me()"
503
+ }
504
+ }
505
+ });
506
+ }
507
+ async function addIssueComment(issueKey, text) {
508
+ await trackerApiRequest(`/issues/${issueKey}/comments`, {
509
+ method: "POST",
510
+ body: { text }
511
+ });
512
+ }
513
+
514
+ // src/core/manifest/manifestManager.ts
515
+ var import_fs2 = require("fs"), import_promises2 = require("fs/promises"), import_ajv = __toESM(require("ajv")), import_ajv_formats = __toESM(require("ajv-formats"));
516
+
517
+ // src/core/manifest/formatValidationErrors.ts
518
+ var priorityOrder = [
519
+ "required",
520
+ "type",
521
+ "minLength",
522
+ "format",
523
+ "pattern",
524
+ "enum",
525
+ "additionalProperties",
526
+ "uniqueItems"
527
+ ], errorMessages = {
528
+ required: (params) => `missing required property '${params.missingProperty}'`,
529
+ type: (params) => `must be ${params.type}`,
530
+ enum: (params) => `must be one of [${params.allowedValues.join(", ")}]`,
531
+ pattern: (params) => `must match pattern ${params.pattern}`,
532
+ format: (params) => `must be a valid ${params.format}`,
533
+ minLength: () => "must not be empty",
534
+ additionalProperties: (params) => `unexpected property '${params.additionalProperty}'`,
535
+ uniqueItems: () => "must contain unique items"
536
+ }, getPriority = (keyword) => {
537
+ let index = priorityOrder.indexOf(keyword);
538
+ return index === -1 ? priorityOrder.length : index;
539
+ }, formatValidationErrors = (errors) => {
540
+ let errorsByPath = {};
541
+ for (let error2 of errors) {
542
+ let path17 = error2.instancePath || "root";
543
+ errorsByPath[path17] || (errorsByPath[path17] = []), errorsByPath[path17].push(error2);
544
+ }
545
+ return Object.entries(errorsByPath).map(([path17, pathErrors]) => {
546
+ let error2 = [...pathErrors].sort(
547
+ (a, b) => getPriority(a.keyword) - getPriority(b.keyword)
548
+ )[0], formatter = errorMessages[error2.keyword], message = formatter ? formatter(error2.params) : error2.message;
549
+ return ` - ${path17}: ${message}`;
550
+ }).join(`
551
+ `);
552
+ };
553
+
554
+ // src/core/manifest/manifest.schema.json
555
+ var manifest_schema_default = {
556
+ $schema: "http://json-schema.org/draft-07/schema#",
557
+ title: "Manifest",
558
+ description: "Schema for validating plugin manifest",
559
+ type: "object",
560
+ required: [
561
+ "slug",
562
+ "version",
563
+ "permissions"
564
+ ],
565
+ properties: {
566
+ $schema: {
567
+ type: "string"
568
+ },
569
+ id: {
570
+ type: "string",
571
+ description: "Unique identifier for the plugin ()",
572
+ minLength: 3,
573
+ maxLength: 63,
574
+ pattern: "^[a-z0-9-]+$"
575
+ },
576
+ slug: {
577
+ type: "string",
578
+ description: "Unique identifier for the plugin (lowercase letters, numbers, hyphen)",
579
+ minLength: 3,
580
+ maxLength: 63,
581
+ pattern: "^[a-z0-9-]+$"
582
+ },
583
+ version: {
584
+ type: "string",
585
+ description: "Version of the plugin (semver format required)",
586
+ minLength: 1,
587
+ pattern: "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?(\\+[a-zA-Z0-9.-]+)?$"
588
+ },
589
+ name: {
590
+ type: "object",
591
+ description: "Localized plugin name",
592
+ required: [
593
+ "ru",
594
+ "en"
595
+ ],
596
+ properties: {
597
+ ru: {
598
+ type: "string",
599
+ description: "Russian name",
600
+ minLength: 1,
601
+ maxLength: 30
602
+ },
603
+ en: {
604
+ type: "string",
605
+ description: "English name",
606
+ minLength: 1,
607
+ maxLength: 30
608
+ }
609
+ },
610
+ additionalProperties: !1
611
+ },
612
+ description: {
613
+ type: "object",
614
+ description: "Localized plugin description",
615
+ required: [
616
+ "ru",
617
+ "en"
618
+ ],
619
+ properties: {
620
+ ru: {
621
+ type: "string",
622
+ description: "Russian description",
623
+ minLength: 1,
624
+ maxLength: 300
625
+ },
626
+ en: {
627
+ type: "string",
628
+ description: "English description",
629
+ minLength: 1,
630
+ maxLength: 300
631
+ }
632
+ },
633
+ additionalProperties: !1
634
+ },
635
+ support: {
636
+ type: "array",
637
+ description: "Support contact information",
638
+ items: {
639
+ type: "object",
640
+ required: [
641
+ "type",
642
+ "value"
643
+ ],
644
+ properties: {
645
+ type: {
646
+ type: "string",
647
+ description: "Type of support contact",
648
+ enum: [
649
+ "email"
650
+ ]
651
+ },
652
+ value: {
653
+ type: "string",
654
+ description: "Contact value",
655
+ minLength: 1,
656
+ maxLength: 100
657
+ }
658
+ },
659
+ additionalProperties: !1
660
+ },
661
+ minItems: 1
662
+ },
663
+ homepage: {
664
+ type: "string",
665
+ description: "Homepage URL for the plugin (http or https)",
666
+ pattern: "^https?://",
667
+ maxLength: 1e3
668
+ },
669
+ license: {
670
+ type: "string",
671
+ description: "License identifier (e.g., MIT, Apache-2.0)",
672
+ minLength: 1,
673
+ maxLength: 32
674
+ },
675
+ keywords: {
676
+ type: "array",
677
+ description: "Keywords for plugin discovery",
678
+ items: {
679
+ type: "string",
680
+ minLength: 1,
681
+ maxLength: 30
682
+ },
683
+ uniqueItems: !0
684
+ },
685
+ whatsnew: {
686
+ type: "string",
687
+ description: "What's new in this version",
688
+ minLength: 1,
689
+ maxLength: 300
690
+ },
691
+ externalHost: {
692
+ type: "string",
693
+ description: "External host URL for the plugin (https only)",
694
+ format: "uri",
695
+ pattern: "^https://",
696
+ maxLength: 1e3
697
+ },
698
+ permissions: {
699
+ type: "object",
700
+ description: "Permissions required by the plugin",
701
+ required: [
702
+ "data"
703
+ ],
704
+ properties: {
705
+ data: {
706
+ type: "array",
707
+ description: "Data access permissions",
708
+ items: {
709
+ type: "string",
710
+ enum: [
711
+ "tracker:issues:read",
712
+ "tracker:issues:write",
713
+ "tracker:issuetypes:read",
714
+ "tracker:statuses:read",
715
+ "tracker:queues:read",
716
+ "tracker:fields:read",
717
+ "tracker:entities:read",
718
+ "tracker:attachments:read",
719
+ "tracker:attachments:write",
720
+ "tracker:applications:read",
721
+ "tracker:boards:read",
722
+ "tracker:boards:write",
723
+ "tracker:bulk:read",
724
+ "tracker:bulk:write",
725
+ "tracker:bulkchange:read",
726
+ "tracker:bulkchange:write",
727
+ "tracker:charts:read",
728
+ "tracker:commentTemplates:read",
729
+ "tracker:commentTemplates:write",
730
+ "tracker:components:read",
731
+ "tracker:components:write",
732
+ "tracker:data:read",
733
+ "tracker:departments:read",
734
+ "tracker:entities:write",
735
+ "tracker:externalEventTypes:write",
736
+ "tracker:externalEvents:write",
737
+ "tracker:fields:write",
738
+ "tracker:filterFolders:write",
739
+ "tracker:filters:read",
740
+ "tracker:filters:write",
741
+ "tracker:goals:read",
742
+ "tracker:goals:write",
743
+ "tracker:groups:read",
744
+ "tracker:issueTemplates:read",
745
+ "tracker:issueTemplates:write",
746
+ "tracker:links:read",
747
+ "tracker:linktypes:read",
748
+ "tracker:liveBoards:write",
749
+ "tracker:localFields:read",
750
+ "tracker:maillists:read",
751
+ "tracker:maillists:write",
752
+ "tracker:myself:read",
753
+ "tracker:myself:write",
754
+ "tracker:priorities:read",
755
+ "tracker:queues:write",
756
+ "tracker:reminders:read",
757
+ "tracker:reminders:write",
758
+ "tracker:remotelinks:read",
759
+ "tracker:reports:read",
760
+ "tracker:reports:write",
761
+ "tracker:resolutions:read",
762
+ "tracker:resources:read",
763
+ "tracker:resources:write",
764
+ "tracker:roles:read",
765
+ "tracker:screens:read",
766
+ "tracker:services:read",
767
+ "tracker:sprints:read",
768
+ "tracker:sprints:write",
769
+ "tracker:system:write",
770
+ "tracker:tags:read",
771
+ "tracker:translations:read",
772
+ "tracker:users:read",
773
+ "tracker:users:write",
774
+ "tracker:versions:read",
775
+ "tracker:versions:write",
776
+ "tracker:workflows:read",
777
+ "tracker:workflows:write",
778
+ "tracker:worklog:read",
779
+ "tracker:worklog:write"
780
+ ]
781
+ },
782
+ uniqueItems: !0
783
+ },
784
+ ui: {
785
+ type: "array",
786
+ description: "UI permissions",
787
+ items: {
788
+ type: "string"
789
+ },
790
+ uniqueItems: !0
791
+ },
792
+ device: {
793
+ type: "array",
794
+ description: "Device permissions",
795
+ items: {
796
+ type: "string",
797
+ enum: [
798
+ "clipboard-write"
799
+ ]
800
+ },
801
+ uniqueItems: !0
802
+ },
803
+ external: {
804
+ type: "array",
805
+ description: "External permissions",
806
+ items: {
807
+ type: "string"
808
+ },
809
+ uniqueItems: !0
810
+ }
811
+ },
812
+ additionalProperties: !1
813
+ },
814
+ slots: {
815
+ type: "object",
816
+ description: "Configuration for service slots",
817
+ minProperties: 1,
818
+ properties: {
819
+ tracker: {
820
+ type: "object",
821
+ description: "Tracker service slots",
822
+ minProperties: 1,
823
+ properties: {
824
+ "issue.action": {
825
+ type: "array",
826
+ description: "Issue Action slot configurations",
827
+ minItems: 1,
828
+ items: {
829
+ $ref: "#/definitions/SlotConfig"
830
+ }
831
+ },
832
+ "issue.block": {
833
+ type: "array",
834
+ description: "Issue Block slot configurations",
835
+ minItems: 1,
836
+ items: {
837
+ $ref: "#/definitions/SlotConfig"
838
+ }
839
+ },
840
+ "issue.tab": {
841
+ type: "array",
842
+ description: "Issue Tab slot configurations",
843
+ minItems: 1,
844
+ items: {
845
+ $ref: "#/definitions/SlotConfig"
846
+ }
847
+ },
848
+ "issue.comment.action": {
849
+ type: "array",
850
+ description: "Issue Comment Action slot configurations",
851
+ minItems: 1,
852
+ items: {
853
+ $ref: "#/definitions/SlotConfig"
854
+ }
855
+ },
856
+ navigation: {
857
+ type: "array",
858
+ description: "Navigation slot configurations",
859
+ minItems: 1,
860
+ items: {
861
+ $ref: "#/definitions/SlotConfig"
862
+ }
863
+ },
864
+ "trigger.create.action": {
865
+ type: "array",
866
+ description: "Trigger Create Action slot configurations",
867
+ minItems: 1,
868
+ items: {
869
+ $ref: "#/definitions/SlotConfig"
870
+ }
871
+ },
872
+ "trigger.edit.action": {
873
+ type: "array",
874
+ description: "Trigger Edit Action slot configurations",
875
+ minItems: 1,
876
+ items: {
877
+ $ref: "#/definitions/SlotConfig"
878
+ }
879
+ },
880
+ "project.action": {
881
+ type: "array",
882
+ description: "Project Action slot configurations",
883
+ minItems: 1,
884
+ items: {
885
+ $ref: "#/definitions/SlotConfig"
886
+ }
887
+ },
888
+ "portfolio.action": {
889
+ type: "array",
890
+ description: "Portfolio Action slot configurations",
891
+ minItems: 1,
892
+ items: {
893
+ $ref: "#/definitions/SlotConfig"
894
+ }
895
+ },
896
+ "goal.action": {
897
+ type: "array",
898
+ description: "Goal Action slot configurations",
899
+ minItems: 1,
900
+ items: {
901
+ $ref: "#/definitions/SlotConfig"
902
+ }
903
+ },
904
+ "issue.floatingbottom.action": {
905
+ type: "array",
906
+ description: "Issue Floatingbottom Action slot configurations",
907
+ minItems: 1,
908
+ items: {
909
+ $ref: "#/definitions/SlotConfig"
910
+ }
911
+ },
912
+ "attachment.viewer.action": {
913
+ type: "array",
914
+ description: "Attachment Viewer Action slot configurations",
915
+ minItems: 1,
916
+ items: {
917
+ $ref: "#/definitions/SlotConfig"
918
+ }
919
+ }
920
+ },
921
+ additionalProperties: !1
922
+ }
923
+ },
924
+ additionalProperties: !1
925
+ }
926
+ },
927
+ additionalProperties: !1,
928
+ definitions: {
929
+ SlotConfig: {
930
+ type: "object",
931
+ description: "Configuration for a specific slot",
932
+ required: [
933
+ "entrypoint",
934
+ "title"
935
+ ],
936
+ properties: {
937
+ entrypoint: {
938
+ type: "string",
939
+ description: "Entry point file path for the slot",
940
+ minLength: 1
941
+ },
942
+ title: {
943
+ type: "object",
944
+ description: "Localized titles for the slot",
945
+ required: [
946
+ "ru",
947
+ "en"
948
+ ],
949
+ properties: {
950
+ ru: {
951
+ type: "string",
952
+ description: "Russian title",
953
+ minLength: 1,
954
+ maxLength: 32
955
+ },
956
+ en: {
957
+ type: "string",
958
+ description: "English title",
959
+ minLength: 1,
960
+ maxLength: 32
961
+ }
962
+ },
963
+ additionalProperties: !1
964
+ },
965
+ description: {
966
+ type: "object",
967
+ description: "Localized descriptions for the slot",
968
+ required: [
969
+ "ru",
970
+ "en"
971
+ ],
972
+ properties: {
973
+ ru: {
974
+ type: "string",
975
+ description: "Russian description",
976
+ minLength: 1,
977
+ maxLength: 300
978
+ },
979
+ en: {
980
+ type: "string",
981
+ description: "English description",
982
+ minLength: 1,
983
+ maxLength: 300
984
+ }
985
+ },
986
+ additionalProperties: !1
987
+ }
988
+ },
989
+ additionalProperties: !1
990
+ }
991
+ }
992
+ };
993
+
994
+ // src/core/manifest/manifestManager.ts
995
+ var validator = (() => {
996
+ let ajv = new import_ajv.default({ allErrors: !0, strict: !1 });
997
+ return (0, import_ajv_formats.default)(ajv), ajv.compile(manifest_schema_default);
998
+ })(), manifestPath = "./manifest.json", parseManifest = (content) => {
999
+ let manifest;
1000
+ try {
1001
+ manifest = JSON.parse(content);
1002
+ } catch (error2) {
1003
+ throw error2 instanceof SyntaxError ? new Error(`File manifest.json contains invalid JSON: ${error2.message}`) : new Error(`Error reading manifest.json: ${error2.message}`);
1004
+ }
1005
+ return manifest;
1006
+ }, loadRaw = async () => {
1007
+ if (!(0, import_fs2.existsSync)(manifestPath))
1008
+ throw new Error(`File manifest.json not found at path: ${manifestPath}`);
1009
+ try {
1010
+ return await (0, import_promises2.readFile)(manifestPath, "utf8");
1011
+ } catch (error2) {
1012
+ throw error2 instanceof Error ? new Error(`Error reading manifest.json: ${error2.message}`) : new Error("Error loading manifest");
1013
+ }
1014
+ }, load = async () => {
1015
+ let manifestContent = await loadRaw();
1016
+ return parseManifest(manifestContent);
1017
+ }, validate = async () => {
1018
+ let manifest = await load();
1019
+ if (!validator(manifest) && validator.errors) {
1020
+ let errorMessages2 = formatValidationErrors(validator.errors);
1021
+ throw new Error(`Manifest validation failed:
1022
+ ${errorMessages2}`);
1023
+ }
1024
+ }, save = async (manifest) => {
1025
+ try {
1026
+ let content = JSON.stringify(manifest, null, 4);
1027
+ await (0, import_promises2.writeFile)(manifestPath, content, "utf8");
1028
+ } catch (error2) {
1029
+ throw error2 instanceof Error ? new Error(`Error saving manifest.json: ${error2.message}`) : new Error("Error saving manifest");
1030
+ }
1031
+ }, update = async (updates) => {
1032
+ let updatedManifest = { ...await load(), ...updates };
1033
+ return await save(updatedManifest), updatedManifest;
1034
+ }, manifestManager = {
1035
+ load,
1036
+ loadRaw,
1037
+ validate,
1038
+ save,
1039
+ update
1040
+ };
1041
+
1042
+ // src/core/pluginState/pluginStateManager.ts
1043
+ var import_fs3 = require("fs"), import_promises3 = require("fs/promises"), STATE_FILE = ".tracker-plugin", load2 = async () => {
1044
+ if (!(0, import_fs3.existsSync)(STATE_FILE))
1045
+ return {};
1046
+ try {
1047
+ let content = await (0, import_promises3.readFile)(STATE_FILE, "utf8");
1048
+ return JSON.parse(content);
1049
+ } catch {
1050
+ return {};
1051
+ }
1052
+ }, save2 = async (state) => {
1053
+ try {
1054
+ let content = JSON.stringify(state, null, 4);
1055
+ await (0, import_promises3.writeFile)(STATE_FILE, content, "utf8");
1056
+ } catch (error2) {
1057
+ throw error2 instanceof Error ? new Error(`Error saving ${STATE_FILE}: ${error2.message}`) : new Error(`Error saving ${STATE_FILE}`);
1058
+ }
1059
+ }, update2 = async (updates) => {
1060
+ let updated = { ...await load2(), ...updates };
1061
+ return await save2(updated), updated;
1062
+ }, pluginStateManager = {
1063
+ load: load2,
1064
+ save: save2,
1065
+ update: update2
1066
+ };
1067
+
1068
+ // src/commands/catalog/index.ts
1069
+ init_logger();
1070
+
1071
+ // src/utils/promptPluginMetadata.ts
1072
+ var import_prompts2 = require("@inquirer/prompts");
1073
+ async function promptPluginName() {
1074
+ return (0, import_prompts2.input)({
1075
+ message: "Plugin name:",
1076
+ validate: (value) => value.trim() ? !0 : "Name is required"
1077
+ });
1078
+ }
1079
+ async function promptPluginDescription() {
1080
+ return (0, import_prompts2.input)({
1081
+ message: "Plugin description:",
1082
+ validate: (value) => value.trim() ? !0 : "Description is required"
1083
+ });
1084
+ }
1085
+ async function promptPluginId(manifest) {
1086
+ return (0, import_prompts2.input)({
1087
+ message: "Plugin ID:",
1088
+ default: manifest.id || void 0,
1089
+ validate: (value) => value.trim() ? !0 : "Plugin ID is required"
1090
+ });
1091
+ }
1092
+ async function promptPluginTags() {
1093
+ return (await (0, import_prompts2.input)({
1094
+ message: "Tags (comma-separated):"
1095
+ })).split(",").map((tag) => tag.trim()).filter((tag) => tag.length > 0);
1096
+ }
1097
+
1098
+ // src/commands/catalog/index.ts
1099
+ async function catalog() {
1100
+ let manifest = await manifestManager.load(), state = await pluginStateManager.load();
1101
+ if (!state.trackerIssueKey) {
1102
+ logger_default.warning('Plugin is not registered yet. Run "tracker-cli register" first.'), logger_default.suggest("tracker-cli register");
1103
+ return;
1104
+ }
1105
+ logger_default.newLine(), logger_default.info("\u{1F4DD} Catalog entry information:");
1106
+ let name = await promptPluginName(), description = await promptPluginDescription(), tags = await promptPluginTags();
1107
+ await pluginStateManager.update({
1108
+ catalog: { name, description, tags }
1109
+ }), logger_default.newLine(), logger_default.info("\u{1F4E4} Syncing catalog metadata to Tracker issue...");
1110
+ let manifestJson = await manifestManager.loadRaw(), issueDescription = buildIssueDescription({
1111
+ pluginId: manifest.id ?? "",
1112
+ slug: manifest.slug,
1113
+ version: manifest.version,
1114
+ manifestJson,
1115
+ catalogName: name,
1116
+ catalogDescription: description,
1117
+ catalogTags: tags
1118
+ });
1119
+ await updatePluginIssue(state.trackerIssueKey, {
1120
+ description: issueDescription
1121
+ }), logger_default.success("Catalog entry updated successfully!");
1122
+ }
1123
+
1124
+ // src/commands/create/index.ts
1125
+ var path8 = __toESM(require("path")), import_prompts3 = require("@inquirer/prompts");
1126
+
1127
+ // src/core/manifest/constants.ts
1128
+ var DATA_PERMISSIONS = [
1129
+ // top 10
1130
+ "tracker:issues:read",
1131
+ "tracker:issues:write",
1132
+ "tracker:issuetypes:read",
1133
+ "tracker:statuses:read",
1134
+ "tracker:queues:read",
1135
+ "tracker:fields:read",
1136
+ "tracker:entities:read",
1137
+ "tracker:attachments:read",
1138
+ "tracker:attachments:write",
1139
+ // in alphabetical order
1140
+ "tracker:applications:read",
1141
+ "tracker:boards:read",
1142
+ "tracker:boards:write",
1143
+ "tracker:bulk:read",
1144
+ "tracker:bulk:write",
1145
+ "tracker:bulkchange:read",
1146
+ "tracker:bulkchange:write",
1147
+ "tracker:charts:read",
1148
+ "tracker:commentTemplates:read",
1149
+ "tracker:commentTemplates:write",
1150
+ "tracker:components:read",
1151
+ "tracker:components:write",
1152
+ "tracker:data:read",
1153
+ "tracker:departments:read",
1154
+ "tracker:entities:write",
1155
+ "tracker:externalEventTypes:write",
1156
+ "tracker:externalEvents:write",
1157
+ "tracker:fields:write",
1158
+ "tracker:filterFolders:write",
1159
+ "tracker:filters:read",
1160
+ "tracker:filters:write",
1161
+ "tracker:goals:read",
1162
+ "tracker:goals:write",
1163
+ "tracker:groups:read",
1164
+ "tracker:issueTemplates:read",
1165
+ "tracker:issueTemplates:write",
1166
+ "tracker:links:read",
1167
+ "tracker:linktypes:read",
1168
+ "tracker:liveBoards:write",
1169
+ "tracker:localFields:read",
1170
+ "tracker:maillists:read",
1171
+ "tracker:maillists:write",
1172
+ "tracker:myself:read",
1173
+ "tracker:myself:write",
1174
+ "tracker:priorities:read",
1175
+ "tracker:queues:write",
1176
+ "tracker:reminders:read",
1177
+ "tracker:reminders:write",
1178
+ "tracker:remotelinks:read",
1179
+ "tracker:reports:read",
1180
+ "tracker:reports:write",
1181
+ "tracker:resolutions:read",
1182
+ "tracker:resources:read",
1183
+ "tracker:resources:write",
1184
+ "tracker:roles:read",
1185
+ "tracker:screens:read",
1186
+ "tracker:services:read",
1187
+ "tracker:sprints:read",
1188
+ "tracker:sprints:write",
1189
+ "tracker:system:write",
1190
+ "tracker:tags:read",
1191
+ "tracker:translations:read",
1192
+ "tracker:users:read",
1193
+ "tracker:users:write",
1194
+ "tracker:versions:read",
1195
+ "tracker:versions:write",
1196
+ "tracker:workflows:read",
1197
+ "tracker:workflows:write",
1198
+ "tracker:worklog:read",
1199
+ "tracker:worklog:write"
1200
+ ], TOP_DATA_PERMISSIONS = DATA_PERMISSIONS.slice(0, 10);
1201
+ var TEMPLATES = [
1202
+ "default",
1203
+ "issue.action",
1204
+ "issue.block",
1205
+ "issue.tab",
1206
+ "issue.comment.action",
1207
+ "navigation",
1208
+ "trigger.action",
1209
+ "project.action",
1210
+ "portfolio.action",
1211
+ "goal.action",
1212
+ "issue.floatingbottom.action",
1213
+ "attachment.viewer.action"
1214
+ ];
1215
+ var TEMPLATE_SLOTS = {
1216
+ default: [],
1217
+ "issue.action": ["issue.action"],
1218
+ "issue.block": ["issue.block"],
1219
+ "issue.tab": ["issue.tab"],
1220
+ "issue.comment.action": ["issue.comment.action"],
1221
+ navigation: ["navigation"],
1222
+ "trigger.action": ["trigger.create.action", "trigger.edit.action"],
1223
+ "project.action": ["project.action"],
1224
+ "portfolio.action": ["portfolio.action"],
1225
+ "goal.action": ["goal.action"],
1226
+ "issue.floatingbottom.action": ["issue.floatingbottom.action"],
1227
+ "attachment.viewer.action": ["attachment.viewer.action"]
1228
+ };
1229
+
1230
+ // src/commands/create/index.ts
1231
+ init_logger();
1232
+
1233
+ // src/commands/create/utils/getWelcomeMessage.ts
1234
+ var import_picocolors2 = __toESM(require("picocolors")), getWelcomeMessage = (pwd) => `
1235
+ ${import_picocolors2.default.bold(import_picocolors2.default.white("\u{1F680} Create new tracker plugin"))}
1236
+
1237
+ ${import_picocolors2.default.dim(`\u{1F4C1} Creating an app in your current directory: ${pwd}`)}
1238
+
1239
+ ${import_picocolors2.default.dim("Press")} ${import_picocolors2.default.yellow("Ctrl+C")} ${import_picocolors2.default.dim("to cancel.")}
1240
+ `;
1241
+
1242
+ // src/commands/create/utils/initManifest.ts
1243
+ var fs2 = __toESM(require("fs")), path3 = __toESM(require("path"));
1244
+
1245
+ // src/commands/create/utils/generateManifest.ts
1246
+ function buildSlots(template, slotTitle) {
1247
+ let slotNames = TEMPLATE_SLOTS[template];
1248
+ if (slotNames.length === 0) return;
1249
+ let slotEntry = {
1250
+ entrypoint: "index.html",
1251
+ title: { ru: slotTitle, en: slotTitle }
1252
+ };
1253
+ return {
1254
+ tracker: Object.fromEntries(slotNames.map((slotName) => [slotName, [slotEntry]]))
1255
+ };
1256
+ }
1257
+ var generateManifest = (answers) => ({
1258
+ $schema: "./manifest.schema.json",
1259
+ slug: answers.packageSlug,
1260
+ version: answers.version,
1261
+ permissions: answers.permissions,
1262
+ slots: buildSlots(answers.template, answers.slotTitle)
1263
+ });
1264
+
1265
+ // src/commands/create/utils/initManifest.ts
1266
+ var initManifest = ({ answers, targetDir }) => {
1267
+ let generatedManifest = generateManifest(answers), manifestPath2 = path3.join(targetDir, "manifest.json");
1268
+ fs2.writeFileSync(manifestPath2, JSON.stringify(generatedManifest, null, 2), "utf-8");
1269
+ };
1270
+
1271
+ // src/commands/create/utils/initTemplate.ts
1272
+ var fs5 = __toESM(require("fs")), path7 = __toESM(require("path"));
1273
+
1274
+ // src/utils/copyDirectory.ts
1275
+ var fs3 = __toESM(require("fs")), import_path2 = __toESM(require("path")), import_tinyglobby = require("tinyglobby"), resolveTargetFileName = (file) => file.endsWith(".template") ? "." + file.replace(".template", "") : file, copyDirectory = async (sourceDir, targetDir) => {
1276
+ let files = await (0, import_tinyglobby.glob)(["**/*"], {
1277
+ cwd: sourceDir,
1278
+ onlyFiles: !0,
1279
+ dot: !0
1280
+ });
1281
+ await Promise.all(
1282
+ files.map(async (file) => {
1283
+ let sourcePath = import_path2.default.join(sourceDir, file), targetFile = resolveTargetFileName(file), targetPath = import_path2.default.join(targetDir, targetFile);
1284
+ await fs3.promises.mkdir(import_path2.default.dirname(targetPath), { recursive: !0 }), await fs3.promises.copyFile(sourcePath, targetPath);
1285
+ })
1286
+ );
1287
+ };
1288
+
1289
+ // src/utils/getProjectPath.ts
1290
+ var import_path3 = __toESM(require("path")), isDevelopment = () => __dirname.includes("/src/"), getProjectPath = (relativePath) => {
1291
+ let levelsUp = isDevelopment() ? "../.." : "..";
1292
+ return import_path3.default.resolve(__dirname, levelsUp, relativePath);
1293
+ }, getTemplatesBaseDir = () => getProjectPath("templates"), getTemplatePath = (filename) => import_path3.default.join(getTemplatesBaseDir(), "_shared", filename);
1294
+
1295
+ // src/commands/create/utils/initTemplate.ts
1296
+ init_logger();
1297
+
1298
+ // src/commands/create/utils/updatePackageJson.ts
1299
+ var fs4 = __toESM(require("fs")), path6 = __toESM(require("path")), updatePackageJson = (targetDir, packageSlug) => {
1300
+ let packageJsonPath = path6.join(targetDir, "package.json");
1301
+ if (fs4.existsSync(packageJsonPath)) {
1302
+ let packageJson = JSON.parse(fs4.readFileSync(packageJsonPath, "utf-8"));
1303
+ packageJson.name = packageSlug, fs4.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 4) + `
1304
+ `);
1305
+ }
1306
+ };
1307
+
1308
+ // src/commands/create/utils/initTemplate.ts
1309
+ var initTemplate = async ({ answers, targetDir }) => {
1310
+ fs5.existsSync(targetDir) || fs5.mkdirSync(targetDir, { recursive: !0 });
1311
+ let templatesBaseDir = getTemplatesBaseDir(), templatesDir = path7.join(templatesBaseDir, answers.template), sharedDir = path7.join(templatesBaseDir, "_shared");
1312
+ await copyDirectory(sharedDir, targetDir), await copyDirectory(templatesDir, targetDir), updatePackageJson(targetDir, answers.packageSlug), logger_default.info("Created template with marketplace publication requirements."), logger_default.info(
1313
+ "Before publishing, add ./marketplace/index.md, ./marketplace/header-image.jpg (784:325), and ./public/logo.svg (square)."
1314
+ );
1315
+ };
1316
+
1317
+ // src/commands/create/index.ts
1318
+ var DEFAULT_VERSION = "0.0.1";
1319
+ async function create() {
1320
+ logger_default.info(getWelcomeMessage(process.cwd()));
1321
+ let packageSlug = await (0, import_prompts3.input)({
1322
+ message: "Enter app slug (e.g., my-tracker-plugin):",
1323
+ required: !0
1324
+ }), template = await (0, import_prompts3.select)({
1325
+ message: "Select a template:",
1326
+ choices: TEMPLATES.map((templateName) => ({
1327
+ name: templateName,
1328
+ value: templateName
1329
+ }))
1330
+ }), dataPermissions = await (0, import_prompts3.checkbox)({
1331
+ message: "Select data permissions (some popular options):",
1332
+ choices: TOP_DATA_PERMISSIONS.map((permission) => ({
1333
+ name: permission,
1334
+ value: permission
1335
+ }))
1336
+ }), answers = {
1337
+ packageSlug,
1338
+ slotTitle: packageSlug,
1339
+ template,
1340
+ permissions: {
1341
+ data: dataPermissions
1342
+ },
1343
+ version: DEFAULT_VERSION
1344
+ }, targetDir = path8.join(process.cwd(), answers.packageSlug);
1345
+ await initTemplate({
1346
+ answers,
1347
+ targetDir
1348
+ }), initManifest({
1349
+ answers,
1350
+ targetDir
1351
+ }), logger_default.newLine(), logger_default.success("Package generated!"), logger_default.commands("To get started, run", [
1352
+ `cd ${answers.packageSlug}`,
1353
+ "npm install",
1354
+ "tracker-cli debug"
1355
+ ]);
1356
+ }
1357
+
1358
+ // src/commands/debug/index.ts
1359
+ var import_fs7 = __toESM(require("fs")), import_path7 = __toESM(require("path"));
1360
+
1361
+ // src/core/s3config/constants.ts
1362
+ var CONFIG_FILE_NAME = "config.json", mimeTypes = {
1363
+ ".html": "text/html",
1364
+ ".css": "text/css",
1365
+ ".js": "text/javascript",
1366
+ ".json": "application/json",
1367
+ ".png": "image/png",
1368
+ ".jpg": "image/jpeg",
1369
+ ".jpeg": "image/jpeg",
1370
+ ".gif": "image/gif",
1371
+ ".svg": "image/svg+xml",
1372
+ ".ico": "image/x-icon",
1373
+ ".txt": "text/plain",
1374
+ ".woff": "font/woff",
1375
+ ".woff2": "font/woff2",
1376
+ ".ttf": "font/ttf",
1377
+ ".eot": "application/vnd.ms-fontobject"
1378
+ };
1379
+
1380
+ // src/commands/debug/index.ts
1381
+ init_logger();
1382
+
1383
+ // src/utils/registerCleanup.ts
1384
+ var registerCleanup = (cleanup) => {
1385
+ process.on("SIGINT", () => {
1386
+ cleanup(), process.exit(0);
1387
+ }), process.on("SIGTERM", () => {
1388
+ cleanup(), process.exit(0);
1389
+ });
1390
+ };
1391
+
1392
+ // src/commands/debug/utils/createDebugConfig.ts
1393
+ var import_fs4 = __toESM(require("fs")), import_path4 = __toESM(require("path"));
1394
+
1395
+ // src/utils/convertManifestToConfig.ts
1396
+ function buildPluginDownloadUrl(baseUrl, id, version) {
1397
+ return `${baseUrl.replace(/\/+$/, "")}/${id}/${version}`;
1398
+ }
1399
+ var convertManifestToConfig = (manifest, downloadBaseUrl) => {
1400
+ let config = {};
1401
+ if (!manifest.slots)
1402
+ return config;
1403
+ for (let service in manifest.slots) {
1404
+ if (!Object.prototype.hasOwnProperty.call(manifest.slots, service))
1405
+ continue;
1406
+ let serviceSlots = manifest.slots[service];
1407
+ if (serviceSlots)
1408
+ for (let slotKey in serviceSlots) {
1409
+ if (!Object.prototype.hasOwnProperty.call(serviceSlots, slotKey))
1410
+ continue;
1411
+ let slot = slotKey, slotConfigs = serviceSlots[slot];
1412
+ if (!(!slotConfigs || !Array.isArray(slotConfigs))) {
1413
+ config[slot] || (config[slot] = []);
1414
+ for (let slotConfig of slotConfigs) {
1415
+ let pluginConfig = {
1416
+ slug: manifest.slug,
1417
+ version: manifest.version,
1418
+ permissions: manifest.permissions,
1419
+ description: slotConfig.description,
1420
+ entrypoint: slotConfig.entrypoint,
1421
+ title: slotConfig.title,
1422
+ downloadUrl: buildPluginDownloadUrl(
1423
+ downloadBaseUrl,
1424
+ manifest.slug,
1425
+ manifest.version
1426
+ )
1427
+ };
1428
+ config[slot].push(pluginConfig);
1429
+ }
1430
+ }
1431
+ }
1432
+ }
1433
+ return config;
1434
+ };
1435
+
1436
+ // src/commands/debug/utils/createDebugConfig.ts
1437
+ var DEBUG_DOWNLOAD_BASE = "http://localhost:5173/plugins-debug", createDebugConfig = async () => {
1438
+ let manifest = await manifestManager.load(), config = convertManifestToConfig(manifest, DEBUG_DOWNLOAD_BASE), configPath = import_path4.default.join(process.cwd(), CONFIG_FILE_NAME);
1439
+ import_fs4.default.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
1440
+ };
1441
+
1442
+ // src/commands/debug/utils/lockFile.ts
1443
+ var import_fs5 = __toESM(require("fs")), import_path5 = __toESM(require("path")), LOCK_FILE_NAME = ".tracker-cli-debug.lock", getLockFilePath = () => import_path5.default.join(process.cwd(), LOCK_FILE_NAME), getRunningDebugPid = () => {
1444
+ let lockPath = getLockFilePath();
1445
+ if (!import_fs5.default.existsSync(lockPath))
1446
+ return null;
1447
+ try {
1448
+ let pid = JSON.parse(import_fs5.default.readFileSync(lockPath, "utf-8")).pid;
1449
+ return process.kill(pid, 0), pid;
1450
+ } catch {
1451
+ try {
1452
+ import_fs5.default.unlinkSync(lockPath);
1453
+ } catch {
1454
+ }
1455
+ return null;
1456
+ }
1457
+ }, createLockFile = () => {
1458
+ let lockPath = getLockFilePath(), lockData = {
1459
+ pid: process.pid
1460
+ }, fd = import_fs5.default.openSync(lockPath, "wx");
1461
+ import_fs5.default.writeSync(fd, JSON.stringify(lockData, null, 2)), import_fs5.default.closeSync(fd);
1462
+ }, removeLockFile = () => {
1463
+ let lockPath = getLockFilePath();
1464
+ import_fs5.default.existsSync(lockPath) && import_fs5.default.unlinkSync(lockPath);
1465
+ };
1466
+
1467
+ // src/commands/debug/utils/watchManifest.ts
1468
+ var import_fs6 = __toESM(require("fs")), import_path6 = __toESM(require("path"));
1469
+ init_logger();
1470
+ var watchManifest = () => {
1471
+ let manifestPath2 = import_path6.default.join(process.cwd(), "manifest.json"), debounceTimer = null, watcher = import_fs6.default.watch(manifestPath2, async (eventType) => {
1472
+ eventType === "change" && (debounceTimer && clearTimeout(debounceTimer), debounceTimer = setTimeout(async () => {
1473
+ try {
1474
+ logger_default.newLine(), logger_default.info("Manifest file changed, validating..."), await manifestManager.validate(), logger_default.info("Regenerating debug config..."), await createDebugConfig(), logger_default.success("Debug config regenerated successfully");
1475
+ } catch (error2) {
1476
+ logger_default.error(`Failed to regenerate debug config: ${error2.message}`);
1477
+ }
1478
+ }, 300));
1479
+ }), originalClose = watcher.close.bind(watcher);
1480
+ return watcher.close = () => {
1481
+ debounceTimer && clearTimeout(debounceTimer), originalClose();
1482
+ }, watcher;
1483
+ };
1484
+
1485
+ // src/commands/debug/index.ts
1486
+ async function debug(options) {
1487
+ let runningPid = getRunningDebugPid();
1488
+ runningPid && (logger_default.error(
1489
+ `Another instance of tracker-cli debug is already running.
1490
+ Please stop the existing instance before starting a new one.
1491
+
1492
+ If you lost the terminal tab, you can kill the process with:
1493
+ kill ${runningPid}`
1494
+ ), process.exit(1));
1495
+ let configPath = import_path7.default.join(process.cwd(), CONFIG_FILE_NAME);
1496
+ options.lint && await manifestManager.validate(), await createDebugConfig();
1497
+ let watcher = watchManifest(), cleanup = () => {
1498
+ watcher.close(), import_fs7.default.existsSync(configPath) && import_fs7.default.unlinkSync(configPath), removeLockFile();
1499
+ };
1500
+ registerCleanup(cleanup), createLockFile(), await execCommand(pluginCmd.dev), cleanup();
1501
+ }
1502
+
1503
+ // src/distribution/promptEnvironment.ts
1504
+ var impl5 = (init_promptEnvironment(), __toCommonJS(promptEnvironment_exports)), { promptEnvironment: promptEnvironment2 } = impl5;
1505
+
1506
+ // src/core/s3config/s3Manager.ts
1507
+ var import_fs8 = require("fs"), import_promises4 = require("fs/promises"), os3 = __toESM(require("os")), import_path8 = __toESM(require("path")), import_client_s3 = require("@aws-sdk/client-s3"), import_lib_storage = require("@aws-sdk/lib-storage"), import_tinyglobby2 = require("tinyglobby");
1508
+
1509
+ // src/distribution/storage.ts
1510
+ var impl6 = (init_storage(), __toCommonJS(storage_exports)), { DEFAULT_ENVIRONMENT: DEFAULT_ENVIRONMENT2, getStorageSettings: getStorageSettings2, listEnvironments: listEnvironments2 } = impl6;
1511
+
1512
+ // src/core/s3config/s3Manager.ts
1513
+ init_logger();
1514
+
1515
+ // src/core/s3config/promptCredentials.ts
1516
+ var import_prompts4 = require("@inquirer/prompts"), promptS3Credentials = async () => {
1517
+ let s3AccessKeyId = await (0, import_prompts4.input)({
1518
+ message: "Enter S3_ACCESS_KEY_ID:",
1519
+ required: !0
1520
+ }), s3SecretAccessKey = await (0, import_prompts4.input)({
1521
+ message: "Enter S3_SECRET_ACCESS_KEY:",
1522
+ required: !0
1523
+ });
1524
+ return {
1525
+ s3AccessKeyId: s3AccessKeyId?.trim(),
1526
+ s3SecretAccessKey: s3SecretAccessKey?.trim()
1527
+ };
1528
+ }, promptMdsCredentials = async () => {
1529
+ let mdsAccessKeyId = await (0, import_prompts4.input)({
1530
+ message: "Enter MDS_ACCESS_KEY_ID:",
1531
+ required: !0
1532
+ }), mdsSecretAccessKey = await (0, import_prompts4.input)({
1533
+ message: "Enter MDS_SECRET_ACCESS_KEY:",
1534
+ required: !0
1535
+ });
1536
+ return {
1537
+ mdsAccessKeyId: mdsAccessKeyId?.trim(),
1538
+ mdsSecretAccessKey: mdsSecretAccessKey?.trim()
1539
+ };
1540
+ };
1541
+
1542
+ // src/core/s3config/s3Manager.ts
1543
+ var S3Manager = class {
1544
+ constructor() {
1545
+ this.credentialsDir = import_path8.default.join(os3.homedir(), ".tracker-cli");
1546
+ this.credentialsFile = import_path8.default.join(this.credentialsDir, "s3-credentials.json");
1547
+ this._environment = DEFAULT_ENVIRONMENT2;
1548
+ this._settings = null;
1549
+ }
1550
+ async setEnvironment(environment) {
1551
+ this._environment = environment, this._settings = await getStorageSettings2(environment), logger_default.info(`Environment set to: ${environment}`);
1552
+ }
1553
+ getEnvironment() {
1554
+ return this._environment;
1555
+ }
1556
+ getSettings() {
1557
+ if (!this._settings)
1558
+ throw new Error("Storage settings not loaded. Call s3Manager.setEnvironment() first.");
1559
+ return this._settings;
1560
+ }
1561
+ async checkS3Auth() {
1562
+ await this.checkAuth("s3");
1563
+ }
1564
+ async checkMdsAuth() {
1565
+ await this.checkAuth("mds");
1566
+ }
1567
+ async saveCredentials(credentials) {
1568
+ (0, import_fs8.existsSync)(this.credentialsDir) || (0, import_fs8.mkdirSync)(this.credentialsDir, { recursive: !0, mode: 448 }), await (0, import_promises4.writeFile)(this.credentialsFile, JSON.stringify(credentials, null, 2), {
1569
+ mode: 384
1570
+ });
1571
+ }
1572
+ get credentials() {
1573
+ try {
1574
+ if (!(0, import_fs8.existsSync)(this.credentialsFile))
1575
+ return null;
1576
+ let data = require("fs").readFileSync(this.credentialsFile, "utf-8");
1577
+ return JSON.parse(data);
1578
+ } catch {
1579
+ return null;
1580
+ }
1581
+ }
1582
+ async getPluginsConfig() {
1583
+ let s3Client = this.createMdsS3Client(), bucket = this.getSettings().configBucket;
1584
+ try {
1585
+ let { Body } = await s3Client.send(
1586
+ new import_client_s3.GetObjectCommand({ Bucket: bucket, Key: CONFIG_FILE_NAME })
1587
+ );
1588
+ if (!Body)
1589
+ return logger_default.info("NO DATA"), {};
1590
+ let text = await Body.transformToString("utf8");
1591
+ return JSON.parse(text);
1592
+ } catch (error2) {
1593
+ return logger_default.error("Error getting plugins config from S3", error2), process.exit();
1594
+ }
1595
+ }
1596
+ async savePluginsConfig(config) {
1597
+ let s3Client = this.createMdsS3Client(), bucket = this.getSettings().configBucket;
1598
+ try {
1599
+ await new import_lib_storage.Upload({
1600
+ client: s3Client,
1601
+ params: {
1602
+ Bucket: bucket,
1603
+ Key: CONFIG_FILE_NAME,
1604
+ Body: Buffer.from(JSON.stringify(config), "utf8"),
1605
+ ContentType: "application/json"
1606
+ }
1607
+ }).done();
1608
+ } catch (error2) {
1609
+ logger_default.error("Error writing plugins config to S3", error2), process.exit();
1610
+ }
1611
+ }
1612
+ async uploadPluginFiles(manifest, files) {
1613
+ if (files.length === 0) {
1614
+ logger_default.warning("No files to upload in dist folder");
1615
+ return;
1616
+ }
1617
+ let keyPrefix = `${manifest.slug}/${manifest.version}/`, s3Client = this.createAwsS3Client(), distPath = import_path8.default.resolve("./dist"), bucket = this.getSettings().staticBucket;
1618
+ logger_default.info(`\u{1F4E6} Starting file upload from ${distPath} to S3 bucket: ${bucket}`);
1619
+ for (let filePath of files)
1620
+ try {
1621
+ let fileContent = await (0, import_promises4.readFile)(filePath), relativePath = import_path8.default.relative(distPath, filePath), s3Key = keyPrefix + relativePath.replace(/\\/g, "/"), mimeType = this.getMimeType(filePath);
1622
+ logger_default.info(`\u2B06\uFE0F Uploading: ${relativePath}`), await new import_lib_storage.Upload({
1623
+ client: s3Client,
1624
+ params: {
1625
+ Bucket: bucket,
1626
+ Key: s3Key,
1627
+ Body: fileContent,
1628
+ ContentType: mimeType
1629
+ }
1630
+ }).done(), logger_default.success(`Uploaded: ${s3Key}`);
1631
+ } catch (error2) {
1632
+ logger_default.error(`Error uploading file ${filePath}`, error2), process.exit();
1633
+ }
1634
+ logger_default.success("Deployment completed successfully!");
1635
+ }
1636
+ /**
1637
+ * Upload extra root-level files/directories to S3 under the same slug/version prefix.
1638
+ * @param manifest slug + version for the key prefix
1639
+ * @param rootPaths paths relative to cwd, e.g. ['manifest.json', 'marketplace']
1640
+ */
1641
+ async uploadRootFiles(manifest, rootPaths) {
1642
+ let keyPrefix = `${manifest.slug}/${manifest.version}/`, s3Client = this.createAwsS3Client(), bucket = this.getSettings().staticBucket, cwd = process.cwd();
1643
+ for (let rootPath of rootPaths) {
1644
+ let absPath = import_path8.default.resolve(cwd, rootPath);
1645
+ if (!(0, import_fs8.existsSync)(absPath)) {
1646
+ logger_default.warning(`Skipping "${rootPath}" \u2014 not found`);
1647
+ continue;
1648
+ }
1649
+ if ((await import("fs")).statSync(absPath).isFile()) {
1650
+ let fileContent = await (0, import_promises4.readFile)(absPath), s3Key = keyPrefix + import_path8.default.basename(absPath), mimeType = this.getMimeType(absPath);
1651
+ logger_default.info(`\u2B06\uFE0F Uploading: ${rootPath}`), await new import_lib_storage.Upload({
1652
+ client: s3Client,
1653
+ params: {
1654
+ Bucket: bucket,
1655
+ Key: s3Key,
1656
+ Body: fileContent,
1657
+ ContentType: mimeType
1658
+ }
1659
+ }).done(), logger_default.success(`Uploaded: ${s3Key}`);
1660
+ } else {
1661
+ let files = await (0, import_tinyglobby2.glob)(["**/*"], {
1662
+ cwd: absPath,
1663
+ onlyFiles: !0,
1664
+ absolute: !0
1665
+ });
1666
+ for (let filePath of files)
1667
+ try {
1668
+ let fileContent = await (0, import_promises4.readFile)(filePath), relativePath = import_path8.default.relative(cwd, filePath), s3Key = keyPrefix + relativePath.replace(/\\/g, "/"), mimeType = this.getMimeType(filePath);
1669
+ logger_default.info(`\u2B06\uFE0F Uploading: ${relativePath}`), await new import_lib_storage.Upload({
1670
+ client: s3Client,
1671
+ params: {
1672
+ Bucket: bucket,
1673
+ Key: s3Key,
1674
+ Body: fileContent,
1675
+ ContentType: mimeType
1676
+ }
1677
+ }).done(), logger_default.success(`Uploaded: ${s3Key}`);
1678
+ } catch (error2) {
1679
+ logger_default.error(`Error uploading file ${filePath}`, error2), process.exit();
1680
+ }
1681
+ }
1682
+ }
1683
+ }
1684
+ createAwsS3Client() {
1685
+ let credentials = this.credentials, settings = this.getSettings();
1686
+ return (!credentials?.s3AccessKeyId || !credentials?.s3SecretAccessKey) && (logger_default.error("S3 credentials not found. Please log in using: tracker-cli login"), process.exit()), new import_client_s3.S3Client({
1687
+ region: settings.awsRegion,
1688
+ endpoint: settings.awsEndpoint,
1689
+ credentials: {
1690
+ accessKeyId: credentials.s3AccessKeyId,
1691
+ secretAccessKey: credentials.s3SecretAccessKey
1692
+ }
1693
+ });
1694
+ }
1695
+ async checkAuth(type) {
1696
+ (type === "s3" ? await this.validateS3Credentials() : await this.validateMdsCredentials()) || (type === "s3" ? await this.promptS3CredentialsAndSave() : await this.promptMdsCredentialsAndSave());
1697
+ }
1698
+ async validateS3Credentials(credentials) {
1699
+ let creds = credentials || this.credentials;
1700
+ if (!creds || !creds.s3AccessKeyId || !creds.s3SecretAccessKey)
1701
+ return !1;
1702
+ try {
1703
+ let settings = await this.resolveSettings();
1704
+ return await new import_client_s3.S3Client({
1705
+ region: settings.awsRegion,
1706
+ endpoint: settings.awsEndpoint,
1707
+ credentials: {
1708
+ accessKeyId: creds.s3AccessKeyId,
1709
+ secretAccessKey: creds.s3SecretAccessKey
1710
+ }
1711
+ }).send(new import_client_s3.ListBucketsCommand({})), !0;
1712
+ } catch (error2) {
1713
+ return logger_default.error("AWS S3 credential validation failed:", error2), !1;
1714
+ }
1715
+ }
1716
+ async validateMdsCredentials(credentials) {
1717
+ let creds = credentials || this.credentials;
1718
+ if (!creds || !creds.mdsAccessKeyId || !creds.mdsSecretAccessKey)
1719
+ return !1;
1720
+ try {
1721
+ let settings = await this.resolveSettings();
1722
+ return await new import_client_s3.S3Client({
1723
+ region: settings.awsRegion,
1724
+ endpoint: settings.mdsEndpoint,
1725
+ forcePathStyle: !0,
1726
+ credentials: {
1727
+ accessKeyId: creds.mdsAccessKeyId,
1728
+ secretAccessKey: creds.mdsSecretAccessKey
1729
+ }
1730
+ }).send(
1731
+ new import_client_s3.GetObjectCommand({ Bucket: settings.configBucket, Key: CONFIG_FILE_NAME })
1732
+ ), !0;
1733
+ } catch (error2) {
1734
+ return logger_default.error("MDS credential validation failed:", error2), !1;
1735
+ }
1736
+ }
1737
+ async promptS3CredentialsAndSave() {
1738
+ await this.promptAndSaveCredentials(
1739
+ "s3",
1740
+ promptS3Credentials,
1741
+ (creds) => this.validateS3Credentials(creds)
1742
+ );
1743
+ }
1744
+ async promptMdsCredentialsAndSave() {
1745
+ await this.promptAndSaveCredentials(
1746
+ "mds",
1747
+ promptMdsCredentials,
1748
+ (creds) => this.validateMdsCredentials(creds)
1749
+ );
1750
+ }
1751
+ async promptAndSaveCredentials(type, promptFn, validateFn) {
1752
+ logger_default.info(`Please enter your ${type.toUpperCase()} credentials:`);
1753
+ let newCreds = await promptFn(), updatedCreds = {
1754
+ ...this.credentials || {},
1755
+ ...newCreds
1756
+ };
1757
+ if (logger_default.info(`Validating ${type.toUpperCase()} credentials...`), !await validateFn(updatedCreds)) {
1758
+ await this.promptAndSaveCredentials(type, promptFn, validateFn);
1759
+ return;
1760
+ }
1761
+ await this.saveCredentials(updatedCreds), logger_default.success(`${type.toUpperCase()} credentials saved successfully.`);
1762
+ }
1763
+ createMdsS3Client() {
1764
+ let credentials = this.credentials, settings = this.getSettings();
1765
+ return (!credentials?.mdsAccessKeyId || !credentials?.mdsSecretAccessKey) && (logger_default.error("MdsS3 credentials not found. Please log in using: tracker-cli login"), process.exit()), new import_client_s3.S3Client({
1766
+ region: settings.awsRegion,
1767
+ endpoint: settings.mdsEndpoint,
1768
+ forcePathStyle: !0,
1769
+ credentials: {
1770
+ accessKeyId: credentials.mdsAccessKeyId,
1771
+ secretAccessKey: credentials.mdsSecretAccessKey
1772
+ }
1773
+ });
1774
+ }
1775
+ async resolveSettings() {
1776
+ return this._settings ? this._settings : (this._settings = await getStorageSettings2(this._environment), this._settings);
1777
+ }
1778
+ getMimeType(filePath) {
1779
+ let ext = import_path8.default.extname(filePath).toLowerCase();
1780
+ return mimeTypes[ext] || "application/octet-stream";
1781
+ }
1782
+ }, s3Manager = new S3Manager();
1783
+
1784
+ // src/utils/getFiles.ts
1785
+ var import_fs9 = __toESM(require("fs")), import_path9 = __toESM(require("path")), import_tinyglobby3 = require("tinyglobby");
1786
+ init_logger();
1787
+ var getFiles = async () => {
1788
+ let distPath = import_path9.default.resolve("./dist");
1789
+ import_fs9.default.existsSync(distPath) || (logger_default.error("Dist folder not found. Build the project first"), process.exit());
1790
+ let files = await (0, import_tinyglobby3.glob)(["**/*"], {
1791
+ cwd: distPath,
1792
+ onlyFiles: !0,
1793
+ absolute: !0
1794
+ });
1795
+ return logger_default.info(`\u{1F4C1} Found ${files.length} files to upload`), files;
1796
+ };
1797
+
1798
+ // src/commands/deploy/index.ts
1799
+ async function deploy() {
1800
+ let environment = await promptEnvironment2();
1801
+ await s3Manager.setEnvironment(environment), await s3Manager.checkS3Auth();
1802
+ let manifest = await manifestManager.load();
1803
+ await build({ environment });
1804
+ let files = await getFiles();
1805
+ await s3Manager.uploadPluginFiles(manifest, files);
1806
+ }
1807
+
1808
+ // src/api/utils.ts
1809
+ init_logger();
1810
+ function mapTrackerStatusToPluginStatus(issue) {
1811
+ let statusKey = issue.status.key, resolutionKey = issue.resolution?.key, resolutionDisplay = issue.resolution?.display;
1812
+ switch (statusKey) {
1813
+ case "open":
1814
+ return "draft";
1815
+ case "inProgress":
1816
+ return "waiting_for_review";
1817
+ case "need_info":
1818
+ return "need_info";
1819
+ case "waitingForApprove":
1820
+ return "pending_approval";
1821
+ case "closed":
1822
+ switch (resolutionKey) {
1823
+ case "agreed":
1824
+ return "approved";
1825
+ case "rejected":
1826
+ case "declined":
1827
+ return "rejected";
1828
+ default:
1829
+ return logger_default.warning(
1830
+ `[tracker-status-debug] Unknown closed resolution for ${issue.key}: status.key=${statusKey}, status.display=${issue.status.display ?? "n/a"}, resolution.key=${resolutionKey ?? "n/a"}, resolution.display=${resolutionDisplay ?? "n/a"}`
1831
+ ), "unknown";
1832
+ }
1833
+ default:
1834
+ return logger_default.warning(
1835
+ `[tracker-status-debug] Unknown tracker status for ${issue.key}: status.key=${statusKey}, status.display=${issue.status.display ?? "n/a"}, resolution.key=${resolutionKey ?? "n/a"}, resolution.display=${resolutionDisplay ?? "n/a"}`
1836
+ ), "unknown";
1837
+ }
1838
+ }
1839
+
1840
+ // src/commands/info/index.ts
1841
+ init_logger();
1842
+
1843
+ // src/utils/pluginDisplay.ts
1844
+ var import_picocolors3 = __toESM(require("picocolors"));
1845
+ init_logger();
1846
+ var printHeader = (title) => {
1847
+ console.info(import_picocolors3.default.bold(import_picocolors3.default.white(title)));
1848
+ }, printSuccessHeader = (title) => {
1849
+ console.info(import_picocolors3.default.bold(import_picocolors3.default.green(title)));
1850
+ }, getStatusBadge = (status) => {
1851
+ let normalized = status.toLowerCase();
1852
+ return normalized.includes("approved") ? import_picocolors3.default.black(import_picocolors3.default.bgGreen(` ${status} `)) : normalized.includes("pending") || normalized.includes("review") ? import_picocolors3.default.black(import_picocolors3.default.bgYellow(` ${status} `)) : normalized.includes("rejected") ? import_picocolors3.default.white(import_picocolors3.default.bgRed(` ${status} `)) : normalized.includes("draft") || normalized.includes("unknown") ? import_picocolors3.default.black(import_picocolors3.default.bgWhite(` ${status} `)) : import_picocolors3.default.black(import_picocolors3.default.bgBlue(` ${status} `));
1853
+ }, formatDate = (dateString) => dateString ? new Date(dateString).toLocaleString("ru-RU", {
1854
+ year: "numeric",
1855
+ month: "2-digit",
1856
+ day: "2-digit",
1857
+ hour: "2-digit",
1858
+ minute: "2-digit"
1859
+ }) : "-", printField = (label, value, minWidth = 12) => {
1860
+ console.info(` ${import_picocolors3.default.dim(label.padEnd(minWidth))} ${value}`);
1861
+ }, printPluginId = (pluginId) => {
1862
+ printField("Plugin ID", import_picocolors3.default.cyan(pluginId));
1863
+ }, printVersionId = (versionId) => {
1864
+ printField("Version ID", import_picocolors3.default.cyan(versionId));
1865
+ }, printStatus = (status) => {
1866
+ printField("Status", getStatusBadge(status.toUpperCase()));
1867
+ }, printCreated = (createdAt) => {
1868
+ printField("Created", import_picocolors3.default.white(formatDate(createdAt)));
1869
+ }, printUpdated = (updatedAt) => {
1870
+ printField("Updated", import_picocolors3.default.white(formatDate(updatedAt)));
1871
+ };
1872
+ function showPluginInfo(data) {
1873
+ printHeader("\u{1F4E6} Plugin"), logger_default.newLine(), printPluginId(data.id), printField("Slug", import_picocolors3.default.magenta(data.slug)), printField("Name", import_picocolors3.default.white(data.name)), printStatus(data.status), data.createdAt && printCreated(data.createdAt), data.updatedAt && printUpdated(data.updatedAt);
1874
+ }
1875
+ function showPluginVersions(versions2) {
1876
+ if (!versions2 || versions2.length === 0) {
1877
+ console.info(import_picocolors3.default.dim(" No versions found")), logger_default.newLine();
1878
+ return;
1879
+ }
1880
+ printHeader(`\u{1F9FE} Versions \xB7 ${versions2.length}`), logger_default.newLine(), versions2.forEach((version, index) => {
1881
+ console.info(` ${import_picocolors3.default.bold(String(index + 1) + ".")} ${import_picocolors3.default.cyan(version.versionId)}`), printField("Status", getStatusBadge(version.status.toUpperCase())), printField("Version", import_picocolors3.default.white(version.version)), printCreated(version.createdAt), logger_default.newLine();
1882
+ });
1883
+ }
1884
+ function showPluginList(plugins) {
1885
+ if (!plugins || plugins.length === 0) {
1886
+ console.info(import_picocolors3.default.dim(" No plugins found")), logger_default.newLine();
1887
+ return;
1888
+ }
1889
+ printHeader(`\u{1F4CB} Your Plugins \xB7 ${plugins.length}`), logger_default.newLine(), plugins.forEach((plugin) => {
1890
+ console.info(
1891
+ ` ${import_picocolors3.default.magenta(plugin.slug)} ${import_picocolors3.default.dim("\xB7")} ${getStatusBadge(plugin.status.toUpperCase())} ${import_picocolors3.default.dim("\xB7")} ${import_picocolors3.default.cyan(plugin.id)}`
1892
+ ), logger_default.newLine();
1893
+ });
1894
+ }
1895
+ function showPluginCreated(data) {
1896
+ printSuccessHeader("\u2705 Plugin Created"), logger_default.newLine(), printPluginId(data.id);
1897
+ }
1898
+ function showPluginSubmitted(data) {
1899
+ printSuccessHeader("\u{1F680} Plugin Submitted"), logger_default.newLine(), printPluginId(data.pluginId), printVersionId(data.versionId), printStatus(data.status);
1900
+ }
1901
+ function showTrackerPluginList(issues, mapStatus) {
1902
+ if (!issues || issues.length === 0) {
1903
+ console.info(import_picocolors3.default.dim(" No plugins found")), logger_default.newLine();
1904
+ return;
1905
+ }
1906
+ printHeader(`\u{1F4CB} Your Plugins \xB7 ${issues.length}`), logger_default.newLine(), issues.forEach((issue) => {
1907
+ let slugMatch = issue.summary.match(/^Plugin:\s*(.+)$/), slug = slugMatch ? import_picocolors3.default.magenta(slugMatch[1].trim()) : import_picocolors3.default.dim(issue.summary), lifecycleStatus = mapStatus(issue), statusBadge = getStatusBadge(lifecycleStatus.toUpperCase());
1908
+ console.info(
1909
+ ` ${slug} ${import_picocolors3.default.dim("\xB7")} ${statusBadge} ${import_picocolors3.default.dim("\xB7")} ${import_picocolors3.default.dim(issue.key)}`
1910
+ ), logger_default.newLine();
1911
+ });
1912
+ }
1913
+ function showTrackerPluginInfo(issue, mapStatus) {
1914
+ printHeader("\u{1F4E6} Plugin"), logger_default.newLine(), printField("Issue key", import_picocolors3.default.cyan(issue.key)), printField("Status", getStatusBadge(mapStatus(issue).toUpperCase())), printField("Summary", import_picocolors3.default.white(issue.summary)), issue.createdAt && printCreated(issue.createdAt), issue.updatedAt && printUpdated(issue.updatedAt);
1915
+ }
1916
+
1917
+ // src/commands/info/index.ts
1918
+ async function info2(issueKey) {
1919
+ let targetIssueKey = issueKey;
1920
+ if (targetIssueKey || (targetIssueKey = (await pluginStateManager.load()).trackerIssueKey), !targetIssueKey) {
1921
+ logger_default.warning(
1922
+ 'No issue key provided and plugin is not registered. Run "tracker-cli register" first.'
1923
+ ), logger_default.suggest("tracker-cli register");
1924
+ return;
1925
+ }
1926
+ logger_default.info(`\u23F3 Fetching plugin info for ${targetIssueKey}...`);
1927
+ try {
1928
+ let issue = await getIssue(targetIssueKey);
1929
+ showTrackerPluginInfo(issue, mapTrackerStatusToPluginStatus);
1930
+ } catch (error2) {
1931
+ throw logger_default.error(`Failed to fetch plugin info for ${targetIssueKey}`), error2;
1932
+ }
1933
+ }
1934
+
1935
+ // src/commands/install/index.ts
1936
+ init_logger();
1937
+
1938
+ // src/commands/install/utils/mergeConfigs.ts
1939
+ var mergeConfigs = (config, newConfig) => {
1940
+ let result = { ...config };
1941
+ for (let [key, newItems] of Object.entries(newConfig)) {
1942
+ let slotKey = key;
1943
+ if (!newItems || !Array.isArray(newItems))
1944
+ continue;
1945
+ let existingItems = result[slotKey];
1946
+ if (!existingItems) {
1947
+ result[slotKey] = [...newItems];
1948
+ continue;
1949
+ }
1950
+ let mergedItems = [];
1951
+ for (let existingItem of existingItems)
1952
+ newItems.some(
1953
+ (newItem) => newItem.slug === existingItem.slug
1954
+ ) || mergedItems.push(existingItem);
1955
+ mergedItems.push(...newItems), result[slotKey] = mergedItems;
1956
+ }
1957
+ return result;
1958
+ };
1959
+
1960
+ // src/commands/install/index.ts
1961
+ async function install() {
1962
+ let environment = await promptEnvironment2();
1963
+ await s3Manager.setEnvironment(environment), await s3Manager.checkMdsAuth();
1964
+ let [config, manifest] = await Promise.all([
1965
+ s3Manager.getPluginsConfig(),
1966
+ manifestManager.load()
1967
+ ]), settings = s3Manager.getSettings(), downloadBaseUrl = `${settings.awsEndpoint.replace(/\/+$/, "")}/${settings.staticBucket}`, pluginConfig = convertManifestToConfig(manifest, downloadBaseUrl), mergedConfig = mergeConfigs(config, pluginConfig);
1968
+ await s3Manager.savePluginsConfig(mergedConfig), logger_default.info("\u{1F389} Installation completed successfully!");
1969
+ }
1970
+
1971
+ // src/commands/lint.ts
1972
+ init_logger();
1973
+ async function lint() {
1974
+ logger_default.info("\u{1F50D} Running manifest.json validation..."), await manifestManager.validate(), logger_default.info("\u{1F50D} Running code lint check..."), await execCommand(pluginCmd.lint);
1975
+ }
1976
+
1977
+ // src/commands/list/index.ts
1978
+ init_logger();
1979
+ async function list() {
1980
+ logger_default.info("\u23F3 Fetching my plugins from Tracker...");
1981
+ try {
1982
+ let issues = await getMyPluginIssues();
1983
+ showTrackerPluginList(issues, mapTrackerStatusToPluginStatus);
1984
+ } catch (error2) {
1985
+ throw logger_default.error("Failed to fetch plugins list"), error2;
1986
+ }
1987
+ }
1988
+
1989
+ // src/api/apiRequest.ts
1990
+ async function apiRequest(endpoint, options = {}) {
1991
+ let { method = "GET", body, headers = {}, token } = options, authHeader = token ? `OAuth ${token}` : authManager.authHeader;
1992
+ if (!authHeader)
1993
+ throw new Error('Not authenticated. Run "tracker-cli login" first.');
1994
+ let requestHeaders = {
1995
+ Authorization: authHeader,
1996
+ "Content-Type": "application/json",
1997
+ ...headers
1998
+ }, requestOptions = {
1999
+ method,
2000
+ headers: requestHeaders
2001
+ };
2002
+ body && method !== "GET" && (requestOptions.body = JSON.stringify(body));
2003
+ let url = `${await getTrackerApiUrl2()}${endpoint}`, response = await fetch(url, requestOptions);
2004
+ if (!response.ok)
2005
+ throw new Error([response.status, response.statusText].join(" ").trim());
2006
+ let contentType = response.headers.get("content-type");
2007
+ return contentType && contentType.includes("application/json") ? await response.json() : await response.text();
2008
+ }
2009
+
2010
+ // src/api/user.ts
2011
+ async function getMyself() {
2012
+ return await apiRequest("/myself");
2013
+ }
2014
+ async function verifyToken(token) {
2015
+ return await apiRequest("/myself", { token });
2016
+ }
2017
+
2018
+ // src/commands/login/index.ts
2019
+ init_logger();
2020
+
2021
+ // src/commands/login/utils/promptForCredentials.ts
2022
+ var import_prompts5 = require("@inquirer/prompts"), import_picocolors4 = __toESM(require("picocolors"));
2023
+ var OSC = "\x1B]", BEL = "\x07", promptForCredentials = async () => {
2024
+ let tokenUrl = await getOAuthTokenUrl2();
2025
+ return tokenUrl && (console.info(
2026
+ import_picocolors4.default.dim("Get your OAuth token at: ") + import_picocolors4.default.cyan(`${OSC}8;;${tokenUrl}${BEL}${tokenUrl}${OSC}8;;${BEL}`)
2027
+ ), console.info("")), {
2028
+ token: (await (0, import_prompts5.input)({
2029
+ message: "Enter your OAuth token:",
2030
+ required: !0
2031
+ })).trim()
2032
+ };
2033
+ };
2034
+
2035
+ // src/commands/login/index.ts
2036
+ async function login() {
2037
+ let authToken = (await promptForCredentials()).token;
2038
+ try {
2039
+ let userInfo = await verifyToken(authToken);
2040
+ authManager.saveAuthData(authToken), logger_default.success(`Successfully logged in as ${userInfo.login}`);
2041
+ } catch (error2) {
2042
+ logger_default.error("Invalid token or API request failed", error2);
2043
+ }
2044
+ }
2045
+
2046
+ // src/commands/logout.ts
2047
+ init_logger();
2048
+ function logout() {
2049
+ try {
2050
+ if (!authManager.data) {
2051
+ logger_default.warning("You are not logged in");
2052
+ return;
2053
+ }
2054
+ authManager.removeAuthData(), logger_default.success("Successfully logged out");
2055
+ } catch (error2) {
2056
+ logger_default.error("Logout failed", error2);
2057
+ }
2058
+ }
2059
+
2060
+ // src/commands/register/index.ts
2061
+ var import_crypto = require("crypto");
2062
+ init_logger();
2063
+ async function register() {
2064
+ let manifest = await manifestManager.load(), state = await pluginStateManager.load();
2065
+ if (state.trackerIssueKey)
2066
+ try {
2067
+ let issue2 = await getIssue(state.trackerIssueKey);
2068
+ logger_default.error(
2069
+ `Plugin is already registered. Tracker issue: ${issue2.key} (${issue2.summary})`
2070
+ ), process.exit(1);
2071
+ } catch {
2072
+ }
2073
+ let pluginId = manifest.id ?? (0, import_crypto.randomUUID)();
2074
+ logger_default.info("\u23F3 Creating plugin issue in Tracker..."), manifest.id || await manifestManager.update({ id: pluginId });
2075
+ let manifestJson = await manifestManager.loadRaw(), issue = await createPluginIssue({
2076
+ pluginId,
2077
+ slug: manifest.slug,
2078
+ version: manifest.version,
2079
+ manifestJson
2080
+ });
2081
+ await pluginStateManager.update({ trackerIssueKey: issue.key }), logger_default.success("Plugin registered!"), logger_default.info(` Tracker issue : ${issue.key}`), logger_default.info(` Summary : ${issue.summary}`), logger_default.info(` Plugin UUID : ${pluginId}`), logger_default.commands("\u{1F4A1} Next steps", [
2082
+ "tracker-cli catalog # Update catalog metadata",
2083
+ "tracker-cli upload # Build and upload plugin bundle",
2084
+ "tracker-cli submit # Submit for review"
2085
+ ]);
2086
+ }
2087
+
2088
+ // src/commands/submit/index.ts
2089
+ init_logger();
2090
+ var SUBMIT_TRANSITION_DISPLAY = "waiting for approve";
2091
+ async function submit() {
2092
+ let manifest = await manifestManager.load(), state = await pluginStateManager.load();
2093
+ if (!state.trackerIssueKey) {
2094
+ logger_default.warning('Plugin is not registered yet. Run "tracker-cli register" first.'), logger_default.suggest("tracker-cli register");
2095
+ return;
2096
+ }
2097
+ let issueKey = state.trackerIssueKey;
2098
+ logger_default.info(`\u23F3 Checking for uploaded bundle on ${issueKey}...`);
2099
+ let attachments = await getIssueAttachments(issueKey), archiveName = `${manifest.slug}-${manifest.version}.zip`;
2100
+ if (!attachments.some((a) => a.name === archiveName)) {
2101
+ logger_default.warning(
2102
+ `No bundle found for version ${manifest.version}. Upload it first with "tracker-cli upload".`
2103
+ ), logger_default.suggest("tracker-cli upload");
2104
+ return;
2105
+ }
2106
+ logger_default.info(`\u23F3 Fetching available transitions for ${issueKey}...`);
2107
+ let transitions = await getIssueTransitions(issueKey), submitTransition = transitions.find(
2108
+ (t) => t.display?.toLowerCase().includes(SUBMIT_TRANSITION_DISPLAY) || t.id?.toLowerCase().includes("waitingforapprove") || t.id?.toLowerCase().includes("waiting")
2109
+ );
2110
+ if (!submitTransition) {
2111
+ let available = transitions.map((t) => `"${t.display ?? t.id}"`).join(", ");
2112
+ logger_default.error(
2113
+ `Could not find a "Waiting for approve" transition on ${issueKey}. Available: ${available}`
2114
+ );
2115
+ return;
2116
+ }
2117
+ logger_default.info(
2118
+ `\u{1F680} Submitting plugin for review (transition: "${submitTransition.display ?? submitTransition.id}")...`
2119
+ ), await executeIssueTransition(issueKey, submitTransition.id), await addIssueComment(issueKey, `Submitted version \`${manifest.version}\` for review.`), logger_default.success("Plugin submitted for review!"), logger_default.info(` Tracker issue : ${issueKey}`), logger_default.info(` Version : ${manifest.version}`);
2120
+ }
2121
+
2122
+ // src/commands/uninstall/index.ts
2123
+ init_logger();
2124
+
2125
+ // src/commands/uninstall/utils/removePluginFromConfig.ts
2126
+ var removePluginFromConfig = (config, pluginSlug) => {
2127
+ let removedFromSlots = [], updatedConfig = {};
2128
+ return Object.keys(config).forEach((slotName) => {
2129
+ let slotPlugins = config[slotName];
2130
+ if (!slotPlugins)
2131
+ return;
2132
+ let filteredPlugins = slotPlugins.filter((plugin) => plugin.slug !== pluginSlug);
2133
+ filteredPlugins.length < slotPlugins.length && removedFromSlots.push(slotName), updatedConfig[slotName] = filteredPlugins;
2134
+ }), { updatedConfig, removedFromSlots };
2135
+ };
2136
+
2137
+ // src/commands/uninstall/index.ts
2138
+ async function uninstall() {
2139
+ let environment = await promptEnvironment2();
2140
+ await s3Manager.setEnvironment(environment), await s3Manager.checkMdsAuth();
2141
+ let [config, manifest] = await Promise.all([
2142
+ s3Manager.getPluginsConfig(),
2143
+ manifestManager.load()
2144
+ ]);
2145
+ if (Object.keys(config).length === 0) {
2146
+ logger_default.info("\u{1F50D} Config is empty. Nothing to uninstall.");
2147
+ return;
2148
+ }
2149
+ let { updatedConfig, removedFromSlots } = removePluginFromConfig(config, manifest.slug);
2150
+ if (removedFromSlots.length === 0) {
2151
+ logger_default.info(
2152
+ `\u{1F50D} Plugin ${manifest.slug} not found in config. It may have already been removed.`
2153
+ );
2154
+ return;
2155
+ }
2156
+ await s3Manager.savePluginsConfig(updatedConfig), logger_default.success(
2157
+ `Plugin ${manifest.slug} successfully removed from slots: ${removedFromSlots.join(", ")}`
2158
+ );
2159
+ }
2160
+
2161
+ // src/commands/up/utils/copyTemplateFiles.ts
2162
+ var import_fs10 = require("fs"), import_promises5 = require("fs/promises");
2163
+ var copyTemplateFiles = async (filenames) => {
2164
+ await Promise.all(
2165
+ filenames.map(async (filename) => {
2166
+ let templatePath = getTemplatePath(filename), targetPath = `./${filename}`;
2167
+ (0, import_fs10.existsSync)(templatePath) && (0, import_fs10.existsSync)(targetPath) && await (0, import_promises5.copyFile)(templatePath, targetPath);
2168
+ })
2169
+ );
2170
+ };
2171
+
2172
+ // src/commands/up/utils/updatePackageDependencies.ts
2173
+ var import_fs11 = require("fs"), import_promises6 = require("fs/promises");
2174
+ var updatePackageDependencies = async (dependencies) => {
2175
+ let packageJsonPath = "./package.json", templatePackageJsonPath = getTemplatePath("package.json");
2176
+ if (!(0, import_fs11.existsSync)(packageJsonPath) || !(0, import_fs11.existsSync)(templatePackageJsonPath))
2177
+ return;
2178
+ let packageJsonContent = await (0, import_promises6.readFile)(packageJsonPath, "utf-8"), templatePackageJsonContent = await (0, import_promises6.readFile)(templatePackageJsonPath, "utf-8"), packageJson = JSON.parse(packageJsonContent), templatePackageJson = JSON.parse(templatePackageJsonContent), updated = !1;
2179
+ dependencies.forEach((dep) => {
2180
+ packageJson.dependencies?.[dep] && templatePackageJson.dependencies?.[dep] && packageJson.dependencies[dep] !== templatePackageJson.dependencies[dep] && (packageJson.dependencies[dep] = templatePackageJson.dependencies[dep], updated = !0);
2181
+ }), updated && await (0, import_promises6.writeFile)(packageJsonPath, JSON.stringify(packageJson, null, 4) + `
2182
+ `, "utf-8");
2183
+ };
2184
+
2185
+ // src/commands/up/index.ts
2186
+ var templateFiles = ["manifest.schema.json", "vite.config.ts"], templateDeps = [
2187
+ "@yandex-data-ui/tracker-plugin-sdk-react",
2188
+ "@yandex-data-ui/tracker-pub-api-types"
2189
+ ];
2190
+ async function up() {
2191
+ await copyTemplateFiles(templateFiles), await updatePackageDependencies(templateDeps);
2192
+ }
2193
+
2194
+ // src/utils/buildArchive.ts
2195
+ var import_path11 = __toESM(require("path")), import_archiver = __toESM(require("archiver"));
2196
+ init_logger();
2197
+
2198
+ // src/utils/marketplace.ts
2199
+ var import_fs12 = __toESM(require("fs")), import_path10 = __toESM(require("path"));
2200
+ init_logger();
2201
+ var MARKETPLACE_DIR = "marketplace", MARKETPLACE_INDEX_FILE = "index.md", MARKETPLACE_HEADER_IMAGE_FILE = "header-image.jpg", PUBLIC_DIR = "public", PUBLIC_LOGO_FILE = "logo.svg", MANIFEST_FILE = "manifest.json", DIST_DIR = "dist", SRC_DIR = "src", ensurePathExists = (targetPath, errorMessage) => {
2202
+ import_fs12.default.existsSync(targetPath) || (logger_default.error(errorMessage), process.exit(1));
2203
+ };
2204
+ function validateMarketplaceAssets() {
2205
+ let marketplaceDir = import_path10.default.resolve(MARKETPLACE_DIR);
2206
+ ensurePathExists(
2207
+ marketplaceDir,
2208
+ "Marketplace folder not found. Create ./marketplace and add index.md and header-image.jpg before publishing."
2209
+ ), ensurePathExists(
2210
+ import_path10.default.join(marketplaceDir, MARKETPLACE_INDEX_FILE),
2211
+ "Marketplace description not found. Add ./marketplace/index.md before publishing."
2212
+ ), ensurePathExists(
2213
+ import_path10.default.join(marketplaceDir, MARKETPLACE_HEADER_IMAGE_FILE),
2214
+ "Marketplace header image not found. Add ./marketplace/header-image.jpg before publishing."
2215
+ ), ensurePathExists(
2216
+ import_path10.default.resolve(PUBLIC_DIR, PUBLIC_LOGO_FILE),
2217
+ "Plugin logo not found. Add ./public/logo.svg before publishing."
2218
+ );
2219
+ }
2220
+ function validateArchiveSources() {
2221
+ ensurePathExists(import_path10.default.resolve(DIST_DIR), "Dist folder not found. Build the project first."), ensurePathExists(
2222
+ import_path10.default.resolve(SRC_DIR),
2223
+ "Source folder not found. Add ./src before publishing."
2224
+ ), ensurePathExists(import_path10.default.resolve(MANIFEST_FILE), "manifest.json not found in plugin root."), validateMarketplaceAssets();
2225
+ }
2226
+ var marketplacePaths = {
2227
+ distDir: DIST_DIR,
2228
+ srcDir: SRC_DIR,
2229
+ marketplaceDir: MARKETPLACE_DIR,
2230
+ manifestFile: MANIFEST_FILE
2231
+ };
2232
+
2233
+ // src/utils/buildArchive.ts
2234
+ async function buildArchive() {
2235
+ return validateArchiveSources(), new Promise((resolve2, reject) => {
2236
+ let archive = (0, import_archiver.default)("zip", { zlib: { level: 9 } }), chunks = [];
2237
+ archive.on("data", (chunk) => chunks.push(chunk)), archive.on("end", () => {
2238
+ let buffer = Buffer.concat(chunks);
2239
+ logger_default.info(`\u{1F4E6} Archive created (${buffer.length} bytes)`), resolve2(buffer);
2240
+ }), archive.on("error", reject), archive.file(import_path11.default.resolve(marketplacePaths.manifestFile), { name: "manifest.json" }), archive.directory(import_path11.default.resolve(marketplacePaths.distDir), "dist"), archive.directory(import_path11.default.resolve(marketplacePaths.srcDir), "src"), archive.directory(import_path11.default.resolve(marketplacePaths.marketplaceDir), "marketplace"), archive.finalize();
2241
+ });
2242
+ }
2243
+
2244
+ // src/commands/upload/index.ts
2245
+ init_logger();
2246
+ async function upload() {
2247
+ let manifest = await manifestManager.load(), state = await pluginStateManager.load();
2248
+ if (!state.trackerIssueKey) {
2249
+ logger_default.warning('Plugin is not registered yet. Run "tracker-cli register" first.'), logger_default.suggest("tracker-cli register");
2250
+ return;
2251
+ }
2252
+ logger_default.info("\u{1F528} Building plugin..."), await build(), logger_default.info("\u{1F4E6} Creating archive...");
2253
+ let archiveBuffer = await buildArchive(), archiveName = `${manifest.slug}-${manifest.version}.zip`;
2254
+ logger_default.info(`\u2B06\uFE0F Attaching ${archiveName} to ${state.trackerIssueKey}...`), await attachFileToIssue(state.trackerIssueKey, archiveBuffer, archiveName), await addIssueComment(
2255
+ state.trackerIssueKey,
2256
+ `Updated bundle: \`${archiveName}\` (${archiveBuffer.length} bytes)`
2257
+ ), logger_default.success(`Bundle updated on ${state.trackerIssueKey}: ${archiveName}`);
2258
+ }
2259
+
2260
+ // src/api/platform.ts
2261
+ var import_form_data2 = __toESM(require("form-data"));
2262
+
2263
+ // src/api/platformApiRequest.ts
2264
+ var import_node_fetch3 = __toESM(require("node-fetch"));
2265
+ function buildRequestHeaders(headers, formData) {
2266
+ let authHeader = authManager.authHeader, requestHeaders = {
2267
+ Accept: "*/*",
2268
+ ...authHeader ? { Authorization: authHeader } : {},
2269
+ ...headers
2270
+ };
2271
+ return formData || (requestHeaders["Content-Type"] = "application/json"), requestHeaders;
2272
+ }
2273
+ function buildRequestBody(method, body, formData) {
2274
+ if (formData) {
2275
+ let formHeaders = formData.getHeaders?.();
2276
+ return {
2277
+ body: formData,
2278
+ headers: formHeaders || {}
2279
+ };
2280
+ }
2281
+ return body && method !== "GET" ? { body: JSON.stringify(body) } : {};
2282
+ }
2283
+ function buildQueryString2(queryParams) {
2284
+ if (!queryParams || Object.keys(queryParams).length === 0)
2285
+ return "";
2286
+ let params = new URLSearchParams();
2287
+ return Object.entries(queryParams).forEach(([key, value]) => {
2288
+ params.append(key, String(value));
2289
+ }), `?${params.toString()}`;
2290
+ }
2291
+ async function parseResponse2(response) {
2292
+ return response.status === 204 || response.headers.get("content-length") === "0" ? void 0 : response.headers.get("content-type")?.includes("application/json") ? await response.json() : await response.text();
2293
+ }
2294
+ async function platformApiRequest(endpoint, options = {}) {
2295
+ let { method = "GET", body, headers = {}, formData, queryParams } = options, requestHeaders = buildRequestHeaders(headers, formData), { body: requestBody, headers: additionalHeaders } = buildRequestBody(
2296
+ method,
2297
+ body,
2298
+ formData
2299
+ ), requestOptions = {
2300
+ method,
2301
+ headers: { ...requestHeaders, ...additionalHeaders },
2302
+ body: requestBody
2303
+ }, queryString = buildQueryString2(queryParams), url = `${await getPlatformApiUrl2()}${endpoint}${queryString}`, response = await (0, import_node_fetch3.default)(url, requestOptions);
2304
+ if (!response.ok) {
2305
+ let errorText = await response.text(), errorMessage = errorText;
2306
+ try {
2307
+ let errorJson = JSON.parse(errorText);
2308
+ errorJson.message && (errorMessage = errorJson.message);
2309
+ } catch {
2310
+ }
2311
+ throw new Error(errorMessage);
2312
+ }
2313
+ return parseResponse2(response);
2314
+ }
2315
+
2316
+ // src/api/platform.ts
2317
+ async function createPlugin(manifestContent) {
2318
+ let formData = new import_form_data2.default();
2319
+ return formData.append("archive", manifestContent, {
2320
+ filename: "manifest.json",
2321
+ contentType: "application/json"
2322
+ }), platformApiRequest("/api/v1/plugins", {
2323
+ method: "POST",
2324
+ formData
2325
+ });
2326
+ }
2327
+ async function updatePluginArchive(pluginId, archiveBuffer, archiveName) {
2328
+ let formData = new import_form_data2.default();
2329
+ return formData.append("archive", archiveBuffer, {
2330
+ filename: archiveName,
2331
+ contentType: "application/zip"
2332
+ }), platformApiRequest(`/api/v1/plugins/${pluginId}/archive`, {
2333
+ method: "PUT",
2334
+ formData
2335
+ });
2336
+ }
2337
+ async function updateCatalogEntry(pluginId, catalogData) {
2338
+ return platformApiRequest(`/api/v1/plugins/${pluginId}/catalog-entry`, {
2339
+ method: "PUT",
2340
+ body: catalogData
2341
+ });
2342
+ }
2343
+ async function submitPlugin(pluginId, version) {
2344
+ return platformApiRequest(`/api/v1/plugins/${pluginId}/submit`, {
2345
+ method: "POST",
2346
+ queryParams: {
2347
+ version
2348
+ }
2349
+ });
2350
+ }
2351
+ async function getPluginInfo(pluginId) {
2352
+ return platformApiRequest(`/api/v1/plugins/${pluginId}`, {
2353
+ method: "GET"
2354
+ });
2355
+ }
2356
+ async function getPluginVersions(pluginId) {
2357
+ return platformApiRequest(`/api/v1/plugins/${pluginId}/versions`, {
2358
+ method: "GET"
2359
+ });
2360
+ }
2361
+ async function getMyPlugins() {
2362
+ return platformApiRequest("/api/v1/plugins/my", {
2363
+ method: "GET"
2364
+ });
2365
+ }
2366
+ async function checkSlugAvailability(slug) {
2367
+ return platformApiRequest(`/api/v1/slugs/${slug}/available`, {
2368
+ method: "GET"
2369
+ });
2370
+ }
2371
+
2372
+ // src/utils/getPluginId.ts
2373
+ async function getPluginId(pluginId) {
2374
+ if (pluginId)
2375
+ return pluginId;
2376
+ try {
2377
+ let manifest = await manifestManager.load();
2378
+ if (!manifest.id)
2379
+ throw new Error("Plugin ID not found in manifest.json");
2380
+ return manifest.id;
2381
+ } catch {
2382
+ throw new Error("Plugin ID must be provided as argument or present in manifest.json");
2383
+ }
2384
+ }
2385
+
2386
+ // src/commands/versions/index.ts
2387
+ init_logger();
2388
+ async function versions(pluginId) {
2389
+ let actualPluginId = await getPluginId(pluginId);
2390
+ logger_default.info(`\u23F3 Fetching versions for plugin ID: ${actualPluginId}...`);
2391
+ try {
2392
+ let pluginVersions = await getPluginVersions(actualPluginId);
2393
+ if (!pluginVersions || pluginVersions.length === 0) {
2394
+ logger_default.info("No versions found for this plugin.");
2395
+ return;
2396
+ }
2397
+ showPluginVersions(pluginVersions), logger_default.newLine();
2398
+ } catch (error2) {
2399
+ throw logger_default.error(`Failed to fetch versions for plugin ID: ${actualPluginId}`), error2;
2400
+ }
2401
+ }
2402
+
2403
+ // src/commands/whoami.ts
2404
+ init_logger();
2405
+ async function whoami() {
2406
+ if (!authManager.data) {
2407
+ logger_default.warning("You are not logged in"), logger_default.suggest("tracker-cli login");
2408
+ return;
2409
+ }
2410
+ try {
2411
+ let userInfo = await getMyself();
2412
+ logger_default.info(`Current user: ${userInfo.login}`);
2413
+ } catch {
2414
+ logger_default.warning("Failed to verify token with API");
2415
+ }
2416
+ }
2417
+
2418
+ // src/commands/catalog/platform.ts
2419
+ init_logger();
2420
+ async function catalogPlatform() {
2421
+ let manifest = await manifestManager.load(), pluginId = await promptPluginId(manifest);
2422
+ logger_default.newLine(), logger_default.info("\u{1F4DD} Catalog entry information:");
2423
+ let name = await promptPluginName(), description = await promptPluginDescription(), tags = await promptPluginTags();
2424
+ logger_default.newLine(), logger_default.info("\u{1F4E4} Updating catalog entry..."), await updateCatalogEntry(pluginId, {
2425
+ name,
2426
+ description,
2427
+ tags
2428
+ }), logger_default.success("Catalog entry updated successfully!");
2429
+ }
2430
+
2431
+ // src/commands/info/platform.ts
2432
+ init_logger();
2433
+ async function infoPlatform(pluginId) {
2434
+ let actualPluginId = await getPluginId(pluginId);
2435
+ logger_default.info(`\u23F3 Fetching plugin info for ID: ${actualPluginId}...`);
2436
+ try {
2437
+ let pluginInfo = await getPluginInfo(actualPluginId);
2438
+ showPluginInfo(pluginInfo), pluginInfo.versions && pluginInfo.versions.length > 0 && (logger_default.newLine(), showPluginVersions(pluginInfo.versions));
2439
+ } catch (error2) {
2440
+ throw logger_default.error(`Failed to fetch plugin info for ID: ${actualPluginId}`), error2;
2441
+ }
2442
+ }
2443
+
2444
+ // src/commands/list/platform.ts
2445
+ init_logger();
2446
+ async function listPlatform() {
2447
+ logger_default.info("\u23F3 Fetching my plugins...");
2448
+ try {
2449
+ let plugins = await getMyPlugins();
2450
+ showPluginList(plugins);
2451
+ } catch (error2) {
2452
+ throw logger_default.error("Failed to fetch plugins list"), error2;
2453
+ }
2454
+ }
2455
+
2456
+ // src/commands/register/platform.ts
2457
+ init_logger();
2458
+ async function registerPlatform() {
2459
+ let manifest = await manifestManager.load();
2460
+ if (manifest.id)
2461
+ try {
2462
+ let pluginInfo = await getPluginInfo(manifest.id);
2463
+ logger_default.error(`Plugin is already registered with ID: ${pluginInfo.id}`), process.exit(1);
2464
+ } catch {
2465
+ }
2466
+ await build(), logger_default.info("\u23F3 Creating plugin...");
2467
+ let manifestContent = await manifestManager.loadRaw(), response = await createPlugin(manifestContent);
2468
+ showPluginCreated(response), await manifestManager.update({ id: response.id }), logger_default.commands("\u{1F4A1} Next steps", [
2469
+ "tracker-cli catalog # Update catalog data",
2470
+ "tracker-cli submit # Submit for review"
2471
+ ]);
2472
+ }
2473
+
2474
+ // src/commands/submit/platform.ts
2475
+ init_logger();
2476
+
2477
+ // src/commands/submit/utils/validateSlug.ts
2478
+ var readline = __toESM(require("readline"));
2479
+ init_logger();
2480
+ function promptForSlug() {
2481
+ return new Promise((resolve2) => {
2482
+ let rl = readline.createInterface({
2483
+ input: process.stdin,
2484
+ output: process.stdout
2485
+ });
2486
+ rl.question("Enter a new slug: ", (answer) => {
2487
+ rl.close(), resolve2(answer.trim());
2488
+ });
2489
+ });
2490
+ }
2491
+ async function validateAndGetUniqueSlug(currentSlug) {
2492
+ let slugToCheck = currentSlug, isValid = !1;
2493
+ for (; !isValid; )
2494
+ try {
2495
+ if ((await checkSlugAvailability(slugToCheck)).available)
2496
+ return isValid = !0, slugToCheck;
2497
+ logger_default.error(`\u274C Slug "${slugToCheck}" is already taken.`), logger_default.info("Please enter a different slug."), slugToCheck = await promptForSlug(), slugToCheck || (logger_default.error("Slug cannot be empty. Please try again."), slugToCheck = currentSlug);
2498
+ } catch (error2) {
2499
+ throw logger_default.error(`Failed to check slug availability: ${error2.message}`), error2;
2500
+ }
2501
+ return slugToCheck;
2502
+ }
2503
+
2504
+ // src/commands/submit/platform.ts
2505
+ async function submitPlatform() {
2506
+ let manifest = await manifestManager.load(), pluginId = manifest.id;
2507
+ if (!pluginId) {
2508
+ logger_default.warning("Please register the plugin first"), logger_default.suggest("tracker-cli register");
2509
+ return;
2510
+ }
2511
+ let validatedSlug = await validateAndGetUniqueSlug(manifest.slug);
2512
+ validatedSlug !== manifest.slug && await manifestManager.update({ slug: validatedSlug });
2513
+ let response = await submitPlugin(pluginId, manifest.version);
2514
+ showPluginSubmitted(response), logger_default.newLine();
2515
+ }
2516
+
2517
+ // src/commands/upload/platform.ts
2518
+ init_logger();
2519
+ async function uploadPlatform() {
2520
+ let manifest = await manifestManager.load(), pluginId = manifest.id;
2521
+ if (!pluginId) {
2522
+ logger_default.warning("Please register the plugin first"), logger_default.suggest("tracker-cli register");
2523
+ return;
2524
+ }
2525
+ await build(), logger_default.info("\u{1F4E6} Creating archive...");
2526
+ let archiveBuffer = await buildArchive(), archiveName = `${manifest.slug}-${manifest.version}.zip`;
2527
+ logger_default.info("\u{1F4E4} Updating plugin archive..."), await updatePluginArchive(pluginId, archiveBuffer, archiveName), logger_default.success("Plugin archive updated successfully!");
2528
+ }
2529
+
2530
+ // src/utils/getVersion.ts
2531
+ var import_fs13 = require("fs"), import_path12 = require("path"), UNKNOWN_VERSION = "unknown", getVersionFromPackageJson = () => {
2532
+ try {
2533
+ let packagePath = (0, import_path12.resolve)(__dirname, "../../package.json");
2534
+ return (0, import_fs13.existsSync)(packagePath) && JSON.parse((0, import_fs13.readFileSync)(packagePath, "utf-8")).version || null;
2535
+ } catch {
2536
+ return null;
2537
+ }
2538
+ }, getVersion = () => "0.1.0-dev";
2539
+
2540
+ // src/index.ts
2541
+ init_logger();
2542
+ function withErrorHandling2(fn) {
2543
+ return async (...args) => {
2544
+ try {
2545
+ await fn(...args);
2546
+ } catch (error2) {
2547
+ error2 instanceof Error && error2.name === "ExitPromptError" && process.exit(0), logger_default.error(error2), process.exit(1);
2548
+ }
2549
+ };
2550
+ }
2551
+ async function main() {
2552
+ let program = new import_commander.Command(), version = getVersion();
2553
+ await checkUpdate(version), program.name(CLI_NAME2).description(CLI_DESCRIPTION2).version(version), CLI_HELP_TEXT2 && program.addHelpText("before", CLI_HELP_TEXT2), program.command("feedback").description("Let us know what you think about Yandex Tracker plugins").action(() => {
2554
+ logger_default.info(
2555
+ `Help us make Yandex Tracker even better.
2556
+ To report bugs or issues, go to: https://forms.yandex.ru/surveys/6767/`
2557
+ );
2558
+ }), program.command("create").description("create your app").action(withErrorHandling2(create)), program.command("up").description("update plugin from old template to latest version").action(withErrorHandling2(up)), program.command("build").description("build your app").action(withErrorHandling2(build)), program.command("debug").description(
2559
+ "start a tunnel to connect your local code with the app running in the development environment"
2560
+ ).option("--no-lint", "skip lint validation").action((options) => withErrorHandling2(debug)(options)), program.command("lint").description("run TypeScript and ESLint checks").action(withErrorHandling2(lint)), program.command("login").description("authenticate with Yandex Tracker").action(withErrorHandling2(login)), program.command("logout").description("remove authentication credentials").action(withErrorHandling2(logout)), program.command("whoami").description("display current authentication status").action(withErrorHandling2(async () => await whoami())), process.env.USE_BACKEND_TO_PUBLISH ? (program.command("register").description("register a new plugin and upload archive").action(withErrorHandling2(registerPlatform)), program.command("upload").description("upload plugin archive").action(withErrorHandling2(uploadPlatform)), program.command("update-catalog").description("update plugin catalog entry").action(withErrorHandling2(catalogPlatform)), program.command("submit").description("submit plugin for review").action(withErrorHandling2(submitPlatform)), program.command("list").description("list my plugins").action(withErrorHandling2(listPlatform)), program.command("info [plugin-id]").description(
2561
+ "get detailed information about a plugin (uses manifest.id if plugin-id not provided)"
2562
+ ).action(withErrorHandling2(infoPlatform)), program.command("versions [plugin-id]").description(
2563
+ "list all versions of a plugin (uses manifest.id if plugin-id not provided)"
2564
+ ).action(withErrorHandling2(versions))) : (program.command("register").description("register a new plugin and create a Tracker issue").action(withErrorHandling2(register)), program.command("upload").description("build and upload plugin bundle").action(withErrorHandling2(upload)), program.command("catalog").description("update plugin catalog metadata").action(withErrorHandling2(catalog)), program.command("submit").description("submit plugin for review").action(withErrorHandling2(submit)), program.command("list").description("list my plugins").action(withErrorHandling2(list)), program.command("info [issue-key]").description(
2565
+ "get detailed information about a plugin (uses manifest.trackerIssueKey if issue-key not provided)"
2566
+ ).action(withErrorHandling2(info2))), process.env.TRACKER_CLI_ADMIN && (program.command("deploy").description("build and upload plugin bundle to S3 for production").action(withErrorHandling2(deploy)), program.command("install").description("manage app installations").action(withErrorHandling2(install)), program.command("uninstall").description("uninstall app from all slots").action(withErrorHandling2(uninstall))), registerDistributionCommands2(program), await program.parseAsync(), process.exit(0);
2567
+ }
2568
+ main();