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