@weavix/cli 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/build/index.js +1641 -710
  2. package/build/templates/{_shared/src/styles-360.scss → _external/src/styles.scss} +2 -3
  3. package/build/templates/{_shared/src/styles-gravity.scss → _internal/src/styles.scss} +3 -2
  4. package/build/templates/_internal/src/themes/yandex-cloud/_dark-hc.scss +328 -0
  5. package/build/templates/_internal/src/themes/yandex-cloud/_dark.scss +329 -0
  6. package/build/templates/_internal/src/themes/yandex-cloud/_light-hc.scss +321 -0
  7. package/build/templates/_internal/src/themes/yandex-cloud/_light.scss +323 -0
  8. package/build/templates/_internal/src/themes/yandex-cloud.scss +168 -0
  9. package/build/templates/_shared/manifest.schema.json +183 -3
  10. package/build/templates/_shared/package.json +64 -65
  11. package/build/templates/_shared/src/main.tsx +1 -5
  12. package/build/templates/_shared/src/themes/yandex-360/_dark-hc.scss +296 -0
  13. package/build/templates/_shared/src/themes/yandex-360/_dark.scss +297 -0
  14. package/build/templates/_shared/src/themes/yandex-360/_light-hc.scss +289 -0
  15. package/build/templates/_shared/src/themes/yandex-360/_light.scss +291 -0
  16. package/build/templates/_shared/src/themes/yandex-360.scss +197 -0
  17. package/build/templates/_shared/src/themes/ys-text.scss +79 -0
  18. package/build/templates/_shared/vite.config.ts +2 -0
  19. package/build/templates/attachment.viewer.action/index.html +1 -1
  20. package/build/templates/attachment.viewer.action/src/App.tsx +13 -19
  21. package/build/templates/board.tab/index.html +14 -0
  22. package/build/templates/board.tab/src/App.tsx +27 -0
  23. package/build/templates/goal.action/index.html +1 -1
  24. package/build/templates/goal.action/src/App.tsx +4 -16
  25. package/build/templates/goal.block/index.html +14 -0
  26. package/build/templates/goal.block/src/App.tsx +27 -0
  27. package/build/templates/goal.tab/index.html +14 -0
  28. package/build/templates/goal.tab/src/App.tsx +27 -0
  29. package/build/templates/issue.action/index.html +1 -1
  30. package/build/templates/issue.action/src/App.tsx +3 -12
  31. package/build/templates/issue.block/index.html +1 -1
  32. package/build/templates/issue.block/src/App.tsx +9 -18
  33. package/build/templates/issue.comment.action/src/App.tsx +2 -8
  34. package/build/templates/issue.tab/src/App.tsx +2 -11
  35. package/build/templates/portfolio.action/index.html +1 -1
  36. package/build/templates/portfolio.action/src/App.tsx +4 -21
  37. package/build/templates/portfolio.block/index.html +14 -0
  38. package/build/templates/portfolio.block/src/App.tsx +27 -0
  39. package/build/templates/portfolio.tab/index.html +14 -0
  40. package/build/templates/portfolio.tab/src/App.tsx +27 -0
  41. package/build/templates/project.action/index.html +1 -1
  42. package/build/templates/project.action/src/App.tsx +4 -21
  43. package/build/templates/project.block/index.html +14 -0
  44. package/build/templates/project.block/src/App.tsx +27 -0
  45. package/build/templates/project.tab/index.html +14 -0
  46. package/build/templates/project.tab/src/App.tsx +27 -0
  47. package/build/templates/trigger.action/index.html +1 -1
  48. package/package.json +2 -1
package/build/index.js CHANGED
@@ -26,6 +26,13 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  mod
27
27
  )), __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: !0 }), mod);
28
28
 
29
+ // src/distribution/flag.ts
30
+ var init_flag = __esm({
31
+ "src/distribution/flag.ts"() {
32
+ "use strict";
33
+ }
34
+ });
35
+
29
36
  // src/distributions/external/meta.ts
30
37
  var meta_exports = {};
31
38
  __export(meta_exports, {
@@ -40,6 +47,26 @@ var CLI_NAME, CLI_DESCRIPTION, CLI_HELP_TEXT, init_meta = __esm({
40
47
  }
41
48
  });
42
49
 
50
+ // src/distribution/meta.ts
51
+ var impl, CLI_NAME2, CLI_DESCRIPTION2, CLI_HELP_TEXT2, init_meta2 = __esm({
52
+ "src/distribution/meta.ts"() {
53
+ "use strict";
54
+ init_flag();
55
+ impl = (init_meta(), __toCommonJS(meta_exports)), { CLI_NAME: CLI_NAME2, CLI_DESCRIPTION: CLI_DESCRIPTION2, CLI_HELP_TEXT: CLI_HELP_TEXT2 } = impl;
56
+ }
57
+ });
58
+
59
+ // src/commands/submit/options.ts
60
+ var import_commander, skipChecksOption, init_options = __esm({
61
+ "src/commands/submit/options.ts"() {
62
+ "use strict";
63
+ import_commander = require("commander"), skipChecksOption = new import_commander.Option(
64
+ "--skip-checks",
65
+ "skip pre-submit validation (manifest, assets, lint, typecheck, tests, audit)"
66
+ );
67
+ }
68
+ });
69
+
43
70
  // src/utils/verbose.ts
44
71
  function setVerboseEnabled(value) {
45
72
  verboseEnabled = value;
@@ -47,10 +74,14 @@ function setVerboseEnabled(value) {
47
74
  function isVerboseEnabled() {
48
75
  return verboseEnabled;
49
76
  }
50
- var verboseEnabled, init_verbose = __esm({
77
+ function writeVerboseArtifact(relativePath, content) {
78
+ let targetPath = import_path.default.resolve(".tracker-cli-debug", relativePath);
79
+ return import_fs.default.mkdirSync(import_path.default.dirname(targetPath), { recursive: !0 }), import_fs.default.writeFileSync(targetPath, content), targetPath;
80
+ }
81
+ var import_fs, import_path, verboseEnabled, init_verbose = __esm({
51
82
  "src/utils/verbose.ts"() {
52
83
  "use strict";
53
- verboseEnabled = !1;
84
+ import_fs = __toESM(require("fs")), import_path = __toESM(require("path")), verboseEnabled = !1;
54
85
  }
55
86
  });
56
87
 
@@ -112,25 +143,25 @@ function getConfigPath() {
112
143
  function readConfig() {
113
144
  if (cached !== void 0)
114
145
  return cached;
115
- if (!(0, import_fs.existsSync)(CONFIG_FILE))
146
+ if (!(0, import_fs2.existsSync)(CONFIG_FILE))
116
147
  return cached = null, cached;
117
148
  try {
118
- cached = JSON.parse((0, import_fs.readFileSync)(CONFIG_FILE, "utf-8"));
149
+ cached = JSON.parse((0, import_fs2.readFileSync)(CONFIG_FILE, "utf-8"));
119
150
  } catch {
120
151
  cached = null;
121
152
  }
122
153
  return cached;
123
154
  }
124
155
  function writeConfig(config) {
125
- (0, import_fs.existsSync)(CONFIG_DIR) || (0, import_fs.mkdirSync)(CONFIG_DIR, { recursive: !0, mode: 448 }), (0, import_fs.writeFileSync)(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 384 }), cached = config;
156
+ (0, import_fs2.existsSync)(CONFIG_DIR) || (0, import_fs2.mkdirSync)(CONFIG_DIR, { recursive: !0, mode: 448 }), (0, import_fs2.writeFileSync)(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 384 }), cached = config;
126
157
  }
127
158
  function clearConfig() {
128
- (0, import_fs.existsSync)(CONFIG_FILE) && (0, import_fs.rmSync)(CONFIG_FILE), cached = null;
159
+ (0, import_fs2.existsSync)(CONFIG_FILE) && (0, import_fs2.rmSync)(CONFIG_FILE), cached = null;
129
160
  }
130
- var import_fs, os, import_path, CONFIG_DIR, CONFIG_FILE, cached, init_manager = __esm({
161
+ var import_fs2, os, import_path2, CONFIG_DIR, CONFIG_FILE, cached, init_manager = __esm({
131
162
  "src/core/cliConfig/manager.ts"() {
132
163
  "use strict";
133
- import_fs = require("fs"), 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");
164
+ import_fs2 = require("fs"), os = __toESM(require("os")), import_path2 = __toESM(require("path")), CONFIG_DIR = import_path2.default.join(os.homedir(), ".tracker-cli"), CONFIG_FILE = import_path2.default.join(CONFIG_DIR, "config.json");
134
165
  }
135
166
  });
136
167
 
@@ -197,19 +228,1446 @@ var import_prompts, init_registerCommand = __esm({
197
228
  }
198
229
  });
199
230
 
231
+ // src/utils/withErrorHandling.ts
232
+ function withErrorHandling(fn) {
233
+ return async (...args) => {
234
+ try {
235
+ await fn(...args);
236
+ } catch (error2) {
237
+ error2 instanceof Error && error2.name === "ExitPromptError" && process.exit(0), logger_default.error(error2), process.exit(1);
238
+ }
239
+ };
240
+ }
241
+ var init_withErrorHandling = __esm({
242
+ "src/utils/withErrorHandling.ts"() {
243
+ "use strict";
244
+ init_logger();
245
+ }
246
+ });
247
+
248
+ // src/core/pluginState/pluginStateManager.ts
249
+ var import_fs3, import_promises, STATE_FILE, load, save, update, pluginStateManager, init_pluginStateManager = __esm({
250
+ "src/core/pluginState/pluginStateManager.ts"() {
251
+ "use strict";
252
+ import_fs3 = require("fs"), import_promises = require("fs/promises"), STATE_FILE = ".tracker-plugin", load = async () => {
253
+ if (!(0, import_fs3.existsSync)(STATE_FILE))
254
+ return {};
255
+ try {
256
+ let content = await (0, import_promises.readFile)(STATE_FILE, "utf8");
257
+ return JSON.parse(content);
258
+ } catch {
259
+ return {};
260
+ }
261
+ }, save = async (state) => {
262
+ try {
263
+ let content = JSON.stringify(state, null, 4);
264
+ await (0, import_promises.writeFile)(STATE_FILE, content, "utf8");
265
+ } catch (error2) {
266
+ throw error2 instanceof Error ? new Error(`Error saving ${STATE_FILE}: ${error2.message}`) : new Error(`Error saving ${STATE_FILE}`);
267
+ }
268
+ }, update = async (updates) => {
269
+ let updated = { ...await load(), ...updates };
270
+ return await save(updated), updated;
271
+ }, pluginStateManager = {
272
+ load,
273
+ save,
274
+ update
275
+ };
276
+ }
277
+ });
278
+
279
+ // src/api/utils.ts
280
+ function getIssueStatusLabel(issue) {
281
+ let { key: statusKey, display: statusDisplay } = issue.status;
282
+ return statusKey === "closed" && issue.resolution?.display ? issue.resolution.display : statusDisplay ?? statusKey;
283
+ }
284
+ function getIssueStatusCategory(issue) {
285
+ let statusKey = issue.status.key, resolutionKey = issue.resolution?.key;
286
+ if (statusKey === "closed")
287
+ return resolutionKey === "agreed" ? "approved" : resolutionKey === "rejected" || resolutionKey === "declined" ? "rejected" : "neutral";
288
+ switch (statusKey) {
289
+ case "waitingForApprove":
290
+ case "inProgress":
291
+ return "pending";
292
+ case "resultAcceptance":
293
+ return "acceptance";
294
+ case "testing":
295
+ return "testing";
296
+ case "need_info":
297
+ return "need_info";
298
+ default:
299
+ return "neutral";
300
+ }
301
+ }
302
+ var init_utils = __esm({
303
+ "src/api/utils.ts"() {
304
+ "use strict";
305
+ }
306
+ });
307
+
308
+ // src/utils/pluginDisplay.ts
309
+ function showTrackerPluginList(issues) {
310
+ if (!issues || issues.length === 0) {
311
+ console.info(import_picocolors2.default.dim(" No plugins found")), logger_default.newLine();
312
+ return;
313
+ }
314
+ printHeader(`\u{1F4CB} Your Plugins \xB7 ${issues.length}`), logger_default.newLine(), issues.forEach((issue) => {
315
+ let slugMatch = issue.summary.match(/^Plugin:\s*(.+)$/), slug = slugMatch ? import_picocolors2.default.magenta(slugMatch[1].trim()) : import_picocolors2.default.dim(issue.summary), statusBadge = getTrackerIssueBadge(issue);
316
+ console.info(
317
+ ` ${slug} ${import_picocolors2.default.dim("\xB7")} ${statusBadge} ${import_picocolors2.default.dim("\xB7")} ${import_picocolors2.default.dim(issue.key)}`
318
+ ), logger_default.newLine();
319
+ });
320
+ }
321
+ function showTrackerPluginInfo(issue) {
322
+ printHeader("\u{1F4E6} Plugin"), logger_default.newLine(), printField("Issue key", import_picocolors2.default.cyan(issue.key)), printField("Status", getTrackerIssueBadge(issue)), printField("Summary", import_picocolors2.default.white(issue.summary)), issue.createdAt && printCreated(issue.createdAt), issue.updatedAt && printUpdated(issue.updatedAt);
323
+ }
324
+ var import_picocolors2, printHeader, getTrackerIssueBadge, formatDate, printField, printCreated, printUpdated, init_pluginDisplay = __esm({
325
+ "src/utils/pluginDisplay.ts"() {
326
+ "use strict";
327
+ import_picocolors2 = __toESM(require("picocolors"));
328
+ init_utils();
329
+ init_logger();
330
+ printHeader = (title) => {
331
+ console.info(import_picocolors2.default.bold(import_picocolors2.default.white(title)));
332
+ }, getTrackerIssueBadge = (issue) => {
333
+ let label = getIssueStatusLabel(issue);
334
+ switch (getIssueStatusCategory(issue)) {
335
+ case "approved":
336
+ return import_picocolors2.default.black(import_picocolors2.default.bgGreen(` ${label} `));
337
+ case "rejected":
338
+ return import_picocolors2.default.white(import_picocolors2.default.bgRed(` ${label} `));
339
+ case "pending":
340
+ return import_picocolors2.default.black(import_picocolors2.default.bgYellow(` ${label} `));
341
+ case "acceptance":
342
+ return import_picocolors2.default.black(import_picocolors2.default.bgCyan(` ${label} `));
343
+ case "testing":
344
+ return import_picocolors2.default.black(import_picocolors2.default.bgMagenta(` ${label} `));
345
+ case "need_info":
346
+ return import_picocolors2.default.black(import_picocolors2.default.bgBlue(` ${label} `));
347
+ default:
348
+ return import_picocolors2.default.black(import_picocolors2.default.bgWhite(` ${label} `));
349
+ }
350
+ }, formatDate = (dateString) => dateString ? new Date(dateString).toLocaleString("ru-RU", {
351
+ year: "numeric",
352
+ month: "2-digit",
353
+ day: "2-digit",
354
+ hour: "2-digit",
355
+ minute: "2-digit"
356
+ }) : "-", printField = (label, value, minWidth = 12) => {
357
+ console.info(` ${import_picocolors2.default.dim(label.padEnd(minWidth))} ${value}`);
358
+ }, printCreated = (createdAt) => {
359
+ printField("Created", import_picocolors2.default.white(formatDate(createdAt)));
360
+ }, printUpdated = (updatedAt) => {
361
+ printField("Updated", import_picocolors2.default.white(formatDate(updatedAt)));
362
+ };
363
+ }
364
+ });
365
+
366
+ // src/distributions/external/authManager.ts
367
+ var fs2, os2, path3, authDir, authFile, getData, getToken, saveAuthData, removeAuthData, externalAuthManager, init_authManager = __esm({
368
+ "src/distributions/external/authManager.ts"() {
369
+ "use strict";
370
+ fs2 = __toESM(require("fs")), os2 = __toESM(require("os")), path3 = __toESM(require("path")), authDir = path3.join(os2.homedir(), ".weavix"), authFile = path3.join(authDir, "auth.json"), getData = () => {
371
+ try {
372
+ if (!fs2.existsSync(authFile))
373
+ return null;
374
+ let data = fs2.readFileSync(authFile, "utf-8");
375
+ return JSON.parse(data);
376
+ } catch {
377
+ return null;
378
+ }
379
+ }, getToken = () => getData()?.token ?? null, saveAuthData = (token) => {
380
+ let authData = { token };
381
+ fs2.existsSync(authDir) || fs2.mkdirSync(authDir, { recursive: !0, mode: 448 }), fs2.writeFileSync(authFile, JSON.stringify(authData, null, 2), {
382
+ mode: 384
383
+ });
384
+ }, removeAuthData = () => {
385
+ fs2.existsSync(authFile) && fs2.unlinkSync(authFile);
386
+ }, externalAuthManager = {
387
+ get token() {
388
+ return getToken();
389
+ },
390
+ get data() {
391
+ return getData();
392
+ },
393
+ saveAuthData,
394
+ removeAuthData
395
+ };
396
+ }
397
+ });
398
+
399
+ // src/distributions/external/trackerApiRequest.ts
400
+ function buildQueryString(queryParams) {
401
+ if (!queryParams || Object.keys(queryParams).length === 0)
402
+ return "";
403
+ let params = new URLSearchParams();
404
+ return Object.entries(queryParams).forEach(([key, value]) => {
405
+ params.append(key, String(value));
406
+ }), `?${params.toString()}`;
407
+ }
408
+ async function parseResponse(response) {
409
+ 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();
410
+ }
411
+ async function externalTrackerApiRequest(endpoint, options = {}) {
412
+ let { method = "GET", body, headers = {}, formData, queryParams } = options, token = externalAuthManager.token;
413
+ if (!token)
414
+ throw new Error(`Not authenticated. Run "${CLI_NAME} login" first.`);
415
+ let requestHeaders = {
416
+ Authorization: `OAuth ${token}`,
417
+ "X-Org-ID": ORG_ID,
418
+ Accept: "application/json",
419
+ ...headers
420
+ }, requestBody;
421
+ if (formData) {
422
+ let formHeaders = formData.getHeaders?.();
423
+ Object.assign(requestHeaders, formHeaders), requestBody = formData;
424
+ } else body && method !== "GET" && (requestHeaders["Content-Type"] = "application/json", requestBody = JSON.stringify(body));
425
+ let queryString = buildQueryString(queryParams), url = `${TRACKER_BASE_URL}${endpoint}${queryString}`, response = await (0, import_node_fetch.default)(url, {
426
+ method,
427
+ headers: requestHeaders,
428
+ body: requestBody
429
+ });
430
+ if (!response.ok) {
431
+ let errorText = await response.text(), errorMessage = `Tracker API error ${response.status}: ${errorText}`;
432
+ try {
433
+ let errorJson = JSON.parse(errorText);
434
+ errorJson.message && (errorMessage = `Tracker API error ${response.status}: ${errorJson.message}`);
435
+ } catch {
436
+ }
437
+ throw new Error(errorMessage);
438
+ }
439
+ return parseResponse(response);
440
+ }
441
+ var import_node_fetch, TRACKER_BASE_URL, ORG_ID, init_trackerApiRequest = __esm({
442
+ "src/distributions/external/trackerApiRequest.ts"() {
443
+ "use strict";
444
+ import_node_fetch = __toESM(require("node-fetch"));
445
+ init_authManager();
446
+ init_meta();
447
+ TRACKER_BASE_URL = "https://api.tracker.yandex.net/v3", ORG_ID = "8470884";
448
+ }
449
+ });
450
+
451
+ // src/distributions/external/tracker.ts
452
+ function buildIssueSummary(slug) {
453
+ return `Plugin: ${slug}`;
454
+ }
455
+ function buildIssueDescription(params) {
456
+ let { pluginId, slug, version, manifestJson } = params;
457
+ return [
458
+ `**Plugin UUID:** ${pluginId}`,
459
+ `**Slug:** ${slug}`,
460
+ `**Version:** ${version}`,
461
+ "",
462
+ "**Manifest:**",
463
+ "```json",
464
+ manifestJson,
465
+ "```"
466
+ ].join(`
467
+ `);
468
+ }
469
+ async function createPluginIssue(params) {
470
+ let { slug, pluginId, version, manifestJson } = params, body = {
471
+ queue: PLUGINMOD_QUEUE,
472
+ summary: buildIssueSummary(slug),
473
+ description: buildIssueDescription({ pluginId, slug, version, manifestJson }),
474
+ tags: ["tracker-plugin"]
475
+ };
476
+ return externalTrackerApiRequest("/issues", {
477
+ method: "POST",
478
+ body
479
+ });
480
+ }
481
+ async function updatePluginIssue(issueKey, params) {
482
+ return externalTrackerApiRequest(`/issues/${issueKey}`, {
483
+ method: "PATCH",
484
+ body: params
485
+ });
486
+ }
487
+ async function attachFileToIssue(issueKey, fileBuffer, fileName) {
488
+ let formData = new import_form_data.default();
489
+ return formData.append("file", fileBuffer, {
490
+ filename: fileName,
491
+ contentType: "application/zip"
492
+ }), externalTrackerApiRequest(`/issues/${issueKey}/attachments`, {
493
+ method: "POST",
494
+ formData
495
+ });
496
+ }
497
+ async function getIssueTransitions(issueKey) {
498
+ return externalTrackerApiRequest(`/issues/${issueKey}/transitions`, {
499
+ method: "GET"
500
+ });
501
+ }
502
+ async function executeIssueTransition(issueKey, transitionId) {
503
+ await externalTrackerApiRequest(
504
+ `/issues/${issueKey}/transitions/${transitionId}/_execute`,
505
+ {
506
+ method: "POST",
507
+ body: {}
508
+ }
509
+ );
510
+ }
511
+ async function getIssue(issueKey) {
512
+ return externalTrackerApiRequest(`/issues/${issueKey}`, {
513
+ method: "GET"
514
+ });
515
+ }
516
+ async function addIssueComment(issueKey, text) {
517
+ await externalTrackerApiRequest(`/issues/${issueKey}/comments`, {
518
+ method: "POST",
519
+ body: { text }
520
+ });
521
+ }
522
+ async function getMyPluginIssues() {
523
+ return externalTrackerApiRequest("/issues/_search", {
524
+ method: "POST",
525
+ body: {
526
+ filter: {
527
+ queue: "PLUGINMOD",
528
+ createdBy: "me()"
529
+ }
530
+ }
531
+ });
532
+ }
533
+ var import_form_data, PLUGINMOD_QUEUE, init_tracker = __esm({
534
+ "src/distributions/external/tracker.ts"() {
535
+ "use strict";
536
+ import_form_data = __toESM(require("form-data"));
537
+ init_trackerApiRequest();
538
+ PLUGINMOD_QUEUE = "PLUGINMOD";
539
+ }
540
+ });
541
+
542
+ // src/distributions/external/info.ts
543
+ async function infoExternal(issueKey) {
544
+ let targetIssueKey = issueKey;
545
+ if (targetIssueKey || (targetIssueKey = (await pluginStateManager.load()).trackerIssueKey), !targetIssueKey) {
546
+ logger_default.warning(
547
+ `No issue key provided and plugin has not been submitted yet. Run "${CLI_NAME} submit" first.`
548
+ ), logger_default.suggest(`${CLI_NAME} submit`);
549
+ return;
550
+ }
551
+ logger_default.info(`\u23F3 Fetching plugin info for ${targetIssueKey}...`);
552
+ try {
553
+ let issue = await getIssue(targetIssueKey);
554
+ showTrackerPluginInfo(issue);
555
+ } catch (error2) {
556
+ throw logger_default.error(`Failed to fetch plugin info for ${targetIssueKey}`), error2;
557
+ }
558
+ }
559
+ var init_info = __esm({
560
+ "src/distributions/external/info.ts"() {
561
+ "use strict";
562
+ init_pluginStateManager();
563
+ init_logger();
564
+ init_pluginDisplay();
565
+ init_meta();
566
+ init_tracker();
567
+ }
568
+ });
569
+
570
+ // src/distributions/external/list.ts
571
+ async function listExternal() {
572
+ logger_default.info("\u23F3 Fetching my plugins from Tracker...");
573
+ try {
574
+ let issues = await getMyPluginIssues();
575
+ showTrackerPluginList(issues);
576
+ } catch (error2) {
577
+ throw logger_default.error("Failed to fetch plugins list"), error2;
578
+ }
579
+ }
580
+ var init_list = __esm({
581
+ "src/distributions/external/list.ts"() {
582
+ "use strict";
583
+ init_logger();
584
+ init_pluginDisplay();
585
+ init_tracker();
586
+ }
587
+ });
588
+
589
+ // src/distributions/external/login.ts
590
+ async function loginExternal() {
591
+ console.info(
592
+ import_picocolors3.default.dim(
593
+ "To get an OAuth token for Yandex Tracker, please contact Tracker support and request one."
594
+ )
595
+ ), console.info("");
596
+ let trimmed = (await (0, import_prompts2.input)({
597
+ message: "Enter your OAuth token:",
598
+ required: !0
599
+ })).trim();
600
+ externalAuthManager.saveAuthData(trimmed), logger_default.success("OAuth token saved successfully."), logger_default.info('You can now use "weavix submit" to submit your plugin for review.');
601
+ }
602
+ function logoutExternal() {
603
+ if (!externalAuthManager.data) {
604
+ logger_default.warning("You are not logged in.");
605
+ return;
606
+ }
607
+ externalAuthManager.removeAuthData(), logger_default.success("Successfully logged out.");
608
+ }
609
+ var import_prompts2, import_picocolors3, init_login = __esm({
610
+ "src/distributions/external/login.ts"() {
611
+ "use strict";
612
+ import_prompts2 = require("@inquirer/prompts"), import_picocolors3 = __toESM(require("picocolors"));
613
+ init_logger();
614
+ init_authManager();
615
+ }
616
+ });
617
+
618
+ // src/utils/execCommand.ts
619
+ var import_execa, execCommand, init_execCommand = __esm({
620
+ "src/utils/execCommand.ts"() {
621
+ "use strict";
622
+ import_execa = require("execa"), execCommand = async (command, cwd = process.cwd(), env) => {
623
+ await (0, import_execa.execa)(command, {
624
+ cwd,
625
+ shell: !0,
626
+ stdio: "inherit",
627
+ env: env ? { ...process.env, ...env } : void 0
628
+ });
629
+ };
630
+ }
631
+ });
632
+
633
+ // src/commands/constants/templateCommands.ts
634
+ var pluginCmd, init_templateCommands = __esm({
635
+ "src/commands/constants/templateCommands.ts"() {
636
+ "use strict";
637
+ pluginCmd = {
638
+ install: "npm install",
639
+ build: "npm run build",
640
+ dev: "npm run dev",
641
+ lint: "npm run lint",
642
+ typecheck: "npm run typecheck",
643
+ test: "npm test",
644
+ audit: "npm audit --audit-level=critical"
645
+ };
646
+ }
647
+ });
648
+
649
+ // src/commands/build.ts
650
+ var build, init_build = __esm({
651
+ "src/commands/build.ts"() {
652
+ "use strict";
653
+ init_execCommand();
654
+ init_logger();
655
+ init_templateCommands();
656
+ build = async ({ environment = "production" } = {}) => {
657
+ logger_default.info("\u{1F528} Building project..."), await execCommand(pluginCmd.install), await execCommand(
658
+ pluginCmd.build,
659
+ process.cwd(),
660
+ environment ? { VITE_DEPLOY_ENV: environment } : void 0
661
+ );
662
+ };
663
+ }
664
+ });
665
+
666
+ // src/distributions/external/manifestPermissionsSchema.ts
667
+ var manifestPermissionsSchema_exports = {};
668
+ __export(manifestPermissionsSchema_exports, {
669
+ permissionsSchemaExtensions: () => permissionsSchemaExtensions
670
+ });
671
+ var permissionsSchemaExtensions, init_manifestPermissionsSchema = __esm({
672
+ "src/distributions/external/manifestPermissionsSchema.ts"() {
673
+ "use strict";
674
+ permissionsSchemaExtensions = {};
675
+ }
676
+ });
677
+
678
+ // src/distribution/manifestPermissionsSchema.ts
679
+ var impl2, permissionsSchemaExtensions2, init_manifestPermissionsSchema2 = __esm({
680
+ "src/distribution/manifestPermissionsSchema.ts"() {
681
+ "use strict";
682
+ init_flag();
683
+ impl2 = (init_manifestPermissionsSchema(), __toCommonJS(manifestPermissionsSchema_exports)), { permissionsSchemaExtensions: permissionsSchemaExtensions2 } = impl2;
684
+ }
685
+ });
686
+
687
+ // src/core/manifest/formatValidationErrors.ts
688
+ var priorityOrder, errorMessages, getPriority, formatValidationErrors, init_formatValidationErrors = __esm({
689
+ "src/core/manifest/formatValidationErrors.ts"() {
690
+ "use strict";
691
+ priorityOrder = [
692
+ "required",
693
+ "type",
694
+ "minLength",
695
+ "format",
696
+ "pattern",
697
+ "enum",
698
+ "additionalProperties",
699
+ "uniqueItems"
700
+ ], errorMessages = {
701
+ required: (params) => `missing required property '${params.missingProperty}'`,
702
+ type: (params) => `must be ${params.type}`,
703
+ enum: (params) => `must be one of [${params.allowedValues.join(", ")}]`,
704
+ pattern: (params) => `must match pattern ${params.pattern}`,
705
+ format: (params) => `must be a valid ${params.format}`,
706
+ minLength: () => "must not be empty",
707
+ additionalProperties: (params) => `unexpected property '${params.additionalProperty}'`,
708
+ uniqueItems: () => "must contain unique items"
709
+ }, getPriority = (keyword) => {
710
+ let index = priorityOrder.indexOf(keyword);
711
+ return index === -1 ? priorityOrder.length : index;
712
+ }, formatValidationErrors = (errors) => {
713
+ let errorsByPath = {};
714
+ for (let error2 of errors) {
715
+ let path18 = error2.instancePath || "root";
716
+ errorsByPath[path18] || (errorsByPath[path18] = []), errorsByPath[path18].push(error2);
717
+ }
718
+ return Object.entries(errorsByPath).map(([path18, pathErrors]) => {
719
+ let error2 = [...pathErrors].sort(
720
+ (a, b) => getPriority(a.keyword) - getPriority(b.keyword)
721
+ )[0], formatter = errorMessages[error2.keyword], message = formatter ? formatter(error2.params) : error2.message;
722
+ return ` - ${path18}: ${message}`;
723
+ }).join(`
724
+ `);
725
+ };
726
+ }
727
+ });
728
+
729
+ // src/core/manifest/manifest.schema.json
730
+ var manifest_schema_default, init_manifest_schema = __esm({
731
+ "src/core/manifest/manifest.schema.json"() {
732
+ manifest_schema_default = {
733
+ $schema: "http://json-schema.org/draft-07/schema#",
734
+ title: "Manifest",
735
+ description: "Schema for validating plugin manifest",
736
+ type: "object",
737
+ required: [
738
+ "slug",
739
+ "version",
740
+ "permissions",
741
+ "name",
742
+ "description",
743
+ "support"
744
+ ],
745
+ properties: {
746
+ $schema: {
747
+ type: "string"
748
+ },
749
+ id: {
750
+ type: "string",
751
+ description: "Unique identifier for the plugin ()",
752
+ minLength: 3,
753
+ maxLength: 63,
754
+ pattern: "^[a-z0-9-]+$"
755
+ },
756
+ manifest_version: {
757
+ type: "number",
758
+ description: "Manifest format version",
759
+ minimum: 1
760
+ },
761
+ supported_services: {
762
+ type: "array",
763
+ description: "Supported services for this plugin",
764
+ items: {
765
+ type: "string",
766
+ enum: [
767
+ "tracker"
768
+ ]
769
+ },
770
+ minItems: 1,
771
+ uniqueItems: !0
772
+ },
773
+ slug: {
774
+ type: "string",
775
+ description: "Unique identifier for the plugin (lowercase letters, numbers, hyphen)",
776
+ minLength: 3,
777
+ maxLength: 63,
778
+ pattern: "^[a-z0-9-]+$"
779
+ },
780
+ version: {
781
+ type: "string",
782
+ description: "Version of the plugin (semver format required)",
783
+ minLength: 1,
784
+ pattern: "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?(\\+[a-zA-Z0-9.-]+)?$"
785
+ },
786
+ name: {
787
+ type: "object",
788
+ description: "Localized plugin name",
789
+ required: [
790
+ "ru",
791
+ "en"
792
+ ],
793
+ properties: {
794
+ ru: {
795
+ type: "string",
796
+ description: "Russian name",
797
+ minLength: 1,
798
+ maxLength: 30
799
+ },
800
+ en: {
801
+ type: "string",
802
+ description: "English name",
803
+ minLength: 1,
804
+ maxLength: 30
805
+ }
806
+ },
807
+ additionalProperties: !1
808
+ },
809
+ description: {
810
+ type: "object",
811
+ description: "Localized plugin description",
812
+ required: [
813
+ "ru",
814
+ "en"
815
+ ],
816
+ properties: {
817
+ ru: {
818
+ type: "string",
819
+ description: "Russian description",
820
+ minLength: 1,
821
+ maxLength: 255
822
+ },
823
+ en: {
824
+ type: "string",
825
+ description: "English description",
826
+ minLength: 1,
827
+ maxLength: 255
828
+ }
829
+ },
830
+ additionalProperties: !1
831
+ },
832
+ support: {
833
+ type: "array",
834
+ description: "Support contact information",
835
+ items: {
836
+ type: "object",
837
+ required: [
838
+ "type",
839
+ "value"
840
+ ],
841
+ properties: {
842
+ type: {
843
+ type: "string",
844
+ description: "Type of support contact",
845
+ enum: [
846
+ "email"
847
+ ]
848
+ },
849
+ value: {
850
+ type: "string",
851
+ description: "Contact value",
852
+ minLength: 1,
853
+ maxLength: 100
854
+ }
855
+ },
856
+ additionalProperties: !1
857
+ },
858
+ minItems: 1
859
+ },
860
+ homepage: {
861
+ type: "string",
862
+ description: "Homepage URL for the plugin (http or https)",
863
+ pattern: "^https?://",
864
+ maxLength: 1e3
865
+ },
866
+ license: {
867
+ type: "string",
868
+ description: "License identifier (e.g., MIT, Apache-2.0)",
869
+ minLength: 1,
870
+ maxLength: 32
871
+ },
872
+ keywords: {
873
+ type: "array",
874
+ description: "Keywords for plugin discovery",
875
+ items: {
876
+ type: "string",
877
+ minLength: 1,
878
+ maxLength: 30
879
+ },
880
+ uniqueItems: !0
881
+ },
882
+ whatsnew: {
883
+ type: "string",
884
+ description: "What's new in this version",
885
+ minLength: 1,
886
+ maxLength: 300
887
+ },
888
+ externalHost: {
889
+ type: "string",
890
+ description: "External host URL for the plugin (https only)",
891
+ format: "uri",
892
+ pattern: "^https://",
893
+ maxLength: 1e3
894
+ },
895
+ permissions: {
896
+ type: "object",
897
+ description: "Permissions required by the plugin",
898
+ required: [
899
+ "data"
900
+ ],
901
+ properties: {
902
+ data: {
903
+ type: "array",
904
+ description: "Data access permissions",
905
+ items: {
906
+ type: "string",
907
+ enum: [
908
+ "tracker:issues:read",
909
+ "tracker:issues:write",
910
+ "tracker:issuetypes:read",
911
+ "tracker:statuses:read",
912
+ "tracker:queues:read",
913
+ "tracker:fields:read",
914
+ "tracker:entities:read",
915
+ "tracker:attachments:read",
916
+ "tracker:attachments:write",
917
+ "tracker:applications:read",
918
+ "tracker:boards:read",
919
+ "tracker:boards:write",
920
+ "tracker:bulk:read",
921
+ "tracker:bulk:write",
922
+ "tracker:bulkchange:read",
923
+ "tracker:bulkchange:write",
924
+ "tracker:charts:read",
925
+ "tracker:commentTemplates:read",
926
+ "tracker:commentTemplates:write",
927
+ "tracker:components:read",
928
+ "tracker:components:write",
929
+ "tracker:data:read",
930
+ "tracker:departments:read",
931
+ "tracker:entities:write",
932
+ "tracker:externalEventTypes:write",
933
+ "tracker:externalEvents:write",
934
+ "tracker:fields:write",
935
+ "tracker:filterFolders:write",
936
+ "tracker:filters:read",
937
+ "tracker:filters:write",
938
+ "tracker:goals:read",
939
+ "tracker:goals:write",
940
+ "tracker:groups:read",
941
+ "tracker:issueTemplates:read",
942
+ "tracker:issueTemplates:write",
943
+ "tracker:links:read",
944
+ "tracker:linktypes:read",
945
+ "tracker:liveBoards:write",
946
+ "tracker:localFields:read",
947
+ "tracker:maillists:read",
948
+ "tracker:maillists:write",
949
+ "tracker:myself:read",
950
+ "tracker:myself:write",
951
+ "tracker:priorities:read",
952
+ "tracker:queues:write",
953
+ "tracker:reminders:read",
954
+ "tracker:reminders:write",
955
+ "tracker:remotelinks:read",
956
+ "tracker:reports:read",
957
+ "tracker:reports:write",
958
+ "tracker:resolutions:read",
959
+ "tracker:resources:read",
960
+ "tracker:resources:write",
961
+ "tracker:roles:read",
962
+ "tracker:screens:read",
963
+ "tracker:services:read",
964
+ "tracker:sprints:read",
965
+ "tracker:sprints:write",
966
+ "tracker:system:write",
967
+ "tracker:tags:read",
968
+ "tracker:translations:read",
969
+ "tracker:users:read",
970
+ "tracker:users:write",
971
+ "tracker:versions:read",
972
+ "tracker:versions:write",
973
+ "tracker:workflows:read",
974
+ "tracker:workflows:write",
975
+ "tracker:worklog:read",
976
+ "tracker:worklog:write"
977
+ ]
978
+ },
979
+ uniqueItems: !0
980
+ },
981
+ ui: {
982
+ type: "array",
983
+ description: "UI permissions",
984
+ items: {
985
+ type: "string"
986
+ },
987
+ uniqueItems: !0
988
+ },
989
+ device: {
990
+ type: "array",
991
+ description: "Device permissions",
992
+ items: {
993
+ type: "string",
994
+ enum: [
995
+ "clipboard-write"
996
+ ]
997
+ },
998
+ uniqueItems: !0
999
+ },
1000
+ external: {
1001
+ type: "array",
1002
+ description: "External API domains the plugin may call through the platform proxy",
1003
+ items: {
1004
+ $ref: "#/definitions/ExternalDomain"
1005
+ },
1006
+ uniqueItems: !0
1007
+ }
1008
+ },
1009
+ additionalProperties: !1
1010
+ },
1011
+ slots: {
1012
+ type: "object",
1013
+ description: "Configuration for service slots",
1014
+ minProperties: 1,
1015
+ properties: {
1016
+ tracker: {
1017
+ type: "object",
1018
+ description: "Tracker service slots",
1019
+ minProperties: 1,
1020
+ properties: {
1021
+ "issue.action": {
1022
+ type: "array",
1023
+ description: "Issue Action slot configurations",
1024
+ minItems: 1,
1025
+ items: {
1026
+ $ref: "#/definitions/SlotConfig"
1027
+ }
1028
+ },
1029
+ "issue.block": {
1030
+ type: "array",
1031
+ description: "Issue Block slot configurations",
1032
+ minItems: 1,
1033
+ items: {
1034
+ $ref: "#/definitions/SlotConfig"
1035
+ }
1036
+ },
1037
+ "issue.tab": {
1038
+ type: "array",
1039
+ description: "Issue Tab slot configurations",
1040
+ minItems: 1,
1041
+ items: {
1042
+ $ref: "#/definitions/SlotConfig"
1043
+ }
1044
+ },
1045
+ "issue.comment.action": {
1046
+ type: "array",
1047
+ description: "Issue Comment Action slot configurations",
1048
+ minItems: 1,
1049
+ items: {
1050
+ $ref: "#/definitions/SlotConfig"
1051
+ }
1052
+ },
1053
+ navigation: {
1054
+ type: "array",
1055
+ description: "Navigation slot configurations",
1056
+ minItems: 1,
1057
+ items: {
1058
+ $ref: "#/definitions/SlotConfig"
1059
+ }
1060
+ },
1061
+ "trigger.create.action": {
1062
+ type: "array",
1063
+ description: "Trigger Create Action slot configurations",
1064
+ minItems: 1,
1065
+ items: {
1066
+ $ref: "#/definitions/SlotConfig"
1067
+ }
1068
+ },
1069
+ "trigger.edit.action": {
1070
+ type: "array",
1071
+ description: "Trigger Edit Action slot configurations",
1072
+ minItems: 1,
1073
+ items: {
1074
+ $ref: "#/definitions/SlotConfig"
1075
+ }
1076
+ },
1077
+ "project.action": {
1078
+ type: "array",
1079
+ description: "Project Action slot configurations",
1080
+ minItems: 1,
1081
+ items: {
1082
+ $ref: "#/definitions/SlotConfig"
1083
+ }
1084
+ },
1085
+ "project.block": {
1086
+ type: "array",
1087
+ description: "Project Block slot configurations",
1088
+ minItems: 1,
1089
+ items: {
1090
+ $ref: "#/definitions/SlotConfig"
1091
+ }
1092
+ },
1093
+ "project.tab": {
1094
+ type: "array",
1095
+ description: "Project Tab slot configurations",
1096
+ minItems: 1,
1097
+ items: {
1098
+ $ref: "#/definitions/SlotConfig"
1099
+ }
1100
+ },
1101
+ "portfolio.action": {
1102
+ type: "array",
1103
+ description: "Portfolio Action slot configurations",
1104
+ minItems: 1,
1105
+ items: {
1106
+ $ref: "#/definitions/SlotConfig"
1107
+ }
1108
+ },
1109
+ "portfolio.block": {
1110
+ type: "array",
1111
+ description: "Portfolio Block slot configurations",
1112
+ minItems: 1,
1113
+ items: {
1114
+ $ref: "#/definitions/SlotConfig"
1115
+ }
1116
+ },
1117
+ "portfolio.tab": {
1118
+ type: "array",
1119
+ description: "Portfolio Tab slot configurations",
1120
+ minItems: 1,
1121
+ items: {
1122
+ $ref: "#/definitions/SlotConfig"
1123
+ }
1124
+ },
1125
+ "goal.action": {
1126
+ type: "array",
1127
+ description: "Goal Action slot configurations",
1128
+ minItems: 1,
1129
+ items: {
1130
+ $ref: "#/definitions/SlotConfig"
1131
+ }
1132
+ },
1133
+ "goal.block": {
1134
+ type: "array",
1135
+ description: "Goal Block slot configurations",
1136
+ minItems: 1,
1137
+ items: {
1138
+ $ref: "#/definitions/SlotConfig"
1139
+ }
1140
+ },
1141
+ "goal.tab": {
1142
+ type: "array",
1143
+ description: "Goal Tab slot configurations",
1144
+ minItems: 1,
1145
+ items: {
1146
+ $ref: "#/definitions/SlotConfig"
1147
+ }
1148
+ },
1149
+ "attachment.viewer.action": {
1150
+ type: "array",
1151
+ description: "Attachment Viewer Action slot configurations",
1152
+ minItems: 1,
1153
+ items: {
1154
+ $ref: "#/definitions/SlotConfig"
1155
+ }
1156
+ },
1157
+ "board.tab": {
1158
+ type: "array",
1159
+ description: "Board Tab slot configurations",
1160
+ minItems: 1,
1161
+ items: {
1162
+ $ref: "#/definitions/SlotConfig"
1163
+ }
1164
+ },
1165
+ dock: {
1166
+ type: "array",
1167
+ description: "Dock slot configurations",
1168
+ minItems: 1,
1169
+ items: {
1170
+ $ref: "#/definitions/SlotConfig"
1171
+ }
1172
+ }
1173
+ },
1174
+ additionalProperties: !1
1175
+ }
1176
+ },
1177
+ additionalProperties: !1
1178
+ }
1179
+ },
1180
+ additionalProperties: !1,
1181
+ definitions: {
1182
+ ExternalDomain: {
1183
+ type: "object",
1184
+ description: "External API domain declaration with optional authorization config",
1185
+ required: [
1186
+ "domain"
1187
+ ],
1188
+ properties: {
1189
+ domain: {
1190
+ type: "string",
1191
+ description: "Hostname of the external API (no scheme, no path, lowercase)",
1192
+ pattern: "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$",
1193
+ minLength: 1,
1194
+ maxLength: 253
1195
+ },
1196
+ authorization: {
1197
+ $ref: "#/definitions/ExternalAuthorization"
1198
+ },
1199
+ instructions: {
1200
+ type: "object",
1201
+ description: "Localized note shown to the end user when they need to provide a token for this domain (e.g. where to generate the PAT)",
1202
+ required: [
1203
+ "ru",
1204
+ "en"
1205
+ ],
1206
+ properties: {
1207
+ ru: {
1208
+ type: "string",
1209
+ description: "Russian instructions",
1210
+ minLength: 1,
1211
+ maxLength: 500
1212
+ },
1213
+ en: {
1214
+ type: "string",
1215
+ description: "English instructions",
1216
+ minLength: 1,
1217
+ maxLength: 500
1218
+ }
1219
+ },
1220
+ additionalProperties: !1
1221
+ }
1222
+ },
1223
+ additionalProperties: !1
1224
+ },
1225
+ ExternalAuthorization: {
1226
+ type: "object",
1227
+ description: "Authorization config for an external API domain",
1228
+ required: [
1229
+ "type"
1230
+ ],
1231
+ properties: {
1232
+ type: {
1233
+ type: "string",
1234
+ description: "Authorization scheme: oauth (full OAuth flow or manual PAT for an OAuth provider) or token (manual non-OAuth token, e.g. API key)",
1235
+ enum: [
1236
+ "oauth",
1237
+ "token"
1238
+ ]
1239
+ },
1240
+ scopes: {
1241
+ type: "array",
1242
+ description: "Scopes required by this version of the plugin for the domain",
1243
+ items: {
1244
+ type: "string",
1245
+ minLength: 1
1246
+ },
1247
+ uniqueItems: !0
1248
+ },
1249
+ contextTypes: {
1250
+ type: "array",
1251
+ description: "Supported token storage contexts",
1252
+ items: {
1253
+ type: "string",
1254
+ enum: [
1255
+ "user",
1256
+ "organization"
1257
+ ]
1258
+ },
1259
+ minItems: 1,
1260
+ uniqueItems: !0
1261
+ },
1262
+ header: {
1263
+ type: "string",
1264
+ description: "Custom HTTP header name to put the token into (default: Authorization)",
1265
+ minLength: 1
1266
+ },
1267
+ prefix: {
1268
+ type: "string",
1269
+ description: "Custom token prefix in the Authorization header (default: Bearer; empty string for no prefix)"
1270
+ }
1271
+ },
1272
+ additionalProperties: !1
1273
+ },
1274
+ SlotConfig: {
1275
+ type: "object",
1276
+ description: "Configuration for a specific slot",
1277
+ required: [
1278
+ "entrypoint",
1279
+ "title",
1280
+ "contextLevel"
1281
+ ],
1282
+ properties: {
1283
+ entrypoint: {
1284
+ type: "string",
1285
+ description: "Entry point file path for the slot",
1286
+ minLength: 1
1287
+ },
1288
+ title: {
1289
+ type: "object",
1290
+ description: "Localized titles for the slot",
1291
+ required: [
1292
+ "ru",
1293
+ "en"
1294
+ ],
1295
+ properties: {
1296
+ ru: {
1297
+ type: "string",
1298
+ description: "Russian title",
1299
+ minLength: 1,
1300
+ maxLength: 32
1301
+ },
1302
+ en: {
1303
+ type: "string",
1304
+ description: "English title",
1305
+ minLength: 1,
1306
+ maxLength: 32
1307
+ }
1308
+ },
1309
+ additionalProperties: !1
1310
+ },
1311
+ contextLevel: {
1312
+ type: "string",
1313
+ description: "Level of context data provided to the slot",
1314
+ enum: [
1315
+ "basic",
1316
+ "full"
1317
+ ]
1318
+ },
1319
+ icon: {
1320
+ type: "object",
1321
+ description: "Optional slot icon (used by 'dock' slot for FAB)",
1322
+ required: [
1323
+ "url"
1324
+ ],
1325
+ properties: {
1326
+ url: {
1327
+ type: "string",
1328
+ description: "Relative path to the icon file (e.g. ./icon.svg)",
1329
+ minLength: 1
1330
+ }
1331
+ },
1332
+ additionalProperties: !1
1333
+ },
1334
+ description: {
1335
+ type: "object",
1336
+ description: "Localized descriptions for the slot",
1337
+ required: [
1338
+ "ru",
1339
+ "en"
1340
+ ],
1341
+ properties: {
1342
+ ru: {
1343
+ type: "string",
1344
+ description: "Russian description",
1345
+ minLength: 1,
1346
+ maxLength: 300
1347
+ },
1348
+ en: {
1349
+ type: "string",
1350
+ description: "English description",
1351
+ minLength: 1,
1352
+ maxLength: 300
1353
+ }
1354
+ },
1355
+ additionalProperties: !1
1356
+ }
1357
+ },
1358
+ additionalProperties: !1
1359
+ }
1360
+ }
1361
+ };
1362
+ }
1363
+ });
1364
+
1365
+ // src/core/manifest/manifestManager.ts
1366
+ var import_fs4, import_promises2, import_ajv, import_ajv_formats, validator, manifestPath, parseManifest, loadRaw, load2, validate, save2, update2, manifestManager, init_manifestManager = __esm({
1367
+ "src/core/manifest/manifestManager.ts"() {
1368
+ "use strict";
1369
+ import_fs4 = require("fs"), import_promises2 = require("fs/promises"), import_ajv = __toESM(require("ajv")), import_ajv_formats = __toESM(require("ajv-formats"));
1370
+ init_manifestPermissionsSchema2();
1371
+ init_formatValidationErrors();
1372
+ init_manifest_schema();
1373
+ validator = (() => {
1374
+ let schema = {
1375
+ ...manifest_schema_default,
1376
+ properties: {
1377
+ ...manifest_schema_default.properties,
1378
+ permissions: {
1379
+ ...manifest_schema_default.properties.permissions,
1380
+ properties: {
1381
+ ...manifest_schema_default.properties.permissions.properties,
1382
+ ...permissionsSchemaExtensions2
1383
+ }
1384
+ }
1385
+ }
1386
+ }, ajv = new import_ajv.default({ allErrors: !0, strict: !1 });
1387
+ return (0, import_ajv_formats.default)(ajv), ajv.compile(schema);
1388
+ })(), manifestPath = "./manifest.json", parseManifest = (content) => {
1389
+ let manifest;
1390
+ try {
1391
+ manifest = JSON.parse(content);
1392
+ } catch (error2) {
1393
+ throw error2 instanceof SyntaxError ? new Error(`File manifest.json contains invalid JSON: ${error2.message}`) : new Error(`Error reading manifest.json: ${error2.message}`);
1394
+ }
1395
+ return manifest;
1396
+ }, loadRaw = async () => {
1397
+ if (!(0, import_fs4.existsSync)(manifestPath))
1398
+ throw new Error(`File manifest.json not found at path: ${manifestPath}`);
1399
+ try {
1400
+ return await (0, import_promises2.readFile)(manifestPath, "utf8");
1401
+ } catch (error2) {
1402
+ throw error2 instanceof Error ? new Error(`Error reading manifest.json: ${error2.message}`) : new Error("Error loading manifest");
1403
+ }
1404
+ }, load2 = async () => {
1405
+ let manifestContent = await loadRaw();
1406
+ return parseManifest(manifestContent);
1407
+ }, validate = async () => {
1408
+ let manifest = await load2();
1409
+ if (!validator(manifest) && validator.errors) {
1410
+ let errorMessages2 = formatValidationErrors(validator.errors);
1411
+ throw new Error(
1412
+ `\u274C Manifest validation failed:
1413
+ ${errorMessages2}
1414
+
1415
+ \u{1F4A1} Ensure all required fields are filled according to the plugin documentation.`
1416
+ );
1417
+ }
1418
+ }, save2 = async (manifest) => {
1419
+ try {
1420
+ let content = JSON.stringify(manifest, null, 4);
1421
+ await (0, import_promises2.writeFile)(manifestPath, content, "utf8");
1422
+ } catch (error2) {
1423
+ throw error2 instanceof Error ? new Error(`Error saving manifest.json: ${error2.message}`) : new Error("Error saving manifest");
1424
+ }
1425
+ }, update2 = async (updates) => {
1426
+ let updatedManifest = { ...await load2(), ...updates };
1427
+ return await save2(updatedManifest), updatedManifest;
1428
+ }, manifestManager = {
1429
+ load: load2,
1430
+ loadRaw,
1431
+ validate,
1432
+ save: save2,
1433
+ update: update2
1434
+ };
1435
+ }
1436
+ });
1437
+
1438
+ // src/utils/marketplace.ts
1439
+ function validateMarketplaceAssets() {
1440
+ let marketplaceDir = import_path3.default.resolve(MARKETPLACE_DIR);
1441
+ ensurePathExists(
1442
+ marketplaceDir,
1443
+ "Marketplace folder not found. Create ./marketplace and add index.md and header-image.jpg before publishing."
1444
+ ), ensurePathExists(
1445
+ import_path3.default.join(marketplaceDir, MARKETPLACE_INDEX_FILE),
1446
+ "Marketplace description not found. Add ./marketplace/index.md before publishing."
1447
+ ), ensurePathExists(
1448
+ import_path3.default.join(marketplaceDir, MARKETPLACE_HEADER_IMAGE_FILE),
1449
+ "Marketplace header image not found. Add ./marketplace/header-image.jpg before publishing."
1450
+ ), ensurePathExists(
1451
+ import_path3.default.resolve(PUBLIC_DIR, PUBLIC_LOGO_FILE),
1452
+ "Plugin logo not found. Add ./public/logo.svg before publishing."
1453
+ );
1454
+ }
1455
+ function validateArchiveSources() {
1456
+ ensurePathExists(import_path3.default.resolve(DIST_DIR), "Dist folder not found. Build the project first."), ensurePathExists(
1457
+ import_path3.default.resolve(SRC_DIR),
1458
+ "Source folder not found. Add ./src before publishing."
1459
+ ), ensurePathExists(import_path3.default.resolve(MANIFEST_FILE), "manifest.json not found in plugin root."), validateMarketplaceAssets();
1460
+ }
1461
+ var import_fs5, import_path3, MARKETPLACE_DIR, MARKETPLACE_INDEX_FILE, MARKETPLACE_HEADER_IMAGE_FILE, PUBLIC_DIR, PUBLIC_LOGO_FILE, MANIFEST_FILE, DIST_DIR, SRC_DIR, ensurePathExists, validateManifestPublishingFields, ensureManifestCatalogFields, marketplacePaths, init_marketplace = __esm({
1462
+ "src/utils/marketplace.ts"() {
1463
+ "use strict";
1464
+ import_fs5 = __toESM(require("fs")), import_path3 = __toESM(require("path"));
1465
+ init_manifestManager();
1466
+ init_logger();
1467
+ 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) => {
1468
+ import_fs5.default.existsSync(targetPath) || (logger_default.error(errorMessage), process.exit(1));
1469
+ }, validateManifestPublishingFields = async () => {
1470
+ let manifest = await manifestManager.load();
1471
+ ensureManifestCatalogFields(manifest);
1472
+ }, ensureManifestCatalogFields = (manifest) => {
1473
+ (!manifest.name?.ru || !manifest.name?.en) && (logger_default.error(
1474
+ 'Manifest field "name" is required for publishing. Add localized "name.ru" and "name.en" to ./manifest.json.'
1475
+ ), process.exit(1)), (!manifest.description?.ru || !manifest.description?.en) && (logger_default.error(
1476
+ 'Manifest field "description" is required for publishing. Add localized "description.ru" and "description.en" to ./manifest.json.'
1477
+ ), process.exit(1));
1478
+ };
1479
+ marketplacePaths = {
1480
+ distDir: DIST_DIR,
1481
+ srcDir: SRC_DIR,
1482
+ marketplaceDir: MARKETPLACE_DIR,
1483
+ manifestFile: MANIFEST_FILE
1484
+ };
1485
+ }
1486
+ });
1487
+
1488
+ // src/utils/pluginPackageScripts.ts
1489
+ function readPluginPackageScripts(cwd = process.cwd()) {
1490
+ let packageJsonPath = import_path4.default.join(cwd, "package.json");
1491
+ return import_fs6.default.existsSync(packageJsonPath) ? JSON.parse(import_fs6.default.readFileSync(packageJsonPath, "utf-8")).scripts ?? {} : null;
1492
+ }
1493
+ function hasPluginScript(name, cwd = process.cwd()) {
1494
+ return !!readPluginPackageScripts(cwd)?.[name];
1495
+ }
1496
+ var import_fs6, import_path4, init_pluginPackageScripts = __esm({
1497
+ "src/utils/pluginPackageScripts.ts"() {
1498
+ "use strict";
1499
+ import_fs6 = __toESM(require("fs")), import_path4 = __toESM(require("path"));
1500
+ }
1501
+ });
1502
+
1503
+ // src/commands/submit/utils/runSubmitPrechecks.ts
1504
+ async function runSubmitPrechecks(options = {}) {
1505
+ if (options.skip) {
1506
+ logger_default.warning("Skipping pre-submit checks (--skip-checks).");
1507
+ return;
1508
+ }
1509
+ logger_default.separator(), logger_default.info("\u{1F50D} Pre-submit checks"), logger_default.separator(), await runStep("Validate manifest.json", () => manifestManager.validate()), await runStep("Check publishing metadata and assets", async () => {
1510
+ await validateManifestPublishingFields(), validateMarketplaceAssets();
1511
+ }), await runShellStep("Install dependencies", pluginCmd.install), await runShellStep("Run linter", pluginCmd.lint), hasPluginScript("typecheck") ? await runShellStep("Run typecheck", pluginCmd.typecheck) : logger_default.verbose('Skipping typecheck (no "typecheck" script in package.json).'), hasPluginScript("test") ? await runShellStep("Run tests", pluginCmd.test) : logger_default.warning(
1512
+ 'No "test" script in package.json \u2014 add tests before publishing, or run submit with --skip-checks.'
1513
+ ), await runShellStep("Check dependency vulnerabilities", pluginCmd.audit), logger_default.separator(), logger_default.success("Pre-submit checks passed"), logger_default.separator();
1514
+ }
1515
+ var import_picocolors4, stepStart, stepDone, runStep, runShellStep, init_runSubmitPrechecks = __esm({
1516
+ "src/commands/submit/utils/runSubmitPrechecks.ts"() {
1517
+ "use strict";
1518
+ import_picocolors4 = __toESM(require("picocolors"));
1519
+ init_manifestManager();
1520
+ init_execCommand();
1521
+ init_logger();
1522
+ init_marketplace();
1523
+ init_pluginPackageScripts();
1524
+ init_templateCommands();
1525
+ stepStart = (label) => {
1526
+ console.info(`${import_picocolors4.default.cyan("\u25B8")} ${label}`);
1527
+ }, stepDone = (label) => {
1528
+ console.info(`${import_picocolors4.default.green("\u2713")} ${label}`), console.info("");
1529
+ }, runStep = async (label, run) => {
1530
+ stepStart(label), await run(), stepDone(label);
1531
+ }, runShellStep = async (label, command) => {
1532
+ stepStart(label), console.info(import_picocolors4.default.dim(` $ ${command}`)), await execCommand(command), stepDone(label);
1533
+ };
1534
+ }
1535
+ });
1536
+
1537
+ // src/utils/buildArchive.ts
1538
+ async function buildArchive() {
1539
+ return validateArchiveSources(), (await manifestManager.load()).manifest_version === void 0 && (logger_default.error(
1540
+ `manifest_version is missing in manifest.json. Run "${CLI_NAME2} up" or add "manifest_version": 1 manually before uploading.`
1541
+ ), process.exit(1)), new Promise((resolve2, reject) => {
1542
+ let archive = (0, import_archiver.default)("zip", { zlib: { level: 9 } }), chunks = [];
1543
+ archive.on("data", (chunk) => chunks.push(chunk)), archive.on("end", () => {
1544
+ let buffer = Buffer.concat(chunks);
1545
+ if (logger_default.info(`\u{1F4E6} Archive created (${buffer.length} bytes)`), isVerboseEnabled()) {
1546
+ let debugPath = writeVerboseArtifact("archive/latest-upload.zip", buffer);
1547
+ logger_default.info(`[platform-api-debug] Saved archive copy to ${debugPath}`);
1548
+ }
1549
+ resolve2(buffer);
1550
+ }), archive.on("error", reject), archive.glob("**/*", {
1551
+ cwd: process.cwd(),
1552
+ ignore: ["node_modules/**", "dist/**", "**/.DS_Store"],
1553
+ dot: !0
1554
+ }), archive.file(import_path5.default.resolve(marketplacePaths.manifestFile), { name: "src/manifest.json" }), archive.glob(
1555
+ "**/*",
1556
+ {
1557
+ cwd: import_path5.default.resolve(marketplacePaths.distDir),
1558
+ ignore: ["**/.DS_Store"]
1559
+ },
1560
+ { prefix: "dist/" }
1561
+ ), archive.finalize();
1562
+ });
1563
+ }
1564
+ var import_path5, import_archiver, init_buildArchive = __esm({
1565
+ "src/utils/buildArchive.ts"() {
1566
+ "use strict";
1567
+ import_path5 = __toESM(require("path")), import_archiver = __toESM(require("archiver"));
1568
+ init_manifestManager();
1569
+ init_meta2();
1570
+ init_logger();
1571
+ init_marketplace();
1572
+ init_verbose();
1573
+ }
1574
+ });
1575
+
1576
+ // src/distributions/external/submit.ts
1577
+ async function submitExternal(options = {}) {
1578
+ await runSubmitPrechecks({ skip: options.skipChecks });
1579
+ let manifest = await manifestManager.load(), issueKey = (await pluginStateManager.load()).trackerIssueKey;
1580
+ if (issueKey)
1581
+ try {
1582
+ await getIssue(issueKey);
1583
+ } catch {
1584
+ issueKey = void 0;
1585
+ }
1586
+ let pluginId = manifest.id ?? (0, import_crypto.randomUUID)();
1587
+ manifest.id || await manifestManager.update({ id: pluginId });
1588
+ let manifestJson = await manifestManager.loadRaw();
1589
+ if (issueKey) {
1590
+ logger_default.verbose(`\u23F3 Updating issue ${issueKey} with latest manifest...`);
1591
+ let issueDescription = buildIssueDescription({
1592
+ pluginId,
1593
+ slug: manifest.slug,
1594
+ version: manifest.version,
1595
+ manifestJson
1596
+ });
1597
+ await updatePluginIssue(issueKey, { description: issueDescription });
1598
+ } else if (options.ticket === !1) {
1599
+ logger_default.warning(
1600
+ "Tracker issue is required for tracker-backed submit. Skipping ticket creation."
1601
+ );
1602
+ return;
1603
+ } else {
1604
+ logger_default.info("\u23F3 Creating plugin issue in Tracker...");
1605
+ let issue = await createPluginIssue({
1606
+ pluginId,
1607
+ slug: manifest.slug,
1608
+ version: manifest.version,
1609
+ manifestJson
1610
+ });
1611
+ await pluginStateManager.update({ trackerIssueKey: issue.key }), issueKey = issue.key, logger_default.info(` Tracker issue : ${issueKey}`);
1612
+ }
1613
+ logger_default.info("\u{1F528} Building plugin..."), await build(), logger_default.info("\u{1F4E6} Creating archive...");
1614
+ let archiveBuffer = await buildArchive(), archiveName = `${manifest.slug}-${manifest.version}.zip`;
1615
+ logger_default.verbose(`\u2B06\uFE0F Attaching ${archiveName} to ${issueKey}...`), await attachFileToIssue(issueKey, archiveBuffer, archiveName), await addIssueComment(
1616
+ issueKey,
1617
+ `Updated bundle: \`${archiveName}\` (${archiveBuffer.length} bytes)`
1618
+ ), logger_default.verbose(`\u23F3 Fetching available transitions for ${issueKey}...`);
1619
+ let transitions = await getIssueTransitions(issueKey), submitTransition = transitions.find(
1620
+ (t) => t.display?.toLowerCase().includes(SUBMIT_TRANSITION_DISPLAY) || t.id?.toLowerCase().includes("waitingforapprove") || t.id?.toLowerCase().includes("waiting")
1621
+ );
1622
+ if (!submitTransition) {
1623
+ let available = transitions.map((t) => `"${t.display ?? t.id}"`).join(", ");
1624
+ logger_default.error(
1625
+ `Could not find a "Waiting for approve" transition on ${issueKey}. Available: ${available}`
1626
+ );
1627
+ return;
1628
+ }
1629
+ logger_default.info("\u{1F680} Submitting plugin for review..."), 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}`), logger_default.newLine();
1630
+ }
1631
+ var import_crypto, SUBMIT_TRANSITION_DISPLAY, init_submit = __esm({
1632
+ "src/distributions/external/submit.ts"() {
1633
+ "use strict";
1634
+ import_crypto = require("crypto");
1635
+ init_build();
1636
+ init_runSubmitPrechecks();
1637
+ init_manifestManager();
1638
+ init_pluginStateManager();
1639
+ init_buildArchive();
1640
+ init_logger();
1641
+ init_tracker();
1642
+ SUBMIT_TRANSITION_DISPLAY = "waiting for approve";
1643
+ }
1644
+ });
1645
+
200
1646
  // src/distributions/external/registerCommands.ts
201
1647
  var registerCommands_exports = {};
202
1648
  __export(registerCommands_exports, {
203
1649
  registerDistributionCommands: () => registerDistributionCommands
204
1650
  });
205
1651
  function registerDistributionCommands(program) {
206
- registerConfigCommand(program, CLI_NAME);
1652
+ registerConfigCommand(program, CLI_NAME), program.command("login").description("save your Yandex Tracker OAuth token (request it via Tracker support)").action(withErrorHandling(loginExternal)), program.command("logout").description("remove saved OAuth token").action(
1653
+ withErrorHandling(async () => {
1654
+ logoutExternal();
1655
+ })
1656
+ ), program.command("submit").description("build plugin, create a Tracker issue in PLUGINMOD, and submit for review").addOption(skipChecksOption).action(withErrorHandling(submitExternal)), program.command("list").description("list all your plugins and their moderation status").action(withErrorHandling(listExternal)), program.command("info [issue-key]").description(
1657
+ "show moderation status of a plugin (uses .tracker-plugin issue key if not provided)"
1658
+ ).action(withErrorHandling(infoExternal));
207
1659
  }
208
1660
  var init_registerCommands = __esm({
209
1661
  "src/distributions/external/registerCommands.ts"() {
210
1662
  "use strict";
1663
+ init_options();
211
1664
  init_registerCommand();
1665
+ init_withErrorHandling();
1666
+ init_info();
1667
+ init_list();
1668
+ init_login();
212
1669
  init_meta();
1670
+ init_submit();
213
1671
  }
214
1672
  });
215
1673
 
@@ -276,7 +1734,7 @@ function getPlatformBaseUrl() {
276
1734
  return cfg.api.platformBaseUrl;
277
1735
  }
278
1736
  function getTrackerBaseUrl() {
279
- return TRACKER_BASE_URL;
1737
+ return TRACKER_BASE_URL2;
280
1738
  }
281
1739
  function getOAuthTokenUrl() {
282
1740
  let cfg = requireConfig();
@@ -287,11 +1745,11 @@ function getOAuthTokenUrl() {
287
1745
  function getUpdateCheckInfo() {
288
1746
  return null;
289
1747
  }
290
- var TRACKER_BASE_URL, init_hosts = __esm({
1748
+ var TRACKER_BASE_URL2, init_hosts = __esm({
291
1749
  "src/distributions/external/hosts.ts"() {
292
1750
  "use strict";
293
1751
  init_manager();
294
- TRACKER_BASE_URL = "https://tracker.yandex.ru";
1752
+ TRACKER_BASE_URL2 = "https://api.tracker.yandex.net/v3";
295
1753
  }
296
1754
  });
297
1755
 
@@ -299,6 +1757,7 @@ var TRACKER_BASE_URL, init_hosts = __esm({
299
1757
  var templateSubstitution_exports = {};
300
1758
  __export(templateSubstitution_exports, {
301
1759
  applySubstitutions: () => applySubstitutions,
1760
+ overlayDirName: () => overlayDirName,
302
1761
  templateDeps: () => templateDeps
303
1762
  });
304
1763
  function rewritePackageJson(content) {
@@ -306,8 +1765,6 @@ function rewritePackageJson(content) {
306
1765
  if (pkg.dependencies) {
307
1766
  let next = {};
308
1767
  for (let [name, version] of Object.entries(pkg.dependencies)) {
309
- if (PACKAGE_DROP.has(name))
310
- continue;
311
1768
  let renamed = PACKAGE_RENAME[name] ?? name;
312
1769
  next[renamed] = ADDED_DEPS[renamed] ?? version;
313
1770
  }
@@ -328,62 +1785,52 @@ function rewriteImports(content) {
328
1785
  }
329
1786
  return result;
330
1787
  }
331
- function rewriteScss(content) {
332
- return content.split(`
333
- `).filter((line) => {
334
- let trimmed = line.trim();
335
- return trimmed.startsWith("@import") ? ![...PACKAGE_DROP].some((pkg) => trimmed.includes(pkg)) : !0;
336
- }).join(`
337
- `);
338
- }
339
1788
  function rewriteNpmrc(content) {
340
1789
  return content.split(`
341
1790
  `).filter((line) => !/^registry\s*=\s*https?:\/\/npm\.yandex-team\.ru/.test(line.trim())).join(`
342
1791
  `);
343
1792
  }
344
1793
  function applySubstitutions(filePath, content) {
345
- let name = import_path2.default.basename(filePath), ext = import_path2.default.extname(filePath);
1794
+ let name = import_path6.default.basename(filePath), ext = import_path6.default.extname(filePath);
346
1795
  if (name === "package.json")
347
1796
  return Buffer.from(rewritePackageJson(content.toString("utf8")), "utf8");
348
1797
  if (name === "npmrc.template" || name === ".npmrc")
349
1798
  return Buffer.from(rewriteNpmrc(content.toString("utf8")), "utf8");
350
- if (ext === ".scss" || ext === ".css")
351
- return Buffer.from(rewriteScss(content.toString("utf8")), "utf8");
352
1799
  if ([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"].includes(ext)) {
353
- let text = content.toString("utf8"), rewritten = rewriteImports(text);
354
- if (rewritten !== text)
1800
+ let original = content.toString("utf8"), rewritten = rewriteImports(original);
1801
+ if (rewritten !== original)
355
1802
  return Buffer.from(rewritten, "utf8");
356
1803
  }
357
1804
  return content;
358
1805
  }
359
- var import_path2, PACKAGE_RENAME, PACKAGE_DROP, ADDED_DEPS, templateDeps, init_templateSubstitution = __esm({
1806
+ var import_path6, PACKAGE_RENAME, ADDED_DEPS, templateDeps, overlayDirName, init_templateSubstitution = __esm({
360
1807
  "src/distributions/external/templateSubstitution.ts"() {
361
1808
  "use strict";
362
- import_path2 = __toESM(require("path")), PACKAGE_RENAME = {
1809
+ import_path6 = __toESM(require("path")), PACKAGE_RENAME = {
363
1810
  "@yandex-data-ui/tracker-plugin-sdk-react": "@weavix/sdk-react",
364
1811
  "@yandex-data-ui/tracker-pub-api-types": "@weavix/tracker-api-types"
365
- }, PACKAGE_DROP = /* @__PURE__ */ new Set(["@yandex-data-ui/gravity-themes"]), ADDED_DEPS = {
1812
+ }, ADDED_DEPS = {
366
1813
  "@weavix/sdk-core": "latest",
367
1814
  "@weavix/sdk-react": "latest",
368
1815
  "@weavix/tracker-api-types": "latest"
369
- }, templateDeps = ["@weavix/sdk-core", "@weavix/sdk-react", "@weavix/tracker-api-types"];
1816
+ }, templateDeps = ["@weavix/sdk-core", "@weavix/sdk-react", "@weavix/tracker-api-types"], overlayDirName = "_external";
370
1817
  }
371
1818
  });
372
1819
 
373
1820
  // src/index.ts
374
- var import_commander = require("commander");
375
-
376
- // src/distribution/meta.ts
377
- var impl = (init_meta(), __toCommonJS(meta_exports)), { CLI_NAME: CLI_NAME2, CLI_DESCRIPTION: CLI_DESCRIPTION2, CLI_HELP_TEXT: CLI_HELP_TEXT2 } = impl;
1821
+ var import_commander2 = require("commander");
1822
+ init_meta2();
378
1823
 
379
1824
  // src/distribution/registerCommands.ts
380
- var impl2 = (init_registerCommands(), __toCommonJS(registerCommands_exports)), { registerDistributionCommands: registerDistributionCommands2 } = impl2;
1825
+ init_flag();
1826
+ var impl3 = (init_registerCommands(), __toCommonJS(registerCommands_exports)), { registerDistributionCommands: registerDistributionCommands2 } = impl3;
381
1827
 
382
1828
  // src/utils/checkUpdate.ts
383
- var import_node_fetch = __toESM(require("node-fetch"));
1829
+ var import_node_fetch2 = __toESM(require("node-fetch"));
384
1830
 
385
1831
  // src/distribution/hosts.ts
386
- var impl3 = (init_hosts(), __toCommonJS(hosts_exports)), {
1832
+ init_flag();
1833
+ var impl4 = (init_hosts(), __toCommonJS(hosts_exports)), {
387
1834
  getS3Endpoint: getS3Endpoint2,
388
1835
  getMdsEndpoint: getMdsEndpoint2,
389
1836
  getS3Region: getS3Region2,
@@ -393,55 +1840,48 @@ var impl3 = (init_hosts(), __toCommonJS(hosts_exports)), {
393
1840
  getTrackerBaseUrl: getTrackerBaseUrl2,
394
1841
  getOAuthTokenUrl: getOAuthTokenUrl2,
395
1842
  getUpdateCheckInfo: getUpdateCheckInfo2
396
- } = impl3;
397
-
398
- // src/utils/checkUpdate.ts
399
- init_logger();
400
- var checkUpdate = async (version) => {
401
- let info2 = getUpdateCheckInfo2();
402
- if (info2)
403
- try {
404
- let response = await (0, import_node_fetch.default)(`${info2.registryUrl}/${info2.packageName}/latest`);
405
- if (!response.ok)
406
- return;
407
- let latest = await response.json();
408
- latest.version !== version && (logger_default.newLine(), logger_default.info(
409
- `\u{1F514} Update available ${version} \u2192 ${latest.version}
410
- Run: npm i -g ${info2.packageName}@latest --registry=${info2.registryUrl}`
411
- ));
412
- } catch {
413
- }
414
- };
415
-
416
- // src/utils/execCommand.ts
417
- var import_execa = require("execa"), execCommand = async (command, cwd = process.cwd()) => {
418
- await (0, import_execa.execa)(command, {
419
- cwd,
420
- shell: !0,
421
- stdio: "inherit"
422
- });
423
- };
424
-
425
- // src/commands/build.ts
426
- init_logger();
1843
+ } = impl4;
427
1844
 
428
- // src/commands/constants/templateCommands.ts
429
- var pluginCmd = {
430
- install: "npm install",
431
- build: "npm run build",
432
- dev: "npm run dev",
433
- lint: "npm run lint"
1845
+ // src/utils/checkUpdate.ts
1846
+ init_logger();
1847
+ var SEMVER_RE = /^(\d+)\.(\d+)\.(\d+)$/, DIAGNOSTIC_FLAGS = /* @__PURE__ */ new Set(["--version", "-V", "--help", "-h", "help"]), parse = (v) => {
1848
+ let m = SEMVER_RE.exec(v);
1849
+ return m ? { major: +m[1], minor: +m[2], patch: +m[3] } : null;
1850
+ }, isDiagnosticInvocation = () => {
1851
+ let args = process.argv.slice(2);
1852
+ return args.length === 0 ? !0 : args.some((a) => DIAGNOSTIC_FLAGS.has(a));
1853
+ }, classify = (current, latest) => latest.major > current.major ? "minorOrMajor" : latest.major < current.major ? "none" : latest.minor > current.minor ? "minorOrMajor" : latest.minor < current.minor ? "none" : latest.patch > current.patch ? "patch" : "none", checkUpdate = async (version) => {
1854
+ if (version === "unknown" || isDiagnosticInvocation() || process.env.TRACKER_CLI_SKIP_UPDATE_CHECK) return;
1855
+ let info2 = getUpdateCheckInfo2();
1856
+ if (!info2) return;
1857
+ let current = parse(version);
1858
+ if (current)
1859
+ try {
1860
+ let response = await (0, import_node_fetch2.default)(`${info2.registryUrl}/${info2.packageName}/latest`);
1861
+ if (!response.ok) return;
1862
+ let json = await response.json(), latest = parse(json.version);
1863
+ if (!latest) return;
1864
+ let kind = classify(current, latest);
1865
+ if (kind === "none") return;
1866
+ let installCmd = `npm i -g ${info2.packageName}@latest --registry=${info2.registryUrl}`;
1867
+ if (kind === "minorOrMajor") {
1868
+ logger_default.newLine(), logger_default.error(
1869
+ `Update required ${version} \u2192 ${json.version}
1870
+ This release is not backward-compatible with your installed version.`
1871
+ ), logger_default.suggest(installCmd), process.exit(1);
1872
+ return;
1873
+ }
1874
+ logger_default.newLine(), logger_default.info(`\u{1F514} Update available ${version} \u2192 ${json.version}
1875
+ Run: ${installCmd}`);
1876
+ } catch {
1877
+ }
434
1878
  };
435
1879
 
436
- // src/commands/build.ts
437
- var build = async ({ environment = "production" } = {}) => {
438
- logger_default.info("\u{1F528} Building project..."), await execCommand(pluginCmd.install), await execCommand(
439
- environment ? `VITE_DEPLOY_ENV=${environment} ${pluginCmd.build}` : pluginCmd.build
440
- );
441
- };
1880
+ // src/index.ts
1881
+ init_build();
442
1882
 
443
1883
  // src/commands/create/index.ts
444
- var path8 = __toESM(require("path")), import_prompts2 = require("@inquirer/prompts");
1884
+ var path13 = __toESM(require("path")), import_prompts3 = require("@inquirer/prompts");
445
1885
 
446
1886
  // src/core/manifest/constants.ts
447
1887
  var DATA_PERMISSIONS = [
@@ -526,9 +1966,16 @@ var TEMPLATES = [
526
1966
  "navigation",
527
1967
  "trigger.action",
528
1968
  "project.action",
1969
+ "project.block",
1970
+ "project.tab",
529
1971
  "portfolio.action",
1972
+ "portfolio.block",
1973
+ "portfolio.tab",
530
1974
  "goal.action",
531
- "attachment.viewer.action"
1975
+ "goal.block",
1976
+ "goal.tab",
1977
+ "attachment.viewer.action",
1978
+ "board.tab"
532
1979
  ];
533
1980
  var TEMPLATE_SLOTS = {
534
1981
  default: [],
@@ -539,25 +1986,33 @@ var TEMPLATE_SLOTS = {
539
1986
  navigation: ["navigation"],
540
1987
  "trigger.action": ["trigger.create.action", "trigger.edit.action"],
541
1988
  "project.action": ["project.action"],
1989
+ "project.block": ["project.block"],
1990
+ "project.tab": ["project.tab"],
542
1991
  "portfolio.action": ["portfolio.action"],
1992
+ "portfolio.block": ["portfolio.block"],
1993
+ "portfolio.tab": ["portfolio.tab"],
543
1994
  "goal.action": ["goal.action"],
544
- "attachment.viewer.action": ["attachment.viewer.action"]
1995
+ "goal.block": ["goal.block"],
1996
+ "goal.tab": ["goal.tab"],
1997
+ "attachment.viewer.action": ["attachment.viewer.action"],
1998
+ "board.tab": ["board.tab"]
545
1999
  };
546
2000
 
547
2001
  // src/commands/create/index.ts
2002
+ init_meta2();
548
2003
  init_logger();
549
2004
 
550
2005
  // src/commands/create/utils/getWelcomeMessage.ts
551
- var import_picocolors2 = __toESM(require("picocolors")), getWelcomeMessage = (pwd) => `
552
- ${import_picocolors2.default.bold(import_picocolors2.default.white("\u{1F680} Create new tracker plugin"))}
2006
+ var import_picocolors5 = __toESM(require("picocolors")), getWelcomeMessage = (pwd) => `
2007
+ ${import_picocolors5.default.bold(import_picocolors5.default.white("\u{1F680} Create new tracker plugin"))}
553
2008
 
554
- ${import_picocolors2.default.dim(`\u{1F4C1} Creating an app in your current directory: ${pwd}`)}
2009
+ ${import_picocolors5.default.dim(`\u{1F4C1} Creating an app in your current directory: ${pwd}`)}
555
2010
 
556
- ${import_picocolors2.default.dim("Press")} ${import_picocolors2.default.yellow("Ctrl+C")} ${import_picocolors2.default.dim("to cancel.")}
2011
+ ${import_picocolors5.default.dim("Press")} ${import_picocolors5.default.yellow("Ctrl+C")} ${import_picocolors5.default.dim("to cancel.")}
557
2012
  `;
558
2013
 
559
2014
  // src/commands/create/utils/initManifest.ts
560
- var fs = __toESM(require("fs")), path2 = __toESM(require("path"));
2015
+ var fs5 = __toESM(require("fs")), path7 = __toESM(require("path"));
561
2016
 
562
2017
  // src/commands/create/utils/generateManifest.ts
563
2018
  function buildSlots(template, slotTitle) {
@@ -565,7 +2020,8 @@ function buildSlots(template, slotTitle) {
565
2020
  if (slotNames.length === 0) return;
566
2021
  let slotEntry = {
567
2022
  entrypoint: "index.html",
568
- title: { ru: slotTitle, en: slotTitle }
2023
+ title: { ru: slotTitle, en: slotTitle },
2024
+ contextLevel: "basic"
569
2025
  };
570
2026
  return {
571
2027
  tracker: Object.fromEntries(slotNames.map((slotName) => [slotName, [slotEntry]]))
@@ -592,20 +2048,19 @@ var generateManifest = (answers) => ({
592
2048
 
593
2049
  // src/commands/create/utils/initManifest.ts
594
2050
  var initManifest = ({ answers, targetDir }) => {
595
- let generatedManifest = generateManifest(answers), manifestPath2 = path2.join(targetDir, "manifest.json");
596
- fs.writeFileSync(manifestPath2, JSON.stringify(generatedManifest, null, 2), "utf-8");
2051
+ let generatedManifest = generateManifest(answers), manifestPath2 = path7.join(targetDir, "manifest.json");
2052
+ fs5.writeFileSync(manifestPath2, JSON.stringify(generatedManifest, null, 2), "utf-8");
597
2053
  };
598
2054
 
599
2055
  // src/commands/create/utils/initTemplate.ts
600
- var fs4 = __toESM(require("fs")), path7 = __toESM(require("path"));
601
-
602
- // src/utils/copyDirectory.ts
603
- var fs2 = __toESM(require("fs")), import_path3 = __toESM(require("path")), import_tinyglobby = require("tinyglobby");
2056
+ var fs8 = __toESM(require("fs")), path12 = __toESM(require("path"));
604
2057
 
605
2058
  // src/distribution/templateSubstitution.ts
606
- var impl4 = (init_templateSubstitution(), __toCommonJS(templateSubstitution_exports)), { applySubstitutions: applySubstitutions2, templateDeps: templateDeps2 } = impl4;
2059
+ init_flag();
2060
+ var impl5 = (init_templateSubstitution(), __toCommonJS(templateSubstitution_exports)), { applySubstitutions: applySubstitutions2, overlayDirName: overlayDirName2, templateDeps: templateDeps2 } = impl5;
607
2061
 
608
2062
  // src/utils/copyDirectory.ts
2063
+ var fs6 = __toESM(require("fs")), import_path7 = __toESM(require("path")), import_tinyglobby = require("tinyglobby");
609
2064
  var resolveTargetFileName = (file) => file.endsWith(".template") ? "." + file.replace(".template", "") : file, copyDirectory = async (sourceDir, targetDir) => {
610
2065
  let files = await (0, import_tinyglobby.glob)(["**/*"], {
611
2066
  cwd: sourceDir,
@@ -614,35 +2069,35 @@ var resolveTargetFileName = (file) => file.endsWith(".template") ? "." + file.re
614
2069
  });
615
2070
  await Promise.all(
616
2071
  files.map(async (file) => {
617
- let sourcePath = import_path3.default.join(sourceDir, file), targetFile = resolveTargetFileName(file), targetPath = import_path3.default.join(targetDir, targetFile);
618
- await fs2.promises.mkdir(import_path3.default.dirname(targetPath), { recursive: !0 });
619
- let content = await fs2.promises.readFile(sourcePath), rewritten = applySubstitutions2(file, content);
620
- await fs2.promises.writeFile(targetPath, rewritten);
2072
+ let sourcePath = import_path7.default.join(sourceDir, file), targetFile = resolveTargetFileName(file), targetPath = import_path7.default.join(targetDir, targetFile);
2073
+ await fs6.promises.mkdir(import_path7.default.dirname(targetPath), { recursive: !0 });
2074
+ let content = await fs6.promises.readFile(sourcePath), rewritten = applySubstitutions2(file, content);
2075
+ await fs6.promises.writeFile(targetPath, rewritten);
621
2076
  })
622
2077
  );
623
2078
  };
624
2079
 
625
2080
  // src/utils/getProjectPath.ts
626
- var import_path4 = __toESM(require("path")), isDevelopment = () => __dirname.includes("/src/"), getProjectPath = (relativePath) => isDevelopment() ? import_path4.default.resolve(__dirname, "..", "..", relativePath) : import_path4.default.resolve(__dirname, relativePath), getTemplatesBaseDir = () => getProjectPath("templates"), getTemplatePath = (filename) => import_path4.default.join(getTemplatesBaseDir(), "_shared", filename);
2081
+ var import_path8 = __toESM(require("path")), isDevelopment = () => __dirname.includes("/src/"), getProjectPath = (relativePath) => isDevelopment() ? import_path8.default.resolve(__dirname, "..", "..", relativePath) : import_path8.default.resolve(__dirname, relativePath), getTemplatesBaseDir = () => getProjectPath("templates"), getTemplatePath = (filename) => import_path8.default.join(getTemplatesBaseDir(), "_shared", filename);
627
2082
 
628
2083
  // src/commands/create/utils/initTemplate.ts
629
2084
  init_logger();
630
2085
 
631
2086
  // src/commands/create/utils/updatePackageJson.ts
632
- var fs3 = __toESM(require("fs")), path6 = __toESM(require("path")), updatePackageJson = (targetDir, packageSlug) => {
633
- let packageJsonPath = path6.join(targetDir, "package.json");
634
- if (fs3.existsSync(packageJsonPath)) {
635
- let packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
636
- packageJson.name = packageSlug, fs3.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 4) + `
2087
+ var fs7 = __toESM(require("fs")), path11 = __toESM(require("path")), updatePackageJson = (targetDir, packageSlug) => {
2088
+ let packageJsonPath = path11.join(targetDir, "package.json");
2089
+ if (fs7.existsSync(packageJsonPath)) {
2090
+ let packageJson = JSON.parse(fs7.readFileSync(packageJsonPath, "utf-8"));
2091
+ packageJson.name = packageSlug, fs7.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 4) + `
637
2092
  `);
638
2093
  }
639
2094
  };
640
2095
 
641
2096
  // src/commands/create/utils/initTemplate.ts
642
2097
  var initTemplate = async ({ answers, targetDir }) => {
643
- fs4.existsSync(targetDir) || fs4.mkdirSync(targetDir, { recursive: !0 });
644
- let templatesBaseDir = getTemplatesBaseDir(), templatesDir = path7.join(templatesBaseDir, answers.template), sharedDir = path7.join(templatesBaseDir, "_shared");
645
- await copyDirectory(sharedDir, targetDir), await copyDirectory(templatesDir, targetDir), updatePackageJson(targetDir, answers.packageSlug), logger_default.info("Created template with marketplace publication requirements."), logger_default.info(
2098
+ fs8.existsSync(targetDir) || fs8.mkdirSync(targetDir, { recursive: !0 });
2099
+ let templatesBaseDir = getTemplatesBaseDir(), templatesDir = path12.join(templatesBaseDir, answers.template), sharedDir = path12.join(templatesBaseDir, "_shared"), overlayDir = path12.join(templatesBaseDir, overlayDirName2);
2100
+ await copyDirectory(sharedDir, targetDir), await copyDirectory(overlayDir, targetDir), await copyDirectory(templatesDir, targetDir), updatePackageJson(targetDir, answers.packageSlug), logger_default.info("Created template with marketplace publication requirements."), logger_default.info(
646
2101
  "Before publishing, add ./marketplace/index.md, ./marketplace/header-image.jpg (784:325), and ./public/logo.svg (square)."
647
2102
  );
648
2103
  };
@@ -651,26 +2106,26 @@ var initTemplate = async ({ answers, targetDir }) => {
651
2106
  var DEFAULT_VERSION = "0.0.1";
652
2107
  async function create() {
653
2108
  logger_default.info(getWelcomeMessage(process.cwd()));
654
- let packageSlug = await (0, import_prompts2.input)({
2109
+ let packageSlug = await (0, import_prompts3.input)({
655
2110
  message: "Enter app slug (e.g., my-tracker-plugin):",
656
2111
  required: !0
657
- }), pluginName = await (0, import_prompts2.input)({
2112
+ }), pluginName = await (0, import_prompts3.input)({
658
2113
  message: "Enter plugin name:",
659
2114
  required: !0
660
- }), pluginDescription = await (0, import_prompts2.input)({
2115
+ }), pluginDescription = await (0, import_prompts3.input)({
661
2116
  message: "Enter plugin description:",
662
2117
  required: !0
663
- }), supportEmail = await (0, import_prompts2.input)({
2118
+ }), supportEmail = await (0, import_prompts3.input)({
664
2119
  message: "Enter support email:",
665
2120
  required: !0,
666
2121
  validate: (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) || "Please enter a valid email address"
667
- }), template = await (0, import_prompts2.select)({
2122
+ }), template = await (0, import_prompts3.select)({
668
2123
  message: "Select a template:",
669
2124
  choices: TEMPLATES.map((templateName) => ({
670
2125
  name: templateName,
671
2126
  value: templateName
672
2127
  }))
673
- }), dataPermissions = await (0, import_prompts2.checkbox)({
2128
+ }), dataPermissions = await (0, import_prompts3.checkbox)({
674
2129
  message: "Select data permissions (some popular options):",
675
2130
  choices: TOP_DATA_PERMISSIONS.map((permission) => ({
676
2131
  name: permission,
@@ -687,567 +2142,28 @@ async function create() {
687
2142
  data: dataPermissions
688
2143
  },
689
2144
  version: DEFAULT_VERSION
690
- }, targetDir = path8.join(process.cwd(), answers.packageSlug);
2145
+ }, targetDir = path13.join(process.cwd(), answers.packageSlug);
691
2146
  await initTemplate({
692
2147
  answers,
693
2148
  targetDir
694
2149
  }), initManifest({
695
2150
  answers,
696
2151
  targetDir
697
- }), logger_default.newLine(), logger_default.success("Package generated!"), logger_default.commands("To get started, run", [
698
- `cd ${answers.packageSlug}`,
699
- "npm install",
700
- `${CLI_NAME2} debug`
701
- ]);
2152
+ }), logger_default.newLine(), logger_default.success("\u2705 Plugin created successfully!"), logger_default.newLine(), logger_default.info("\u{1F680} To start development:"), logger_default.commands("", [`cd ${answers.packageSlug}`, "npm install", `${CLI_NAME2} debug`]), logger_default.newLine(), logger_default.info(
2153
+ "\u{1F4CC} Important: After running debug, the plugin will be available in the Tracker interface,"
2154
+ ), logger_default.info("not at localhost. Open Tracker and check the plugin in the appropriate context.");
702
2155
  }
703
2156
 
704
2157
  // src/commands/debug/index.ts
705
- var import_fs6 = __toESM(require("fs")), import_path8 = __toESM(require("path"));
706
-
707
- // src/core/manifest/manifestManager.ts
708
- var import_fs2 = require("fs"), import_promises = require("fs/promises"), import_ajv = __toESM(require("ajv")), import_ajv_formats = __toESM(require("ajv-formats"));
709
-
710
- // src/core/manifest/formatValidationErrors.ts
711
- var priorityOrder = [
712
- "required",
713
- "type",
714
- "minLength",
715
- "format",
716
- "pattern",
717
- "enum",
718
- "additionalProperties",
719
- "uniqueItems"
720
- ], errorMessages = {
721
- required: (params) => `missing required property '${params.missingProperty}'`,
722
- type: (params) => `must be ${params.type}`,
723
- enum: (params) => `must be one of [${params.allowedValues.join(", ")}]`,
724
- pattern: (params) => `must match pattern ${params.pattern}`,
725
- format: (params) => `must be a valid ${params.format}`,
726
- minLength: () => "must not be empty",
727
- additionalProperties: (params) => `unexpected property '${params.additionalProperty}'`,
728
- uniqueItems: () => "must contain unique items"
729
- }, getPriority = (keyword) => {
730
- let index = priorityOrder.indexOf(keyword);
731
- return index === -1 ? priorityOrder.length : index;
732
- }, formatValidationErrors = (errors) => {
733
- let errorsByPath = {};
734
- for (let error2 of errors) {
735
- let path13 = error2.instancePath || "root";
736
- errorsByPath[path13] || (errorsByPath[path13] = []), errorsByPath[path13].push(error2);
737
- }
738
- return Object.entries(errorsByPath).map(([path13, pathErrors]) => {
739
- let error2 = [...pathErrors].sort(
740
- (a, b) => getPriority(a.keyword) - getPriority(b.keyword)
741
- )[0], formatter = errorMessages[error2.keyword], message = formatter ? formatter(error2.params) : error2.message;
742
- return ` - ${path13}: ${message}`;
743
- }).join(`
744
- `);
745
- };
746
-
747
- // src/core/manifest/manifest.schema.json
748
- var manifest_schema_default = {
749
- $schema: "http://json-schema.org/draft-07/schema#",
750
- title: "Manifest",
751
- description: "Schema for validating plugin manifest",
752
- type: "object",
753
- required: [
754
- "slug",
755
- "version",
756
- "permissions",
757
- "name",
758
- "description",
759
- "support"
760
- ],
761
- properties: {
762
- $schema: {
763
- type: "string"
764
- },
765
- id: {
766
- type: "string",
767
- description: "Unique identifier for the plugin ()",
768
- minLength: 3,
769
- maxLength: 63,
770
- pattern: "^[a-z0-9-]+$"
771
- },
772
- manifest_version: {
773
- type: "number",
774
- description: "Manifest format version",
775
- minimum: 1
776
- },
777
- supported_services: {
778
- type: "array",
779
- description: "Supported services for this plugin",
780
- items: {
781
- type: "string",
782
- enum: [
783
- "tracker"
784
- ]
785
- },
786
- minItems: 1,
787
- uniqueItems: !0
788
- },
789
- slug: {
790
- type: "string",
791
- description: "Unique identifier for the plugin (lowercase letters, numbers, hyphen)",
792
- minLength: 3,
793
- maxLength: 63,
794
- pattern: "^[a-z0-9-]+$"
795
- },
796
- version: {
797
- type: "string",
798
- description: "Version of the plugin (semver format required)",
799
- minLength: 1,
800
- pattern: "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?(\\+[a-zA-Z0-9.-]+)?$"
801
- },
802
- name: {
803
- type: "object",
804
- description: "Localized plugin name",
805
- required: [
806
- "ru",
807
- "en"
808
- ],
809
- properties: {
810
- ru: {
811
- type: "string",
812
- description: "Russian name",
813
- minLength: 1,
814
- maxLength: 30
815
- },
816
- en: {
817
- type: "string",
818
- description: "English name",
819
- minLength: 1,
820
- maxLength: 30
821
- }
822
- },
823
- additionalProperties: !1
824
- },
825
- description: {
826
- type: "object",
827
- description: "Localized plugin description",
828
- required: [
829
- "ru",
830
- "en"
831
- ],
832
- properties: {
833
- ru: {
834
- type: "string",
835
- description: "Russian description",
836
- minLength: 1,
837
- maxLength: 255
838
- },
839
- en: {
840
- type: "string",
841
- description: "English description",
842
- minLength: 1,
843
- maxLength: 255
844
- }
845
- },
846
- additionalProperties: !1
847
- },
848
- support: {
849
- type: "array",
850
- description: "Support contact information",
851
- items: {
852
- type: "object",
853
- required: [
854
- "type",
855
- "value"
856
- ],
857
- properties: {
858
- type: {
859
- type: "string",
860
- description: "Type of support contact",
861
- enum: [
862
- "email"
863
- ]
864
- },
865
- value: {
866
- type: "string",
867
- description: "Contact value",
868
- minLength: 1,
869
- maxLength: 100
870
- }
871
- },
872
- additionalProperties: !1
873
- },
874
- minItems: 1
875
- },
876
- homepage: {
877
- type: "string",
878
- description: "Homepage URL for the plugin (http or https)",
879
- pattern: "^https?://",
880
- maxLength: 1e3
881
- },
882
- license: {
883
- type: "string",
884
- description: "License identifier (e.g., MIT, Apache-2.0)",
885
- minLength: 1,
886
- maxLength: 32
887
- },
888
- keywords: {
889
- type: "array",
890
- description: "Keywords for plugin discovery",
891
- items: {
892
- type: "string",
893
- minLength: 1,
894
- maxLength: 30
895
- },
896
- uniqueItems: !0
897
- },
898
- whatsnew: {
899
- type: "string",
900
- description: "What's new in this version",
901
- minLength: 1,
902
- maxLength: 300
903
- },
904
- externalHost: {
905
- type: "string",
906
- description: "External host URL for the plugin (https only)",
907
- format: "uri",
908
- pattern: "^https://",
909
- maxLength: 1e3
910
- },
911
- permissions: {
912
- type: "object",
913
- description: "Permissions required by the plugin",
914
- required: [
915
- "data"
916
- ],
917
- properties: {
918
- data: {
919
- type: "array",
920
- description: "Data access permissions",
921
- items: {
922
- type: "string",
923
- enum: [
924
- "tracker:issues:read",
925
- "tracker:issues:write",
926
- "tracker:issuetypes:read",
927
- "tracker:statuses:read",
928
- "tracker:queues:read",
929
- "tracker:fields:read",
930
- "tracker:entities:read",
931
- "tracker:attachments:read",
932
- "tracker:attachments:write",
933
- "tracker:applications:read",
934
- "tracker:boards:read",
935
- "tracker:boards:write",
936
- "tracker:bulk:read",
937
- "tracker:bulk:write",
938
- "tracker:bulkchange:read",
939
- "tracker:bulkchange:write",
940
- "tracker:charts:read",
941
- "tracker:commentTemplates:read",
942
- "tracker:commentTemplates:write",
943
- "tracker:components:read",
944
- "tracker:components:write",
945
- "tracker:data:read",
946
- "tracker:departments:read",
947
- "tracker:entities:write",
948
- "tracker:externalEventTypes:write",
949
- "tracker:externalEvents:write",
950
- "tracker:fields:write",
951
- "tracker:filterFolders:write",
952
- "tracker:filters:read",
953
- "tracker:filters:write",
954
- "tracker:goals:read",
955
- "tracker:goals:write",
956
- "tracker:groups:read",
957
- "tracker:issueTemplates:read",
958
- "tracker:issueTemplates:write",
959
- "tracker:links:read",
960
- "tracker:linktypes:read",
961
- "tracker:liveBoards:write",
962
- "tracker:localFields:read",
963
- "tracker:maillists:read",
964
- "tracker:maillists:write",
965
- "tracker:myself:read",
966
- "tracker:myself:write",
967
- "tracker:priorities:read",
968
- "tracker:queues:write",
969
- "tracker:reminders:read",
970
- "tracker:reminders:write",
971
- "tracker:remotelinks:read",
972
- "tracker:reports:read",
973
- "tracker:reports:write",
974
- "tracker:resolutions:read",
975
- "tracker:resources:read",
976
- "tracker:resources:write",
977
- "tracker:roles:read",
978
- "tracker:screens:read",
979
- "tracker:services:read",
980
- "tracker:sprints:read",
981
- "tracker:sprints:write",
982
- "tracker:system:write",
983
- "tracker:tags:read",
984
- "tracker:translations:read",
985
- "tracker:users:read",
986
- "tracker:users:write",
987
- "tracker:versions:read",
988
- "tracker:versions:write",
989
- "tracker:workflows:read",
990
- "tracker:workflows:write",
991
- "tracker:worklog:read",
992
- "tracker:worklog:write"
993
- ]
994
- },
995
- uniqueItems: !0
996
- },
997
- ui: {
998
- type: "array",
999
- description: "UI permissions",
1000
- items: {
1001
- type: "string"
1002
- },
1003
- uniqueItems: !0
1004
- },
1005
- device: {
1006
- type: "array",
1007
- description: "Device permissions",
1008
- items: {
1009
- type: "string",
1010
- enum: [
1011
- "clipboard-write"
1012
- ]
1013
- },
1014
- uniqueItems: !0
1015
- },
1016
- external: {
1017
- type: "array",
1018
- description: "External permissions",
1019
- items: {
1020
- type: "string"
1021
- },
1022
- uniqueItems: !0
1023
- }
1024
- },
1025
- additionalProperties: !1
1026
- },
1027
- slots: {
1028
- type: "object",
1029
- description: "Configuration for service slots",
1030
- minProperties: 1,
1031
- properties: {
1032
- tracker: {
1033
- type: "object",
1034
- description: "Tracker service slots",
1035
- minProperties: 1,
1036
- properties: {
1037
- "issue.action": {
1038
- type: "array",
1039
- description: "Issue Action slot configurations",
1040
- minItems: 1,
1041
- items: {
1042
- $ref: "#/definitions/SlotConfig"
1043
- }
1044
- },
1045
- "issue.block": {
1046
- type: "array",
1047
- description: "Issue Block slot configurations",
1048
- minItems: 1,
1049
- items: {
1050
- $ref: "#/definitions/SlotConfig"
1051
- }
1052
- },
1053
- "issue.tab": {
1054
- type: "array",
1055
- description: "Issue Tab slot configurations",
1056
- minItems: 1,
1057
- items: {
1058
- $ref: "#/definitions/SlotConfig"
1059
- }
1060
- },
1061
- "issue.comment.action": {
1062
- type: "array",
1063
- description: "Issue Comment Action slot configurations",
1064
- minItems: 1,
1065
- items: {
1066
- $ref: "#/definitions/SlotConfig"
1067
- }
1068
- },
1069
- navigation: {
1070
- type: "array",
1071
- description: "Navigation slot configurations",
1072
- minItems: 1,
1073
- items: {
1074
- $ref: "#/definitions/SlotConfig"
1075
- }
1076
- },
1077
- "trigger.create.action": {
1078
- type: "array",
1079
- description: "Trigger Create Action slot configurations",
1080
- minItems: 1,
1081
- items: {
1082
- $ref: "#/definitions/SlotConfig"
1083
- }
1084
- },
1085
- "trigger.edit.action": {
1086
- type: "array",
1087
- description: "Trigger Edit Action slot configurations",
1088
- minItems: 1,
1089
- items: {
1090
- $ref: "#/definitions/SlotConfig"
1091
- }
1092
- },
1093
- "project.action": {
1094
- type: "array",
1095
- description: "Project Action slot configurations",
1096
- minItems: 1,
1097
- items: {
1098
- $ref: "#/definitions/SlotConfig"
1099
- }
1100
- },
1101
- "portfolio.action": {
1102
- type: "array",
1103
- description: "Portfolio Action slot configurations",
1104
- minItems: 1,
1105
- items: {
1106
- $ref: "#/definitions/SlotConfig"
1107
- }
1108
- },
1109
- "goal.action": {
1110
- type: "array",
1111
- description: "Goal Action slot configurations",
1112
- minItems: 1,
1113
- items: {
1114
- $ref: "#/definitions/SlotConfig"
1115
- }
1116
- },
1117
- "attachment.viewer.action": {
1118
- type: "array",
1119
- description: "Attachment Viewer Action slot configurations",
1120
- minItems: 1,
1121
- items: {
1122
- $ref: "#/definitions/SlotConfig"
1123
- }
1124
- }
1125
- },
1126
- additionalProperties: !1
1127
- }
1128
- },
1129
- additionalProperties: !1
1130
- }
1131
- },
1132
- additionalProperties: !1,
1133
- definitions: {
1134
- SlotConfig: {
1135
- type: "object",
1136
- description: "Configuration for a specific slot",
1137
- required: [
1138
- "entrypoint",
1139
- "title"
1140
- ],
1141
- properties: {
1142
- entrypoint: {
1143
- type: "string",
1144
- description: "Entry point file path for the slot",
1145
- minLength: 1
1146
- },
1147
- title: {
1148
- type: "object",
1149
- description: "Localized titles for the slot",
1150
- required: [
1151
- "ru",
1152
- "en"
1153
- ],
1154
- properties: {
1155
- ru: {
1156
- type: "string",
1157
- description: "Russian title",
1158
- minLength: 1,
1159
- maxLength: 32
1160
- },
1161
- en: {
1162
- type: "string",
1163
- description: "English title",
1164
- minLength: 1,
1165
- maxLength: 32
1166
- }
1167
- },
1168
- additionalProperties: !1
1169
- },
1170
- description: {
1171
- type: "object",
1172
- description: "Localized descriptions for the slot",
1173
- required: [
1174
- "ru",
1175
- "en"
1176
- ],
1177
- properties: {
1178
- ru: {
1179
- type: "string",
1180
- description: "Russian description",
1181
- minLength: 1,
1182
- maxLength: 300
1183
- },
1184
- en: {
1185
- type: "string",
1186
- description: "English description",
1187
- minLength: 1,
1188
- maxLength: 300
1189
- }
1190
- },
1191
- additionalProperties: !1
1192
- }
1193
- },
1194
- additionalProperties: !1
1195
- }
1196
- }
1197
- };
1198
-
1199
- // src/core/manifest/manifestManager.ts
1200
- var validator = (() => {
1201
- let ajv = new import_ajv.default({ allErrors: !0, strict: !1 });
1202
- return (0, import_ajv_formats.default)(ajv), ajv.compile(manifest_schema_default);
1203
- })(), manifestPath = "./manifest.json", parseManifest = (content) => {
1204
- let manifest;
1205
- try {
1206
- manifest = JSON.parse(content);
1207
- } catch (error2) {
1208
- throw error2 instanceof SyntaxError ? new Error(`File manifest.json contains invalid JSON: ${error2.message}`) : new Error(`Error reading manifest.json: ${error2.message}`);
1209
- }
1210
- return manifest;
1211
- }, loadRaw = async () => {
1212
- if (!(0, import_fs2.existsSync)(manifestPath))
1213
- throw new Error(`File manifest.json not found at path: ${manifestPath}`);
1214
- try {
1215
- return await (0, import_promises.readFile)(manifestPath, "utf8");
1216
- } catch (error2) {
1217
- throw error2 instanceof Error ? new Error(`Error reading manifest.json: ${error2.message}`) : new Error("Error loading manifest");
1218
- }
1219
- }, load = async () => {
1220
- let manifestContent = await loadRaw();
1221
- return parseManifest(manifestContent);
1222
- }, validate = async () => {
1223
- let manifest = await load();
1224
- if (!validator(manifest) && validator.errors) {
1225
- let errorMessages2 = formatValidationErrors(validator.errors);
1226
- throw new Error(`Manifest validation failed:
1227
- ${errorMessages2}`);
1228
- }
1229
- }, save = async (manifest) => {
1230
- try {
1231
- let content = JSON.stringify(manifest, null, 4);
1232
- await (0, import_promises.writeFile)(manifestPath, content, "utf8");
1233
- } catch (error2) {
1234
- throw error2 instanceof Error ? new Error(`Error saving manifest.json: ${error2.message}`) : new Error("Error saving manifest");
1235
- }
1236
- }, update = async (updates) => {
1237
- let updatedManifest = { ...await load(), ...updates };
1238
- return await save(updatedManifest), updatedManifest;
1239
- }, manifestManager = {
1240
- load,
1241
- loadRaw,
1242
- validate,
1243
- save,
1244
- update
1245
- };
2158
+ var import_fs10 = __toESM(require("fs")), import_path12 = __toESM(require("path"));
2159
+ init_manifestManager();
1246
2160
 
1247
2161
  // src/core/s3config/constants.ts
1248
2162
  var CONFIG_FILE_NAME = "config.json";
1249
2163
 
1250
2164
  // src/commands/debug/index.ts
2165
+ init_meta2();
2166
+ init_execCommand();
1251
2167
  init_logger();
1252
2168
 
1253
2169
  // src/utils/registerCleanup.ts
@@ -1259,8 +2175,12 @@ var registerCleanup = (cleanup) => {
1259
2175
  });
1260
2176
  };
1261
2177
 
2178
+ // src/commands/debug/index.ts
2179
+ init_templateCommands();
2180
+
1262
2181
  // src/commands/debug/utils/createDebugConfig.ts
1263
- var import_fs3 = __toESM(require("fs")), import_path5 = __toESM(require("path"));
2182
+ var import_fs7 = __toESM(require("fs")), import_path9 = __toESM(require("path"));
2183
+ init_manifestManager();
1264
2184
 
1265
2185
  // src/utils/convertManifestToConfig.ts
1266
2186
  function buildPluginDownloadUrl(env, id, version) {
@@ -1289,6 +2209,7 @@ var convertManifestToConfig = (manifest, environment) => {
1289
2209
  description: slotConfig.description,
1290
2210
  entrypoint: slotConfig.entrypoint,
1291
2211
  title: slotConfig.title,
2212
+ contextLevel: slotConfig.contextLevel,
1292
2213
  downloadUrl: buildPluginDownloadUrl(
1293
2214
  environment,
1294
2215
  manifest.slug,
@@ -1305,21 +2226,21 @@ var convertManifestToConfig = (manifest, environment) => {
1305
2226
 
1306
2227
  // src/commands/debug/utils/createDebugConfig.ts
1307
2228
  var createDebugConfig = async () => {
1308
- let manifest = await manifestManager.load(), config = convertManifestToConfig(manifest, "debug"), configPath = import_path5.default.join(process.cwd(), CONFIG_FILE_NAME);
1309
- import_fs3.default.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
2229
+ let manifest = await manifestManager.load(), config = convertManifestToConfig(manifest, "debug"), configPath = import_path9.default.join(process.cwd(), CONFIG_FILE_NAME);
2230
+ import_fs7.default.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
1310
2231
  };
1311
2232
 
1312
2233
  // src/commands/debug/utils/lockFile.ts
1313
- var import_fs4 = __toESM(require("fs")), import_path6 = __toESM(require("path")), LOCK_FILE_NAME = ".tracker-cli-debug.lock", getLockFilePath = () => import_path6.default.join(process.cwd(), LOCK_FILE_NAME), getRunningDebugPid = () => {
2234
+ var import_fs8 = __toESM(require("fs")), import_path10 = __toESM(require("path")), LOCK_FILE_NAME = ".tracker-cli-debug.lock", getLockFilePath = () => import_path10.default.join(process.cwd(), LOCK_FILE_NAME), getRunningDebugPid = () => {
1314
2235
  let lockPath = getLockFilePath();
1315
- if (!import_fs4.default.existsSync(lockPath))
2236
+ if (!import_fs8.default.existsSync(lockPath))
1316
2237
  return null;
1317
2238
  try {
1318
- let pid = JSON.parse(import_fs4.default.readFileSync(lockPath, "utf-8")).pid;
2239
+ let pid = JSON.parse(import_fs8.default.readFileSync(lockPath, "utf-8")).pid;
1319
2240
  return process.kill(pid, 0), pid;
1320
2241
  } catch {
1321
2242
  try {
1322
- import_fs4.default.unlinkSync(lockPath);
2243
+ import_fs8.default.unlinkSync(lockPath);
1323
2244
  } catch {
1324
2245
  }
1325
2246
  return null;
@@ -1327,18 +2248,19 @@ var import_fs4 = __toESM(require("fs")), import_path6 = __toESM(require("path"))
1327
2248
  }, createLockFile = () => {
1328
2249
  let lockPath = getLockFilePath(), lockData = {
1329
2250
  pid: process.pid
1330
- }, fd = import_fs4.default.openSync(lockPath, "wx");
1331
- import_fs4.default.writeSync(fd, JSON.stringify(lockData, null, 2)), import_fs4.default.closeSync(fd);
2251
+ }, fd = import_fs8.default.openSync(lockPath, "wx");
2252
+ import_fs8.default.writeSync(fd, JSON.stringify(lockData, null, 2)), import_fs8.default.closeSync(fd);
1332
2253
  }, removeLockFile = () => {
1333
2254
  let lockPath = getLockFilePath();
1334
- import_fs4.default.existsSync(lockPath) && import_fs4.default.unlinkSync(lockPath);
2255
+ import_fs8.default.existsSync(lockPath) && import_fs8.default.unlinkSync(lockPath);
1335
2256
  };
1336
2257
 
1337
2258
  // src/commands/debug/utils/watchManifest.ts
1338
- var import_fs5 = __toESM(require("fs")), import_path7 = __toESM(require("path"));
2259
+ var import_fs9 = __toESM(require("fs")), import_path11 = __toESM(require("path"));
2260
+ init_manifestManager();
1339
2261
  init_logger();
1340
2262
  var watchManifest = () => {
1341
- let manifestPath2 = import_path7.default.join(process.cwd(), "manifest.json"), debounceTimer = null, watcher = import_fs5.default.watch(manifestPath2, async (eventType) => {
2263
+ let manifestPath2 = import_path11.default.join(process.cwd(), "manifest.json"), debounceTimer = null, watcher = import_fs9.default.watch(manifestPath2, async (eventType) => {
1342
2264
  eventType === "change" && (debounceTimer && clearTimeout(debounceTimer), debounceTimer = setTimeout(async () => {
1343
2265
  try {
1344
2266
  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");
@@ -1362,53 +2284,71 @@ Please stop the existing instance before starting a new one.
1362
2284
  If you lost the terminal tab, you can kill the process with:
1363
2285
  kill ${runningPid}`
1364
2286
  ), process.exit(1));
1365
- let configPath = import_path8.default.join(process.cwd(), CONFIG_FILE_NAME);
2287
+ let configPath = import_path12.default.join(process.cwd(), CONFIG_FILE_NAME);
1366
2288
  options.lint && await manifestManager.validate(), await createDebugConfig();
1367
2289
  let watcher = watchManifest(), cleanup = () => {
1368
- watcher.close(), import_fs6.default.existsSync(configPath) && import_fs6.default.unlinkSync(configPath), removeLockFile();
2290
+ watcher.close(), import_fs10.default.existsSync(configPath) && import_fs10.default.unlinkSync(configPath), removeLockFile();
1369
2291
  };
1370
- registerCleanup(cleanup), createLockFile(), await execCommand(pluginCmd.dev), cleanup();
2292
+ registerCleanup(cleanup), createLockFile(), logger_default.newLine(), logger_default.info("\u{1F527} Debug mode started!"), logger_default.newLine(), logger_default.info("\u{1F4CC} The plugin is now available in the Tracker interface."), logger_default.info("Open Tracker and check the plugin functionality in the appropriate context."), logger_default.newLine(), logger_default.info("\u26A0\uFE0F Do not try to open localhost in the browser - the plugin works"), logger_default.info("only inside Tracker through a special loading mechanism."), logger_default.newLine(), logger_default.info("\u{1F504} Code changes will be automatically reloaded."), logger_default.info("Press Ctrl+C to stop."), logger_default.newLine(), await execCommand(pluginCmd.dev), cleanup();
1371
2293
  }
1372
2294
 
1373
2295
  // src/commands/lint.ts
2296
+ init_manifestManager();
2297
+ init_execCommand();
1374
2298
  init_logger();
2299
+ init_templateCommands();
1375
2300
  async function lint() {
1376
2301
  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);
1377
2302
  }
1378
2303
 
1379
2304
  // src/commands/up/utils/copyTemplateFiles.ts
1380
- var import_fs7 = require("fs"), import_promises2 = require("fs/promises");
2305
+ var import_fs11 = require("fs"), import_promises3 = require("fs/promises");
1381
2306
  var copyTemplateFiles = async (filenames) => {
1382
2307
  await Promise.all(
1383
2308
  filenames.map(async (filename) => {
1384
2309
  let templatePath = getTemplatePath(filename), targetPath = `./${filename}`;
1385
- if ((0, import_fs7.existsSync)(templatePath) && (0, import_fs7.existsSync)(targetPath)) {
1386
- let content = await (0, import_promises2.readFile)(templatePath), rewritten = applySubstitutions2(filename, content);
1387
- await (0, import_promises2.writeFile)(targetPath, rewritten);
2310
+ if ((0, import_fs11.existsSync)(templatePath) && (0, import_fs11.existsSync)(targetPath)) {
2311
+ let content = await (0, import_promises3.readFile)(templatePath), rewritten = applySubstitutions2(filename, content);
2312
+ await (0, import_promises3.writeFile)(targetPath, rewritten);
1388
2313
  }
1389
2314
  })
1390
2315
  );
1391
2316
  };
1392
2317
 
1393
2318
  // src/commands/up/utils/updateManifestCompatibility.ts
2319
+ init_manifestManager();
2320
+ function addDefaultContextLevel(slots) {
2321
+ if (!slots)
2322
+ return;
2323
+ let updatedSlots = {}, updates = [];
2324
+ for (let [service, serviceSlots] of Object.entries(slots))
2325
+ if (serviceSlots) {
2326
+ updatedSlots[service] = {};
2327
+ for (let [slot, slotConfigs] of Object.entries(serviceSlots))
2328
+ slotConfigs && (updatedSlots[service][slot] = slotConfigs.map((slotConfig) => "contextLevel" in slotConfig ? slotConfig : (updates.push(slotConfig), Object.assign({}, slotConfig, { contextLevel: "basic" }))));
2329
+ }
2330
+ return updates.length > 0 ? updatedSlots : void 0;
2331
+ }
1394
2332
  async function updateManifestCompatibility() {
1395
2333
  let manifest = await manifestManager.load(), updates = {};
1396
- "manifest_version" in manifest || (updates.manifest_version = 1), "supported_services" in manifest || (updates.supported_services = ["tracker"]), Object.keys(updates).length > 0 && await manifestManager.update(updates);
2334
+ "manifest_version" in manifest || (updates.manifest_version = 1), "supported_services" in manifest || (updates.supported_services = ["tracker"]);
2335
+ let updatedSlots = addDefaultContextLevel(manifest.slots);
2336
+ updatedSlots && (updates.slots = updatedSlots), Object.keys(updates).length > 0 && await manifestManager.update(updates);
1397
2337
  }
1398
2338
 
1399
2339
  // src/commands/up/utils/updatePackageDependencies.ts
1400
- var import_fs8 = require("fs"), import_promises3 = require("fs/promises");
2340
+ var import_fs12 = require("fs"), import_promises4 = require("fs/promises");
1401
2341
  var updatePackageDependencies = async (dependencies) => {
1402
2342
  let packageJsonPath = "./package.json", templatePackageJsonPath = getTemplatePath("package.json");
1403
- if (!(0, import_fs8.existsSync)(packageJsonPath) || !(0, import_fs8.existsSync)(templatePackageJsonPath))
2343
+ if (!(0, import_fs12.existsSync)(packageJsonPath) || !(0, import_fs12.existsSync)(templatePackageJsonPath))
1404
2344
  return;
1405
- let packageJsonContent = await (0, import_promises3.readFile)(packageJsonPath, "utf-8"), templatePackageJsonRaw = await (0, import_promises3.readFile)(templatePackageJsonPath), templatePackageJsonContent = applySubstitutions2(
2345
+ let packageJsonContent = await (0, import_promises4.readFile)(packageJsonPath, "utf-8"), templatePackageJsonRaw = await (0, import_promises4.readFile)(templatePackageJsonPath), templatePackageJsonContent = applySubstitutions2(
1406
2346
  "package.json",
1407
2347
  templatePackageJsonRaw
1408
2348
  ).toString("utf8"), packageJson = JSON.parse(packageJsonContent), templatePackageJson = JSON.parse(templatePackageJsonContent), updated = !1;
1409
2349
  dependencies.forEach((dep) => {
1410
2350
  packageJson.dependencies?.[dep] && templatePackageJson.dependencies?.[dep] && packageJson.dependencies[dep] !== templatePackageJson.dependencies[dep] && (packageJson.dependencies[dep] = templatePackageJson.dependencies[dep], updated = !0);
1411
- }), updated && await (0, import_promises3.writeFile)(packageJsonPath, JSON.stringify(packageJson, null, 4) + `
2351
+ }), updated && await (0, import_promises4.writeFile)(packageJsonPath, JSON.stringify(packageJson, null, 4) + `
1412
2352
  `, "utf-8");
1413
2353
  };
1414
2354
 
@@ -1419,34 +2359,25 @@ async function up() {
1419
2359
  }
1420
2360
 
1421
2361
  // src/utils/getVersion.ts
1422
- var import_fs9 = require("fs"), import_path9 = require("path"), UNKNOWN_VERSION = "unknown", getVersionFromPackageJson = () => {
1423
- try {
1424
- let packagePath = (0, import_path9.resolve)(__dirname, "../../package.json");
1425
- return (0, import_fs9.existsSync)(packagePath) && JSON.parse((0, import_fs9.readFileSync)(packagePath, "utf-8")).version || null;
1426
- } catch {
1427
- return null;
2362
+ var import_fs13 = require("fs"), import_path13 = require("path"), UNKNOWN_VERSION = "unknown", CANDIDATES = ["..", "../.."], findVersionInPackageJson = (startDir) => {
2363
+ for (let rel of CANDIDATES) {
2364
+ let path18 = (0, import_path13.resolve)(startDir, rel, "package.json");
2365
+ if ((0, import_fs13.existsSync)(path18))
2366
+ try {
2367
+ let pkg = JSON.parse((0, import_fs13.readFileSync)(path18, "utf-8"));
2368
+ if (typeof pkg.version == "string") return pkg.version;
2369
+ } catch {
2370
+ }
1428
2371
  }
1429
- }, getVersion = () => "0.4.0";
2372
+ return null;
2373
+ }, getVersion = () => findVersionInPackageJson(__dirname) ?? UNKNOWN_VERSION;
1430
2374
 
1431
2375
  // src/index.ts
1432
2376
  init_verbose();
1433
-
1434
- // src/utils/withErrorHandling.ts
1435
- init_logger();
1436
- function withErrorHandling(fn) {
1437
- return async (...args) => {
1438
- try {
1439
- await fn(...args);
1440
- } catch (error2) {
1441
- error2 instanceof Error && error2.name === "ExitPromptError" && process.exit(0), logger_default.error(error2), process.exit(1);
1442
- }
1443
- };
1444
- }
1445
-
1446
- // src/index.ts
2377
+ init_withErrorHandling();
1447
2378
  async function main() {
1448
- let program = new import_commander.Command(), version = getVersion();
1449
- await checkUpdate(version), program.name(CLI_NAME2).description(CLI_DESCRIPTION2).version(version), CLI_HELP_TEXT2 && program.addHelpText("before", CLI_HELP_TEXT2), program.hook("preAction", (thisCommand) => {
2379
+ let program = new import_commander2.Command(), version = getVersion();
2380
+ await checkUpdate(version), program.name(CLI_NAME2).description(CLI_DESCRIPTION2).version(version).option("--verbose", "enable verbose output"), CLI_HELP_TEXT2 && program.addHelpText("before", CLI_HELP_TEXT2), program.hook("preAction", (thisCommand) => {
1450
2381
  setVerboseEnabled(!!thisCommand.opts().verbose);
1451
2382
  }), program.command("create").description("create your app").action(withErrorHandling(create)), program.command("up").description("update plugin from old template to latest version").action(withErrorHandling(up)), program.command("build").description("build your app").action(withErrorHandling(build)), program.command("debug").description(
1452
2383
  "start a tunnel to connect your local code with the app running in the development environment"