@weavix/cli 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +2 -1
  2. package/build/index.js +2404 -1050
  3. package/build/templates/_external/npmrc.template +1 -0
  4. package/build/templates/_external/src/styles.scss +14 -15
  5. package/build/templates/_internal/npmrc.template +3 -0
  6. package/build/templates/_internal/src/styles.scss +32 -12
  7. package/build/templates/_shared/AGENTS.md +53 -0
  8. package/build/templates/_shared/manifest.schema.json +72 -2
  9. package/build/templates/_shared/package.json +4 -5
  10. package/build/templates/_shared/proxy.ts +111 -0
  11. package/build/templates/_shared/src/main.tsx +1 -1
  12. package/build/templates/_shared/vite.config.ts +3 -1
  13. package/build/templates/attachment.viewer.action/src/App.tsx +1 -5
  14. package/build/templates/board.tab/src/App.tsx +1 -1
  15. package/build/templates/default/src/App.tsx +1 -1
  16. package/build/templates/goal.action/src/App.tsx +2 -2
  17. package/build/templates/goal.block/src/App.tsx +2 -2
  18. package/build/templates/goal.editor.action/index.html +14 -0
  19. package/build/templates/goal.editor.action/src/App.tsx +56 -0
  20. package/build/templates/goal.tab/src/App.tsx +2 -2
  21. package/build/templates/issue.action/src/App.tsx +4 -2
  22. package/build/templates/issue.block/src/App.tsx +2 -2
  23. package/build/templates/issue.comment.action/src/App.tsx +3 -3
  24. package/build/templates/issue.editor.action/index.html +14 -0
  25. package/build/templates/issue.editor.action/src/App.tsx +56 -0
  26. package/build/templates/issue.tab/src/App.tsx +4 -2
  27. package/build/templates/navigation/src/App.tsx +2 -7
  28. package/build/templates/portfolio.action/src/App.tsx +2 -2
  29. package/build/templates/portfolio.block/src/App.tsx +2 -2
  30. package/build/templates/portfolio.editor.action/index.html +14 -0
  31. package/build/templates/portfolio.editor.action/src/App.tsx +56 -0
  32. package/build/templates/portfolio.tab/src/App.tsx +2 -2
  33. package/build/templates/project.action/src/App.tsx +2 -2
  34. package/build/templates/project.block/src/App.tsx +2 -2
  35. package/build/templates/project.editor.action/index.html +14 -0
  36. package/build/templates/project.editor.action/src/App.tsx +56 -0
  37. package/build/templates/project.tab/src/App.tsx +2 -2
  38. package/build/templates/queue.action/index.html +14 -0
  39. package/build/templates/queue.action/src/App.tsx +29 -0
  40. package/build/templates/queue.tab/index.html +14 -0
  41. package/build/templates/queue.tab/src/App.tsx +29 -0
  42. package/build/templates/trigger.action/src/App.tsx +15 -21
  43. package/package.json +2 -1
  44. package/build/templates/_shared/npmrc.template +0 -2
package/build/index.js CHANGED
@@ -38,101 +38,22 @@ var meta_exports = {};
38
38
  __export(meta_exports, {
39
39
  CLI_DESCRIPTION: () => CLI_DESCRIPTION,
40
40
  CLI_HELP_TEXT: () => CLI_HELP_TEXT,
41
- CLI_NAME: () => CLI_NAME
41
+ CLI_NAME: () => CLI_NAME,
42
+ CREATE_SERVICES: () => CREATE_SERVICES
42
43
  });
43
- var CLI_NAME, CLI_DESCRIPTION, CLI_HELP_TEXT, init_meta = __esm({
44
+ var CLI_NAME, CLI_DESCRIPTION, CLI_HELP_TEXT, CREATE_SERVICES, init_meta = __esm({
44
45
  "src/distributions/external/meta.ts"() {
45
46
  "use strict";
46
- CLI_NAME = "weavix", CLI_DESCRIPTION = "Weavix CLI", CLI_HELP_TEXT = "";
47
+ CLI_NAME = "weavix", CLI_DESCRIPTION = "Weavix CLI", CLI_HELP_TEXT = "", CREATE_SERVICES = ["tracker"];
47
48
  }
48
49
  });
49
50
 
50
51
  // src/distribution/meta.ts
51
- var impl, CLI_NAME2, CLI_DESCRIPTION2, CLI_HELP_TEXT2, init_meta2 = __esm({
52
+ var impl, CLI_NAME2, CLI_DESCRIPTION2, CLI_HELP_TEXT2, CREATE_SERVICES2, init_meta2 = __esm({
52
53
  "src/distribution/meta.ts"() {
53
54
  "use strict";
54
55
  init_flag();
55
- impl = (init_meta(), __toCommonJS(meta_exports)), { CLI_NAME: CLI_NAME2, CLI_DESCRIPTION: CLI_DESCRIPTION2, CLI_HELP_TEXT: CLI_HELP_TEXT2 } = impl;
56
- }
57
- });
58
-
59
- // src/commands/submit/options.ts
60
- var import_commander, skipChecksOption, init_options = __esm({
61
- "src/commands/submit/options.ts"() {
62
- "use strict";
63
- import_commander = require("commander"), skipChecksOption = new import_commander.Option(
64
- "--skip-checks",
65
- "skip pre-submit validation (manifest, assets, lint, typecheck, tests, audit)"
66
- );
67
- }
68
- });
69
-
70
- // src/utils/verbose.ts
71
- function setVerboseEnabled(value) {
72
- verboseEnabled = value;
73
- }
74
- function isVerboseEnabled() {
75
- return verboseEnabled;
76
- }
77
- function writeVerboseArtifact(relativePath, content) {
78
- let targetPath = import_path.default.resolve(".tracker-cli-debug", relativePath);
79
- return import_fs.default.mkdirSync(import_path.default.dirname(targetPath), { recursive: !0 }), import_fs.default.writeFileSync(targetPath, content), targetPath;
80
- }
81
- var import_fs, import_path, verboseEnabled, init_verbose = __esm({
82
- "src/utils/verbose.ts"() {
83
- "use strict";
84
- import_fs = __toESM(require("fs")), import_path = __toESM(require("path")), verboseEnabled = !1;
85
- }
86
- });
87
-
88
- // src/utils/logger.ts
89
- function success(message) {
90
- console.info(import_picocolors.default.green(`\u2705 ${message}`)), newLine();
91
- }
92
- function error(messageOrErr, err) {
93
- let message = messageOrErr instanceof Error ? messageOrErr.message : messageOrErr;
94
- console.error(import_picocolors.default.red(`\u274C ${message}`)), err instanceof Error && console.error(import_picocolors.default.red(err.message)), newLine();
95
- }
96
- function warning(message) {
97
- console.warn(import_picocolors.default.yellow(`\u26A0\uFE0F ${message}`)), newLine();
98
- }
99
- function info(message) {
100
- console.info(message), newLine();
101
- }
102
- function verbose(message) {
103
- isVerboseEnabled() && (console.info(import_picocolors.default.dim(message)), newLine());
104
- }
105
- function suggest(command) {
106
- console.info(`Run: ${command}`), newLine();
107
- }
108
- function newLine(count = 1) {
109
- console.info(`
110
- `.repeat(count - 1));
111
- }
112
- function separator(char = "\u2500", length = 60) {
113
- console.info(import_picocolors.default.dim(char.repeat(length))), newLine();
114
- }
115
- function commands(title, data) {
116
- newLine(), console.info(import_picocolors.default.bold(import_picocolors.default.cyan(`${title}:`))), newLine(), data.forEach((cmd) => {
117
- console.info(import_picocolors.default.dim(" $ ") + import_picocolors.default.white(cmd));
118
- }), newLine();
119
- }
120
- var import_picocolors, logger, logger_default, init_logger = __esm({
121
- "src/utils/logger.ts"() {
122
- "use strict";
123
- import_picocolors = __toESM(require("picocolors"));
124
- init_verbose();
125
- logger = {
126
- success,
127
- error,
128
- warning,
129
- info,
130
- verbose,
131
- suggest,
132
- newLine,
133
- separator,
134
- commands
135
- }, logger_default = logger;
56
+ impl = (init_meta(), __toCommonJS(meta_exports)), { CLI_NAME: CLI_NAME2, CLI_DESCRIPTION: CLI_DESCRIPTION2, CLI_HELP_TEXT: CLI_HELP_TEXT2, CREATE_SERVICES: CREATE_SERVICES2 } = impl;
136
57
  }
137
58
  });
138
59
 
@@ -143,274 +64,292 @@ function getConfigPath() {
143
64
  function readConfig() {
144
65
  if (cached !== void 0)
145
66
  return cached;
146
- if (!(0, import_fs2.existsSync)(CONFIG_FILE))
67
+ if (!(0, import_fs.existsSync)(CONFIG_FILE))
147
68
  return cached = null, cached;
148
69
  try {
149
- cached = JSON.parse((0, import_fs2.readFileSync)(CONFIG_FILE, "utf-8"));
70
+ cached = JSON.parse((0, import_fs.readFileSync)(CONFIG_FILE, "utf-8"));
150
71
  } catch {
151
72
  cached = null;
152
73
  }
153
74
  return cached;
154
75
  }
155
76
  function writeConfig(config) {
156
- (0, import_fs2.existsSync)(CONFIG_DIR) || (0, import_fs2.mkdirSync)(CONFIG_DIR, { recursive: !0, mode: 448 }), (0, import_fs2.writeFileSync)(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 384 }), cached = config;
77
+ (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;
157
78
  }
158
79
  function clearConfig() {
159
- (0, import_fs2.existsSync)(CONFIG_FILE) && (0, import_fs2.rmSync)(CONFIG_FILE), cached = null;
80
+ (0, import_fs.existsSync)(CONFIG_FILE) && (0, import_fs.rmSync)(CONFIG_FILE), cached = null;
160
81
  }
161
- var import_fs2, os, import_path2, CONFIG_DIR, CONFIG_FILE, cached, init_manager = __esm({
82
+ var import_fs, os, import_path, CONFIG_DIR, CONFIG_FILE, cached, init_manager = __esm({
162
83
  "src/core/cliConfig/manager.ts"() {
163
84
  "use strict";
164
- import_fs2 = require("fs"), os = __toESM(require("os")), import_path2 = __toESM(require("path")), CONFIG_DIR = import_path2.default.join(os.homedir(), ".tracker-cli"), CONFIG_FILE = import_path2.default.join(CONFIG_DIR, "config.json");
85
+ import_fs = require("fs"), os = __toESM(require("os")), import_path = __toESM(require("path")), CONFIG_DIR = import_path.default.join(os.homedir(), ".yaweavix"), CONFIG_FILE = import_path.default.join(CONFIG_DIR, "config.json");
165
86
  }
166
87
  });
167
88
 
168
- // src/core/cliConfig/registerCommand.ts
169
- async function promptString(message, current) {
170
- return (await (0, import_prompts.input)({
171
- message: current ? `${message} (current: ${current})` : `${message} (optional)`,
172
- default: current,
173
- required: !1
174
- }))?.trim() || void 0;
175
- }
176
- async function runConfigSet(cliName) {
177
- let existing = readConfig() ?? {};
178
- logger_default.info(
179
- "Configure CLI overrides. Empty input clears the value (and falls back to defaults where applicable)."
180
- );
181
- 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(
182
- "Production bucket (static)",
183
- existing.buckets?.production?.static
184
- ), productionConfig = await promptString(
185
- "Production bucket (config)",
186
- existing.buckets?.production?.config
187
- ), pluginDownloadProduction = await promptString(
188
- "Plugin download base URL",
189
- existing.pluginDownloadBase?.production
190
- ), platformBaseUrl = await promptString(
191
- "Platform API base URL",
192
- existing.api?.platformBaseUrl
193
- ), oauthUrl = await promptString("OAuth token URL", existing.auth?.oauthUrl);
194
- writeConfig({
195
- s3: { endpoint: s3Endpoint, region: s3Region },
196
- mds: { endpoint: mdsEndpoint },
197
- buckets: {
198
- production: { static: productionStatic, config: productionConfig }
199
- },
200
- pluginDownloadBase: { production: pluginDownloadProduction },
201
- api: { platformBaseUrl },
202
- auth: { oauthUrl }
203
- }), logger_default.success(`Configuration saved \u2192 ${getConfigPath()}`), logger_default.info(`Inspect with "${cliName} config show" or revert with "${cliName} config clear".`);
204
- }
205
- function runConfigShow(cliName) {
206
- let cfg = readConfig();
207
- if (!cfg) {
208
- logger_default.info(
209
- `No configuration found at ${getConfigPath()}. Run "${cliName} config set" to create one.`
210
- );
211
- return;
212
- }
213
- logger_default.info(`Configuration at ${getConfigPath()}:`), logger_default.info(JSON.stringify(cfg, null, 2));
214
- }
215
- function runConfigClear() {
216
- clearConfig(), logger_default.success(`Configuration removed (${getConfigPath()})`);
217
- }
218
- function registerConfigCommand(program, cliName) {
219
- let config = program.command("config").description("manage CLI configuration");
220
- 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);
89
+ // src/core/doctor/policy.ts
90
+ function createDoctorPolicy(options) {
91
+ let publish = !!options.publish, publishOnlyStatus = publish ? "fail" : "warn";
92
+ return {
93
+ mode: publish ? "publish" : "debug",
94
+ marketplaceAssetsStatus: publishOnlyStatus,
95
+ manifestPermissionsStatus: publishOnlyStatus,
96
+ manifestSupportStatus: publishOnlyStatus,
97
+ distMissingStatus: publishOnlyStatus,
98
+ authMissingStatus: publishOnlyStatus
99
+ };
221
100
  }
222
- var import_prompts, init_registerCommand = __esm({
223
- "src/core/cliConfig/registerCommand.ts"() {
101
+ var init_policy = __esm({
102
+ "src/core/doctor/policy.ts"() {
224
103
  "use strict";
225
- import_prompts = require("@inquirer/prompts");
226
- init_logger();
227
- init_manager();
228
104
  }
229
105
  });
230
106
 
231
- // src/utils/withErrorHandling.ts
232
- function withErrorHandling(fn) {
233
- return async (...args) => {
234
- try {
235
- await fn(...args);
236
- } catch (error2) {
237
- error2 instanceof Error && error2.name === "ExitPromptError" && process.exit(0), logger_default.error(error2), process.exit(1);
238
- }
107
+ // src/core/doctor/report.ts
108
+ function createDoctorReport() {
109
+ return {
110
+ ok: !1,
111
+ summary: {
112
+ passed: 0,
113
+ warnings: 0,
114
+ failures: 0
115
+ },
116
+ checks: []
239
117
  };
240
118
  }
241
- var init_withErrorHandling = __esm({
242
- "src/utils/withErrorHandling.ts"() {
119
+ function addCheck(report, check) {
120
+ report.checks.push({
121
+ ...check,
122
+ status: check.status || "pass"
123
+ });
124
+ }
125
+ function updateSummary(report) {
126
+ let passed = report.checks.filter((check) => check.status === "pass").length, warnings = report.checks.filter((check) => check.status === "warn").length, failures = report.checks.filter((check) => check.status === "fail").length;
127
+ report.summary = {
128
+ passed,
129
+ warnings,
130
+ failures
131
+ }, report.ok = failures === 0;
132
+ }
133
+ function statusBadge(status) {
134
+ let display = STATUS_DISPLAY[status];
135
+ return `${display.icon} [${display.label}]`;
136
+ }
137
+ function formatReport(report) {
138
+ let lines = ["Tracker Plugin Doctor", ""];
139
+ report.distribution && lines.push(`Distribution: ${report.distribution}`), report.mode && lines.push(`Mode: ${report.mode}`), report.projectRoot && lines.push(`Project root: ${report.projectRoot}`), report.manifestPath && lines.push(`Manifest path: ${report.manifestPath}`), report.manifest && lines.push(`Manifest: ${report.manifest.slug}@${report.manifest.version}`), report.packageManager && lines.push(`Package manager: ${report.packageManager}`), lines.push("", "Checks:");
140
+ for (let check of report.checks)
141
+ lines.push(` ${statusBadge(check.status)} ${check.title}: ${check.message}`), check.action && lines.push(` Action: ${check.action}`);
142
+ return lines.push(
143
+ "",
144
+ `Summary: \u2713 ${report.summary.passed} passed, \u26A0 ${report.summary.warnings} warning(s), \u2717 ${report.summary.failures} failure(s).`
145
+ ), lines.push(
146
+ report.ok ? report.summary.warnings > 0 ? "\u26A0 Doctor finished with warnings." : "\u2713 Doctor finished successfully." : report.mode === "publish" ? "\u2717 Doctor failed. Fix failed checks before publishing." : "\u2717 Doctor failed. Fix failed checks before local debug or build."
147
+ ), `${lines.join(`
148
+ `)}
149
+ `;
150
+ }
151
+ function writeStdout(content) {
152
+ return new Promise((resolve2, reject) => {
153
+ process.stdout.write(content, (error2) => {
154
+ if (error2) {
155
+ reject(error2);
156
+ return;
157
+ }
158
+ resolve2();
159
+ });
160
+ });
161
+ }
162
+ async function finishDoctor(report, options) {
163
+ updateSummary(report), await writeStdout(options.json ? `${JSON.stringify(report, null, 4)}
164
+ ` : formatReport(report)), report.ok || (process.exitCode = 1);
165
+ }
166
+ var STATUS_DISPLAY, init_report = __esm({
167
+ "src/core/doctor/report.ts"() {
243
168
  "use strict";
244
- init_logger();
169
+ STATUS_DISPLAY = {
170
+ pass: { icon: "\u2713", label: "PASS" },
171
+ warn: { icon: "\u26A0", label: "WARN" },
172
+ fail: { icon: "\u2717", label: "FAIL" }
173
+ };
245
174
  }
246
175
  });
247
176
 
248
- // src/core/pluginState/pluginStateManager.ts
249
- var import_fs3, import_promises, STATE_FILE, load, save, update, pluginStateManager, init_pluginStateManager = __esm({
250
- "src/core/pluginState/pluginStateManager.ts"() {
177
+ // src/core/auth/keyringAuthStorage.ts
178
+ var fs, import_keyring, parseAuthData, readLegacyAuthData, removeLegacyAuthData, createKeyringAuthStorage, init_keyringAuthStorage = __esm({
179
+ "src/core/auth/keyringAuthStorage.ts"() {
251
180
  "use strict";
252
- import_fs3 = require("fs"), import_promises = require("fs/promises"), STATE_FILE = ".tracker-plugin", load = async () => {
253
- if (!(0, import_fs3.existsSync)(STATE_FILE))
254
- return {};
181
+ fs = __toESM(require("fs")), import_keyring = require("@napi-rs/keyring"), parseAuthData = (value) => !value || typeof value != "object" || !("token" in value) || typeof value.token != "string" || !value.token ? null : {
182
+ token: value.token
183
+ }, readLegacyAuthData = (legacyAuthFile) => {
255
184
  try {
256
- let content = await (0, import_promises.readFile)(STATE_FILE, "utf8");
257
- return JSON.parse(content);
185
+ if (!fs.existsSync(legacyAuthFile))
186
+ return null;
187
+ let data = fs.readFileSync(legacyAuthFile, "utf-8");
188
+ return parseAuthData(JSON.parse(data));
258
189
  } catch {
259
- return {};
190
+ return null;
260
191
  }
261
- }, save = async (state) => {
192
+ }, removeLegacyAuthData = (legacyAuthFile) => {
262
193
  try {
263
- let content = JSON.stringify(state, null, 4);
264
- await (0, import_promises.writeFile)(STATE_FILE, content, "utf8");
265
- } catch (error2) {
266
- throw error2 instanceof Error ? new Error(`Error saving ${STATE_FILE}: ${error2.message}`) : new Error(`Error saving ${STATE_FILE}`);
267
- }
268
- }, update = async (updates) => {
269
- let updated = { ...await load(), ...updates };
270
- return await save(updated), updated;
271
- }, pluginStateManager = {
272
- load,
273
- save,
274
- update
275
- };
276
- }
277
- });
278
-
279
- // src/api/utils.ts
280
- function getIssueStatusLabel(issue) {
281
- let { key: statusKey, display: statusDisplay } = issue.status;
282
- return statusKey === "closed" && issue.resolution?.display ? issue.resolution.display : statusDisplay ?? statusKey;
283
- }
284
- function getIssueStatusCategory(issue) {
285
- let statusKey = issue.status.key, resolutionKey = issue.resolution?.key;
286
- if (statusKey === "closed")
287
- return resolutionKey === "agreed" ? "approved" : resolutionKey === "rejected" || resolutionKey === "declined" ? "rejected" : "neutral";
288
- switch (statusKey) {
289
- case "waitingForApprove":
290
- case "inProgress":
291
- return "pending";
292
- case "resultAcceptance":
293
- return "acceptance";
294
- case "testing":
295
- return "testing";
296
- case "need_info":
297
- return "need_info";
298
- default:
299
- return "neutral";
300
- }
301
- }
302
- var init_utils = __esm({
303
- "src/api/utils.ts"() {
304
- "use strict";
305
- }
306
- });
307
-
308
- // src/utils/pluginDisplay.ts
309
- function showTrackerPluginList(issues) {
310
- if (!issues || issues.length === 0) {
311
- console.info(import_picocolors2.default.dim(" No plugins found")), logger_default.newLine();
312
- return;
313
- }
314
- printHeader(`\u{1F4CB} Your Plugins \xB7 ${issues.length}`), logger_default.newLine(), issues.forEach((issue) => {
315
- let slugMatch = issue.summary.match(/^Plugin:\s*(.+)$/), slug = slugMatch ? import_picocolors2.default.magenta(slugMatch[1].trim()) : import_picocolors2.default.dim(issue.summary), statusBadge = getTrackerIssueBadge(issue);
316
- console.info(
317
- ` ${slug} ${import_picocolors2.default.dim("\xB7")} ${statusBadge} ${import_picocolors2.default.dim("\xB7")} ${import_picocolors2.default.dim(issue.key)}`
318
- ), logger_default.newLine();
319
- });
320
- }
321
- function showTrackerPluginInfo(issue) {
322
- printHeader("\u{1F4E6} Plugin"), logger_default.newLine(), printField("Issue key", import_picocolors2.default.cyan(issue.key)), printField("Status", getTrackerIssueBadge(issue)), printField("Summary", import_picocolors2.default.white(issue.summary)), issue.createdAt && printCreated(issue.createdAt), issue.updatedAt && printUpdated(issue.updatedAt);
323
- }
324
- var import_picocolors2, printHeader, getTrackerIssueBadge, formatDate, printField, printCreated, printUpdated, init_pluginDisplay = __esm({
325
- "src/utils/pluginDisplay.ts"() {
326
- "use strict";
327
- import_picocolors2 = __toESM(require("picocolors"));
328
- init_utils();
329
- init_logger();
330
- printHeader = (title) => {
331
- console.info(import_picocolors2.default.bold(import_picocolors2.default.white(title)));
332
- }, getTrackerIssueBadge = (issue) => {
333
- let label = getIssueStatusLabel(issue);
334
- switch (getIssueStatusCategory(issue)) {
335
- case "approved":
336
- return import_picocolors2.default.black(import_picocolors2.default.bgGreen(` ${label} `));
337
- case "rejected":
338
- return import_picocolors2.default.white(import_picocolors2.default.bgRed(` ${label} `));
339
- case "pending":
340
- return import_picocolors2.default.black(import_picocolors2.default.bgYellow(` ${label} `));
341
- case "acceptance":
342
- return import_picocolors2.default.black(import_picocolors2.default.bgCyan(` ${label} `));
343
- case "testing":
344
- return import_picocolors2.default.black(import_picocolors2.default.bgMagenta(` ${label} `));
345
- case "need_info":
346
- return import_picocolors2.default.black(import_picocolors2.default.bgBlue(` ${label} `));
347
- default:
348
- return import_picocolors2.default.black(import_picocolors2.default.bgWhite(` ${label} `));
194
+ fs.existsSync(legacyAuthFile) && fs.unlinkSync(legacyAuthFile);
195
+ } catch {
349
196
  }
350
- }, formatDate = (dateString) => dateString ? new Date(dateString).toLocaleString("ru-RU", {
351
- year: "numeric",
352
- month: "2-digit",
353
- day: "2-digit",
354
- hour: "2-digit",
355
- minute: "2-digit"
356
- }) : "-", printField = (label, value, minWidth = 12) => {
357
- console.info(` ${import_picocolors2.default.dim(label.padEnd(minWidth))} ${value}`);
358
- }, printCreated = (createdAt) => {
359
- printField("Created", import_picocolors2.default.white(formatDate(createdAt)));
360
- }, printUpdated = (updatedAt) => {
361
- printField("Updated", import_picocolors2.default.white(formatDate(updatedAt)));
197
+ }, createKeyringAuthStorage = ({
198
+ service,
199
+ account,
200
+ legacyAuthFile
201
+ }) => {
202
+ let createEntry = () => new import_keyring.Entry(service, account);
203
+ return {
204
+ getData: () => {
205
+ try {
206
+ let token = createEntry().getPassword();
207
+ if (token)
208
+ return { token };
209
+ } catch {
210
+ return null;
211
+ }
212
+ let legacyAuthData = readLegacyAuthData(legacyAuthFile);
213
+ if (!legacyAuthData)
214
+ return null;
215
+ try {
216
+ createEntry().setPassword(legacyAuthData.token), removeLegacyAuthData(legacyAuthFile);
217
+ } catch {
218
+ return null;
219
+ }
220
+ return legacyAuthData;
221
+ },
222
+ saveAuthData: (token) => {
223
+ createEntry().setPassword(token), removeLegacyAuthData(legacyAuthFile);
224
+ },
225
+ removeAuthData: () => {
226
+ try {
227
+ createEntry().deletePassword();
228
+ } catch {
229
+ }
230
+ removeLegacyAuthData(legacyAuthFile);
231
+ }
232
+ };
362
233
  };
363
234
  }
364
235
  });
365
236
 
366
237
  // src/distributions/external/authManager.ts
367
- var fs2, os2, path3, authDir, authFile, getData, getToken, saveAuthData, removeAuthData, externalAuthManager, init_authManager = __esm({
238
+ var os2, path2, authFile, authStorage, getToken, externalAuthManager, init_authManager = __esm({
368
239
  "src/distributions/external/authManager.ts"() {
369
240
  "use strict";
370
- fs2 = __toESM(require("fs")), os2 = __toESM(require("os")), path3 = __toESM(require("path")), authDir = path3.join(os2.homedir(), ".weavix"), authFile = path3.join(authDir, "auth.json"), getData = () => {
371
- try {
372
- if (!fs2.existsSync(authFile))
373
- return null;
374
- let data = fs2.readFileSync(authFile, "utf-8");
375
- return JSON.parse(data);
376
- } catch {
377
- return null;
378
- }
379
- }, getToken = () => getData()?.token ?? null, saveAuthData = (token) => {
380
- let authData = { token };
381
- fs2.existsSync(authDir) || fs2.mkdirSync(authDir, { recursive: !0, mode: 448 }), fs2.writeFileSync(authFile, JSON.stringify(authData, null, 2), {
382
- mode: 384
383
- });
384
- }, removeAuthData = () => {
385
- fs2.existsSync(authFile) && fs2.unlinkSync(authFile);
386
- }, externalAuthManager = {
241
+ os2 = __toESM(require("os")), path2 = __toESM(require("path"));
242
+ init_keyringAuthStorage();
243
+ authFile = path2.join(os2.homedir(), ".weavix", "auth.json"), authStorage = createKeyringAuthStorage({
244
+ service: "weavix",
245
+ account: "oauth-token",
246
+ legacyAuthFile: authFile
247
+ }), getToken = () => authStorage.getData()?.token ?? null, externalAuthManager = {
387
248
  get token() {
388
249
  return getToken();
389
250
  },
390
251
  get data() {
391
- return getData();
252
+ return authStorage.getData();
392
253
  },
393
- saveAuthData,
394
- removeAuthData
254
+ saveAuthData: authStorage.saveAuthData,
255
+ removeAuthData: authStorage.removeAuthData
395
256
  };
396
257
  }
397
258
  });
398
259
 
399
- // src/distributions/external/trackerApiRequest.ts
400
- function buildQueryString(queryParams) {
401
- if (!queryParams || Object.keys(queryParams).length === 0)
402
- return "";
403
- let params = new URLSearchParams();
404
- return Object.entries(queryParams).forEach(([key, value]) => {
405
- params.append(key, String(value));
406
- }), `?${params.toString()}`;
260
+ // src/distributions/external/hosts.ts
261
+ var hosts_exports = {};
262
+ __export(hosts_exports, {
263
+ getBuckets: () => getBuckets,
264
+ getMdsEndpoint: () => getMdsEndpoint,
265
+ getOAuthTokenUrl: () => getOAuthTokenUrl,
266
+ getPlatformApiPrefix: () => getPlatformApiPrefix,
267
+ getPlatformBaseUrl: () => getPlatformBaseUrl,
268
+ getPluginDownloadBase: () => getPluginDownloadBase,
269
+ getS3Endpoint: () => getS3Endpoint,
270
+ getS3Region: () => getS3Region,
271
+ getTrackerBaseUrl: () => getTrackerBaseUrl,
272
+ getUpdateCheckInfo: () => getUpdateCheckInfo
273
+ });
274
+ function requireConfig() {
275
+ let cfg = readConfig();
276
+ if (!cfg)
277
+ throw new Error('CLI is not configured. Run "weavix config set" to configure.');
278
+ return cfg;
407
279
  }
408
- async function parseResponse(response) {
409
- return response.status === 204 || response.headers.get("content-length") === "0" ? void 0 : response.headers.get("content-type")?.includes("application/json") ? await response.json() : await response.text();
280
+ function getS3Endpoint() {
281
+ let cfg = requireConfig();
282
+ if (!cfg.s3?.endpoint)
283
+ throw new Error('S3 endpoint is not configured. Run "weavix config set" to configure.');
284
+ return cfg.s3.endpoint;
410
285
  }
411
- async function externalTrackerApiRequest(endpoint, options = {}) {
412
- let { method = "GET", body, headers = {}, formData, queryParams } = options, token = externalAuthManager.token;
413
- if (!token)
286
+ function getMdsEndpoint() {
287
+ let cfg = requireConfig();
288
+ if (!cfg.mds?.endpoint)
289
+ throw new Error('MDS endpoint is not configured. Run "weavix config set" to configure.');
290
+ return cfg.mds.endpoint;
291
+ }
292
+ function getS3Region() {
293
+ let cfg = requireConfig();
294
+ if (!cfg.s3?.region)
295
+ throw new Error('S3 region is not configured. Run "weavix config set" to configure.');
296
+ return cfg.s3.region;
297
+ }
298
+ function getBuckets() {
299
+ let production = requireConfig().buckets?.production;
300
+ if (!production?.static || !production?.config)
301
+ throw new Error('S3 buckets are not configured. Run "weavix config set" to configure.');
302
+ let prod = { static: production.static, config: production.config };
303
+ return { testing: prod, production: prod };
304
+ }
305
+ function getPluginDownloadBase(env) {
306
+ if (env === "debug")
307
+ return "http://localhost:5173/plugins-debug";
308
+ let base = requireConfig().pluginDownloadBase?.production;
309
+ if (!base)
310
+ throw new Error(
311
+ 'Plugin download base is not configured. Run "weavix config set" to configure.'
312
+ );
313
+ return base;
314
+ }
315
+ function getPlatformBaseUrl() {
316
+ return readConfig()?.api?.platformBaseUrl ?? PLATFORM_BASE_URL;
317
+ }
318
+ function getPlatformApiPrefix() {
319
+ return "/api/cli/v1";
320
+ }
321
+ function getTrackerBaseUrl() {
322
+ return TRACKER_BASE_URL;
323
+ }
324
+ function getOAuthTokenUrl() {
325
+ return readConfig()?.auth?.oauthUrl ?? OAUTH_TOKEN_URL;
326
+ }
327
+ function getUpdateCheckInfo() {
328
+ return null;
329
+ }
330
+ var TRACKER_BASE_URL, PLATFORM_BASE_URL, OAUTH_TOKEN_URL, init_hosts = __esm({
331
+ "src/distributions/external/hosts.ts"() {
332
+ "use strict";
333
+ init_manager();
334
+ TRACKER_BASE_URL = "https://api.tracker.yandex.net/v3", PLATFORM_BASE_URL = "https://plugins-platform.b.tracker.yandex.net", OAUTH_TOKEN_URL = "https://oauth.yandex.ru/authorize?response_type=token&client_id=f57901dffe3849cbb3dbb5f616158e28";
335
+ }
336
+ });
337
+
338
+ // src/distributions/external/trackerApiRequest.ts
339
+ function buildQueryString(queryParams) {
340
+ if (!queryParams || Object.keys(queryParams).length === 0)
341
+ return "";
342
+ let params = new URLSearchParams();
343
+ return Object.entries(queryParams).forEach(([key, value]) => {
344
+ params.append(key, String(value));
345
+ }), `?${params.toString()}`;
346
+ }
347
+ async function parseResponse(response) {
348
+ 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();
349
+ }
350
+ async function externalTrackerApiRequest(endpoint, options = {}) {
351
+ let { method = "GET", body, headers = {}, formData, queryParams } = options, token = externalAuthManager.token;
352
+ if (!token)
414
353
  throw new Error(`Not authenticated. Run "${CLI_NAME} login" first.`);
415
354
  let requestHeaders = {
416
355
  Authorization: `OAuth ${token}`,
@@ -422,7 +361,7 @@ async function externalTrackerApiRequest(endpoint, options = {}) {
422
361
  let formHeaders = formData.getHeaders?.();
423
362
  Object.assign(requestHeaders, formHeaders), requestBody = formData;
424
363
  } else body && method !== "GET" && (requestHeaders["Content-Type"] = "application/json", requestBody = JSON.stringify(body));
425
- let queryString = buildQueryString(queryParams), url = `${TRACKER_BASE_URL}${endpoint}${queryString}`, response = await (0, import_node_fetch.default)(url, {
364
+ let queryString = buildQueryString(queryParams), url = `${TRACKER_BASE_URL2}${endpoint}${queryString}`, response = await (0, import_node_fetch.default)(url, {
426
365
  method,
427
366
  headers: requestHeaders,
428
367
  body: requestBody
@@ -438,227 +377,433 @@ async function externalTrackerApiRequest(endpoint, options = {}) {
438
377
  }
439
378
  return parseResponse(response);
440
379
  }
441
- var import_node_fetch, TRACKER_BASE_URL, ORG_ID, init_trackerApiRequest = __esm({
380
+ var import_node_fetch, TRACKER_BASE_URL2, ORG_ID, init_trackerApiRequest = __esm({
442
381
  "src/distributions/external/trackerApiRequest.ts"() {
443
382
  "use strict";
444
383
  import_node_fetch = __toESM(require("node-fetch"));
445
384
  init_authManager();
446
385
  init_meta();
447
- TRACKER_BASE_URL = "https://api.tracker.yandex.net/v3", ORG_ID = "8470884";
386
+ TRACKER_BASE_URL2 = "https://api.tracker.yandex.net/v3", ORG_ID = "8470884";
448
387
  }
449
388
  });
450
389
 
451
- // src/distributions/external/tracker.ts
452
- function buildIssueSummary(slug) {
453
- return `Plugin: ${slug}`;
454
- }
455
- function buildIssueDescription(params) {
456
- let { pluginId, slug, version, manifestJson } = params;
457
- return [
458
- `**Plugin UUID:** ${pluginId}`,
459
- `**Slug:** ${slug}`,
460
- `**Version:** ${version}`,
461
- "",
462
- "**Manifest:**",
463
- "```json",
464
- manifestJson,
465
- "```"
466
- ].join(`
467
- `);
468
- }
469
- async function createPluginIssue(params) {
470
- let { slug, pluginId, version, manifestJson } = params, body = {
471
- queue: PLUGINMOD_QUEUE,
472
- summary: buildIssueSummary(slug),
473
- description: buildIssueDescription({ pluginId, slug, version, manifestJson }),
474
- tags: ["tracker-plugin"]
475
- };
476
- return externalTrackerApiRequest("/issues", {
477
- method: "POST",
478
- body
479
- });
480
- }
481
- async function updatePluginIssue(issueKey, params) {
482
- return externalTrackerApiRequest(`/issues/${issueKey}`, {
483
- method: "PATCH",
484
- body: params
485
- });
486
- }
487
- async function attachFileToIssue(issueKey, fileBuffer, fileName) {
488
- let formData = new import_form_data.default();
489
- return formData.append("file", fileBuffer, {
490
- filename: fileName,
491
- contentType: "application/zip"
492
- }), externalTrackerApiRequest(`/issues/${issueKey}/attachments`, {
493
- method: "POST",
494
- formData
495
- });
496
- }
497
- async function getIssueTransitions(issueKey) {
498
- return externalTrackerApiRequest(`/issues/${issueKey}/transitions`, {
499
- method: "GET"
500
- });
501
- }
502
- async function executeIssueTransition(issueKey, transitionId) {
503
- await externalTrackerApiRequest(
504
- `/issues/${issueKey}/transitions/${transitionId}/_execute`,
505
- {
506
- method: "POST",
507
- body: {}
390
+ // src/distributions/external/doctorChecks.ts
391
+ var doctorChecks_exports = {};
392
+ __export(doctorChecks_exports, {
393
+ checkDistribution: () => checkDistribution
394
+ });
395
+ function checkCliConfig(report) {
396
+ let config = readConfig(), configPath = getConfigPath();
397
+ if (config) {
398
+ addCheck(report, {
399
+ id: "distribution.config",
400
+ title: "CLI config",
401
+ message: `External CLI config is readable at ${configPath}.`,
402
+ data: {
403
+ configPath
404
+ }
405
+ });
406
+ return;
407
+ }
408
+ addCheck(report, {
409
+ id: "distribution.config",
410
+ title: "CLI config",
411
+ status: "fail",
412
+ message: `External CLI config is missing at ${configPath}.`,
413
+ action: "Run weavix config set before using external distribution commands.",
414
+ data: {
415
+ configPath
508
416
  }
509
- );
510
- }
511
- async function getIssue(issueKey) {
512
- return externalTrackerApiRequest(`/issues/${issueKey}`, {
513
- method: "GET"
514
417
  });
515
418
  }
516
- async function addIssueComment(issueKey, text) {
517
- await externalTrackerApiRequest(`/issues/${issueKey}/comments`, {
518
- method: "POST",
519
- body: { text }
520
- });
419
+ function checkHostResolution(report) {
420
+ try {
421
+ let data = {
422
+ trackerBaseUrl: getTrackerBaseUrl(),
423
+ platformBaseUrl: getPlatformBaseUrl(),
424
+ s3Endpoint: getS3Endpoint(),
425
+ mdsEndpoint: getMdsEndpoint(),
426
+ s3Region: getS3Region(),
427
+ buckets: getBuckets(),
428
+ pluginDownloadBase: getPluginDownloadBase("production")
429
+ };
430
+ addCheck(report, {
431
+ id: "distribution.hosts",
432
+ title: "External host configuration",
433
+ message: "External host configuration resolved.",
434
+ data
435
+ });
436
+ } catch (error2) {
437
+ addCheck(report, {
438
+ id: "distribution.hosts",
439
+ title: "External host configuration",
440
+ status: "fail",
441
+ message: error2 instanceof Error ? error2.message : String(error2),
442
+ action: "Run weavix config set and fill required endpoints."
443
+ });
444
+ }
521
445
  }
522
- async function getMyPluginIssues() {
523
- return externalTrackerApiRequest("/issues/_search", {
524
- method: "POST",
525
- body: {
526
- filter: {
527
- queue: "PLUGINMOD",
528
- createdBy: "me()"
446
+ async function checkExternalAuth(report, {
447
+ required,
448
+ useNetwork
449
+ }) {
450
+ let authData = externalAuthManager.data, authStatus = required || useNetwork ? "fail" : "warn";
451
+ if (!authData) {
452
+ addCheck(report, {
453
+ id: "auth.tracker",
454
+ title: "Tracker auth",
455
+ status: authStatus,
456
+ message: "External Tracker auth token is missing in the system credential store.",
457
+ action: "Run weavix login before submit or network diagnostics.",
458
+ data: {
459
+ storage: "system credential store"
529
460
  }
461
+ });
462
+ return;
463
+ }
464
+ if (addCheck(report, {
465
+ id: "auth.tracker",
466
+ title: "Tracker auth",
467
+ message: "External Tracker auth token is available in the system credential store.",
468
+ data: {
469
+ storage: "system credential store"
470
+ }
471
+ }), !!useNetwork)
472
+ try {
473
+ await externalTrackerApiRequest("/myself"), addCheck(report, {
474
+ id: "auth.tracker.network",
475
+ title: "Tracker auth network",
476
+ message: "Verified external Tracker auth with /myself."
477
+ });
478
+ } catch (error2) {
479
+ addCheck(report, {
480
+ id: "auth.tracker.network",
481
+ title: "Tracker auth network",
482
+ status: "fail",
483
+ message: error2 instanceof Error ? error2.message : String(error2),
484
+ action: "Check network access, org access, and rerun weavix login."
485
+ });
530
486
  }
487
+ }
488
+ async function checkDistribution(report, _projectRoot, options, policy = createDoctorPolicy(options)) {
489
+ report.distribution = DISTRIBUTION, checkCliConfig(report), checkHostResolution(report), await checkExternalAuth(report, {
490
+ required: policy.authMissingStatus === "fail",
491
+ useNetwork: !!options.network
531
492
  });
532
493
  }
533
- var import_form_data, PLUGINMOD_QUEUE, init_tracker = __esm({
534
- "src/distributions/external/tracker.ts"() {
494
+ var DISTRIBUTION, init_doctorChecks = __esm({
495
+ "src/distributions/external/doctorChecks.ts"() {
535
496
  "use strict";
536
- import_form_data = __toESM(require("form-data"));
497
+ init_manager();
498
+ init_policy();
499
+ init_report();
500
+ init_authManager();
501
+ init_hosts();
537
502
  init_trackerApiRequest();
538
- PLUGINMOD_QUEUE = "PLUGINMOD";
503
+ DISTRIBUTION = "external";
539
504
  }
540
505
  });
541
506
 
542
- // src/distributions/external/info.ts
543
- async function infoExternal(issueKey) {
544
- let targetIssueKey = issueKey;
545
- if (targetIssueKey || (targetIssueKey = (await pluginStateManager.load()).trackerIssueKey), !targetIssueKey) {
546
- logger_default.warning(
547
- `No issue key provided and plugin has not been submitted yet. Run "${CLI_NAME} submit" first.`
548
- ), logger_default.suggest(`${CLI_NAME} submit`);
549
- return;
550
- }
551
- logger_default.info(`\u23F3 Fetching plugin info for ${targetIssueKey}...`);
552
- try {
553
- let issue = await getIssue(targetIssueKey);
554
- showTrackerPluginInfo(issue);
555
- } catch (error2) {
556
- throw logger_default.error(`Failed to fetch plugin info for ${targetIssueKey}`), error2;
557
- }
558
- }
559
- var init_info = __esm({
560
- "src/distributions/external/info.ts"() {
507
+ // src/distribution/doctorChecks.ts
508
+ var impl2, checkDistribution2, init_doctorChecks2 = __esm({
509
+ "src/distribution/doctorChecks.ts"() {
561
510
  "use strict";
562
- init_pluginStateManager();
563
- init_logger();
564
- init_pluginDisplay();
565
- init_meta();
566
- init_tracker();
511
+ init_flag();
512
+ impl2 = (init_doctorChecks(), __toCommonJS(doctorChecks_exports)), { checkDistribution: checkDistribution2 } = impl2;
567
513
  }
568
514
  });
569
515
 
570
- // src/distributions/external/list.ts
571
- async function listExternal() {
572
- logger_default.info("\u23F3 Fetching my plugins from Tracker...");
573
- try {
574
- let issues = await getMyPluginIssues();
575
- showTrackerPluginList(issues);
576
- } catch (error2) {
577
- throw logger_default.error("Failed to fetch plugins list"), error2;
578
- }
516
+ // src/core/doctor/distChecks.ts
517
+ function resolveDistEntrypoint(distDir, entrypoint) {
518
+ if (import_path2.default.isAbsolute(entrypoint))
519
+ return {
520
+ error: `${entrypoint} is absolute`
521
+ };
522
+ let filePath = import_path2.default.resolve(distDir, import_path2.default.normalize(entrypoint)), relative = import_path2.default.relative(distDir, filePath);
523
+ return relative.startsWith("..") || import_path2.default.isAbsolute(relative) ? {
524
+ error: `${entrypoint} escapes dist`
525
+ } : {
526
+ filePath
527
+ };
579
528
  }
580
- var init_list = __esm({
581
- "src/distributions/external/list.ts"() {
582
- "use strict";
583
- init_logger();
584
- init_pluginDisplay();
585
- init_tracker();
529
+ async function checkDist(report, projectRoot, entries, policy) {
530
+ let distDir = import_path2.default.join(projectRoot, "dist");
531
+ if (!import_fs2.default.existsSync(distDir)) {
532
+ addCheck(report, {
533
+ id: "dist.exists",
534
+ title: "dist directory",
535
+ status: policy.distMissingStatus,
536
+ message: "dist directory is missing.",
537
+ action: "Run the plugin build before publishing."
538
+ });
539
+ return;
586
540
  }
587
- });
588
-
589
- // src/distributions/external/login.ts
590
- async function loginExternal() {
591
- console.info(
592
- import_picocolors3.default.dim(
593
- "To get an OAuth token for Yandex Tracker, please contact Tracker support and request one."
594
- )
595
- ), console.info("");
596
- let trimmed = (await (0, import_prompts2.input)({
597
- message: "Enter your OAuth token:",
598
- required: !0
599
- })).trim();
600
- externalAuthManager.saveAuthData(trimmed), logger_default.success("OAuth token saved successfully."), logger_default.info('You can now use "weavix submit" to submit your plugin for review.');
601
- }
602
- function logoutExternal() {
603
- if (!externalAuthManager.data) {
604
- logger_default.warning("You are not logged in.");
541
+ if (!import_fs2.default.statSync(distDir).isDirectory()) {
542
+ addCheck(report, {
543
+ id: "dist.exists",
544
+ title: "dist directory",
545
+ status: "fail",
546
+ message: `${distDir} exists but is not a directory.`,
547
+ action: "Remove it and run the plugin build."
548
+ });
605
549
  return;
606
550
  }
607
- externalAuthManager.removeAuthData(), logger_default.success("Successfully logged out.");
551
+ let files = await (0, import_tinyglobby.glob)(["**/*"], {
552
+ cwd: distDir,
553
+ onlyFiles: !0,
554
+ absolute: !0
555
+ });
556
+ files.length === 0 ? addCheck(report, {
557
+ id: "dist.files",
558
+ title: "dist files",
559
+ status: "fail",
560
+ message: "dist directory is empty.",
561
+ action: "Run the plugin build and verify generated files."
562
+ }) : addCheck(report, {
563
+ id: "dist.files",
564
+ title: "dist files",
565
+ message: `dist contains ${files.length} file(s).`
566
+ });
567
+ let entrypoints = [...new Set(entries.map((entry) => entry.entrypoint))], invalidEntrypoints = [], missingEntrypoints = [];
568
+ for (let entrypoint of entrypoints) {
569
+ let resolved = resolveDistEntrypoint(distDir, entrypoint);
570
+ if (resolved.error || !resolved.filePath) {
571
+ invalidEntrypoints.push(
572
+ resolved.error ? `${entrypoint} (${resolved.error})` : entrypoint
573
+ );
574
+ continue;
575
+ }
576
+ (!import_fs2.default.existsSync(resolved.filePath) || !import_fs2.default.statSync(resolved.filePath).isFile()) && missingEntrypoints.push(entrypoint);
577
+ }
578
+ invalidEntrypoints.length > 0 ? addCheck(report, {
579
+ id: "dist.entrypoints.valid",
580
+ title: "Built entrypoint paths",
581
+ status: "fail",
582
+ message: `Invalid entrypoint path(s): ${invalidEntrypoints.join(", ")}.`,
583
+ action: "Use relative entrypoint paths inside dist, for example index.html."
584
+ }) : entrypoints.length > 0 && addCheck(report, {
585
+ id: "dist.entrypoints.valid",
586
+ title: "Built entrypoint paths",
587
+ message: "Manifest entrypoint paths stay inside dist."
588
+ }), missingEntrypoints.length > 0 ? addCheck(report, {
589
+ id: "dist.entrypoints.exist",
590
+ title: "Built entrypoints",
591
+ status: "fail",
592
+ message: `Missing built entrypoint file(s): ${missingEntrypoints.join(", ")}.`,
593
+ action: "Run the plugin build and keep manifest entrypoint values in sync."
594
+ }) : entrypoints.length > 0 && invalidEntrypoints.length === 0 && addCheck(report, {
595
+ id: "dist.entrypoints.exist",
596
+ title: "Built entrypoints",
597
+ message: "All manifest entrypoints exist in dist."
598
+ });
608
599
  }
609
- var import_prompts2, import_picocolors3, init_login = __esm({
610
- "src/distributions/external/login.ts"() {
600
+ var import_fs2, import_path2, import_tinyglobby, init_distChecks = __esm({
601
+ "src/core/doctor/distChecks.ts"() {
611
602
  "use strict";
612
- import_prompts2 = require("@inquirer/prompts"), import_picocolors3 = __toESM(require("picocolors"));
613
- init_logger();
614
- init_authManager();
603
+ import_fs2 = __toESM(require("fs")), import_path2 = __toESM(require("path")), import_tinyglobby = require("tinyglobby");
604
+ init_report();
615
605
  }
616
606
  });
617
607
 
618
- // src/utils/execCommand.ts
619
- var import_execa, execCommand, init_execCommand = __esm({
620
- "src/utils/execCommand.ts"() {
608
+ // ../tracker-core/src/types/slots.ts
609
+ var TRACKER_SLOTS, init_slots = __esm({
610
+ "../tracker-core/src/types/slots.ts"() {
621
611
  "use strict";
622
- import_execa = require("execa"), execCommand = async (command, cwd = process.cwd(), env) => {
623
- await (0, import_execa.execa)(command, {
624
- cwd,
625
- shell: !0,
626
- stdio: "inherit",
627
- env: env ? { ...process.env, ...env } : void 0
628
- });
629
- };
612
+ TRACKER_SLOTS = [
613
+ "issue.action",
614
+ "issue.block",
615
+ "issue.tab",
616
+ "issue.comment.action",
617
+ "issue.editor.action",
618
+ "queue.action",
619
+ "queue.tab",
620
+ "navigation",
621
+ "trigger.create.action",
622
+ "trigger.edit.action",
623
+ "project.action",
624
+ "project.block",
625
+ "project.tab",
626
+ "project.editor.action",
627
+ "portfolio.action",
628
+ "portfolio.block",
629
+ "portfolio.tab",
630
+ "portfolio.editor.action",
631
+ "goal.action",
632
+ "goal.block",
633
+ "goal.tab",
634
+ "goal.editor.action",
635
+ "attachment.viewer.action",
636
+ "board.tab"
637
+ ];
630
638
  }
631
639
  });
632
640
 
633
- // src/commands/constants/templateCommands.ts
634
- var pluginCmd, init_templateCommands = __esm({
635
- "src/commands/constants/templateCommands.ts"() {
641
+ // ../tracker-core/src/index.ts
642
+ var init_src = __esm({
643
+ "../tracker-core/src/index.ts"() {
636
644
  "use strict";
637
- pluginCmd = {
638
- install: "npm install",
639
- build: "npm run build",
640
- dev: "npm run dev",
641
- lint: "npm run lint",
642
- typecheck: "npm run typecheck",
643
- test: "npm test",
644
- audit: "npm audit --audit-level=critical"
645
- };
645
+ init_slots();
646
646
  }
647
647
  });
648
648
 
649
- // src/commands/build.ts
650
- var build, init_build = __esm({
651
- "src/commands/build.ts"() {
649
+ // src/core/manifest/constants.ts
650
+ var DATA_PERMISSIONS, TOP_DATA_PERMISSIONS, SERVICES, TEMPLATES, CLI_ONLY_TRACKER_SLOTS, TRACKER_SERVICE_SLOTS, MESSENGER_SERVICE_SLOTS, SERVICE_SLOTS, TEMPLATE_SLOTS, TEMPLATE_SERVICE, init_constants = __esm({
651
+ "src/core/manifest/constants.ts"() {
652
652
  "use strict";
653
- init_execCommand();
654
- init_logger();
655
- init_templateCommands();
656
- build = async ({ environment = "production" } = {}) => {
657
- logger_default.info("\u{1F528} Building project..."), await execCommand(pluginCmd.install), await execCommand(
658
- pluginCmd.build,
659
- process.cwd(),
660
- environment ? { VITE_DEPLOY_ENV: environment } : void 0
661
- );
653
+ init_src();
654
+ DATA_PERMISSIONS = [
655
+ // top 10
656
+ "tracker:issues:read",
657
+ "tracker:issues:write",
658
+ "tracker:issuetypes:read",
659
+ "tracker:statuses:read",
660
+ "tracker:queues:read",
661
+ "tracker:fields:read",
662
+ "tracker:entities:read",
663
+ "tracker:attachments:read",
664
+ "tracker:attachments:write",
665
+ // in alphabetical order
666
+ "tracker:applications:read",
667
+ "tracker:boards:read",
668
+ "tracker:boards:write",
669
+ "tracker:bulk:read",
670
+ "tracker:bulk:write",
671
+ "tracker:bulkchange:read",
672
+ "tracker:bulkchange:write",
673
+ "tracker:charts:read",
674
+ "tracker:commentTemplates:read",
675
+ "tracker:commentTemplates:write",
676
+ "tracker:components:read",
677
+ "tracker:components:write",
678
+ "tracker:data:read",
679
+ "tracker:departments:read",
680
+ "tracker:entities:write",
681
+ "tracker:externalEventTypes:write",
682
+ "tracker:externalEvents:write",
683
+ "tracker:fields:write",
684
+ "tracker:filterFolders:write",
685
+ "tracker:filters:read",
686
+ "tracker:filters:write",
687
+ "tracker:goals:read",
688
+ "tracker:goals:write",
689
+ "tracker:groups:read",
690
+ "tracker:issueTemplates:read",
691
+ "tracker:issueTemplates:write",
692
+ "tracker:links:read",
693
+ "tracker:linktypes:read",
694
+ "tracker:liveBoards:write",
695
+ "tracker:localFields:read",
696
+ "tracker:maillists:read",
697
+ "tracker:maillists:write",
698
+ "tracker:myself:read",
699
+ "tracker:myself:write",
700
+ "tracker:priorities:read",
701
+ "tracker:queues:write",
702
+ "tracker:reminders:read",
703
+ "tracker:reminders:write",
704
+ "tracker:remotelinks:read",
705
+ "tracker:reports:read",
706
+ "tracker:reports:write",
707
+ "tracker:resolutions:read",
708
+ "tracker:resources:read",
709
+ "tracker:resources:write",
710
+ "tracker:roles:read",
711
+ "tracker:screens:read",
712
+ "tracker:services:read",
713
+ "tracker:sprints:read",
714
+ "tracker:sprints:write",
715
+ "tracker:system:write",
716
+ "tracker:tags:read",
717
+ "tracker:translations:read",
718
+ "tracker:users:read",
719
+ "tracker:users:write",
720
+ "tracker:versions:read",
721
+ "tracker:versions:write",
722
+ "tracker:workflows:read",
723
+ "tracker:workflows:write",
724
+ "tracker:worklog:read",
725
+ "tracker:worklog:write"
726
+ ], TOP_DATA_PERMISSIONS = DATA_PERMISSIONS.slice(0, 10), SERVICES = ["tracker", "messenger"], TEMPLATES = [
727
+ "default",
728
+ "issue.action",
729
+ "issue.block",
730
+ "issue.tab",
731
+ "issue.comment.action",
732
+ "issue.editor.action",
733
+ "queue.action",
734
+ "queue.tab",
735
+ "navigation",
736
+ "trigger.action",
737
+ "project.action",
738
+ "project.block",
739
+ "project.tab",
740
+ "project.editor.action",
741
+ "portfolio.action",
742
+ "portfolio.block",
743
+ "portfolio.tab",
744
+ "portfolio.editor.action",
745
+ "goal.action",
746
+ "goal.block",
747
+ "goal.tab",
748
+ "goal.editor.action",
749
+ "attachment.viewer.action",
750
+ "board.tab",
751
+ "user-card-info",
752
+ "user-card-calendar"
753
+ ], CLI_ONLY_TRACKER_SLOTS = ["dock"], TRACKER_SERVICE_SLOTS = [...TRACKER_SLOTS, ...CLI_ONLY_TRACKER_SLOTS], MESSENGER_SERVICE_SLOTS = ["user.card.info"], SERVICE_SLOTS = [...TRACKER_SERVICE_SLOTS, ...MESSENGER_SERVICE_SLOTS], TEMPLATE_SLOTS = {
754
+ default: [],
755
+ "issue.action": ["issue.action"],
756
+ "issue.block": ["issue.block"],
757
+ "issue.tab": ["issue.tab"],
758
+ "issue.comment.action": ["issue.comment.action"],
759
+ "issue.editor.action": ["issue.editor.action"],
760
+ "queue.action": ["queue.action"],
761
+ "queue.tab": ["queue.tab"],
762
+ navigation: ["navigation"],
763
+ "trigger.action": ["trigger.create.action", "trigger.edit.action"],
764
+ "project.action": ["project.action"],
765
+ "project.block": ["project.block"],
766
+ "project.tab": ["project.tab"],
767
+ "project.editor.action": ["project.editor.action"],
768
+ "portfolio.action": ["portfolio.action"],
769
+ "portfolio.block": ["portfolio.block"],
770
+ "portfolio.tab": ["portfolio.tab"],
771
+ "portfolio.editor.action": ["portfolio.editor.action"],
772
+ "goal.action": ["goal.action"],
773
+ "goal.block": ["goal.block"],
774
+ "goal.tab": ["goal.tab"],
775
+ "goal.editor.action": ["goal.editor.action"],
776
+ "attachment.viewer.action": ["attachment.viewer.action"],
777
+ "board.tab": ["board.tab"],
778
+ "user-card-info": ["user.card.info"],
779
+ "user-card-calendar": ["user.card.info"]
780
+ }, TEMPLATE_SERVICE = {
781
+ default: "tracker",
782
+ "issue.action": "tracker",
783
+ "issue.block": "tracker",
784
+ "issue.tab": "tracker",
785
+ "issue.comment.action": "tracker",
786
+ "issue.editor.action": "tracker",
787
+ "queue.action": "tracker",
788
+ "queue.tab": "tracker",
789
+ navigation: "tracker",
790
+ "trigger.action": "tracker",
791
+ "project.action": "tracker",
792
+ "project.block": "tracker",
793
+ "project.tab": "tracker",
794
+ "project.editor.action": "tracker",
795
+ "portfolio.action": "tracker",
796
+ "portfolio.block": "tracker",
797
+ "portfolio.tab": "tracker",
798
+ "portfolio.editor.action": "tracker",
799
+ "goal.action": "tracker",
800
+ "goal.block": "tracker",
801
+ "goal.tab": "tracker",
802
+ "goal.editor.action": "tracker",
803
+ "attachment.viewer.action": "tracker",
804
+ "board.tab": "tracker",
805
+ "user-card-info": "messenger",
806
+ "user-card-calendar": "messenger"
662
807
  };
663
808
  }
664
809
  });
@@ -676,11 +821,11 @@ var permissionsSchemaExtensions, init_manifestPermissionsSchema = __esm({
676
821
  });
677
822
 
678
823
  // src/distribution/manifestPermissionsSchema.ts
679
- var impl2, permissionsSchemaExtensions2, init_manifestPermissionsSchema2 = __esm({
824
+ var impl3, permissionsSchemaExtensions2, init_manifestPermissionsSchema2 = __esm({
680
825
  "src/distribution/manifestPermissionsSchema.ts"() {
681
826
  "use strict";
682
827
  init_flag();
683
- impl2 = (init_manifestPermissionsSchema(), __toCommonJS(manifestPermissionsSchema_exports)), { permissionsSchemaExtensions: permissionsSchemaExtensions2 } = impl2;
828
+ impl3 = (init_manifestPermissionsSchema(), __toCommonJS(manifestPermissionsSchema_exports)), { permissionsSchemaExtensions: permissionsSchemaExtensions2 } = impl3;
684
829
  }
685
830
  });
686
831
 
@@ -712,14 +857,14 @@ var priorityOrder, errorMessages, getPriority, formatValidationErrors, init_form
712
857
  }, formatValidationErrors = (errors) => {
713
858
  let errorsByPath = {};
714
859
  for (let error2 of errors) {
715
- let path18 = error2.instancePath || "root";
716
- errorsByPath[path18] || (errorsByPath[path18] = []), errorsByPath[path18].push(error2);
860
+ let path24 = error2.instancePath || "root";
861
+ errorsByPath[path24] || (errorsByPath[path24] = []), errorsByPath[path24].push(error2);
717
862
  }
718
- return Object.entries(errorsByPath).map(([path18, pathErrors]) => {
863
+ return Object.entries(errorsByPath).map(([path24, pathErrors]) => {
719
864
  let error2 = [...pathErrors].sort(
720
865
  (a, b) => getPriority(a.keyword) - getPriority(b.keyword)
721
866
  )[0], formatter = errorMessages[error2.keyword], message = formatter ? formatter(error2.params) : error2.message;
722
- return ` - ${path18}: ${message}`;
867
+ return ` - ${path24}: ${message}`;
723
868
  }).join(`
724
869
  `);
725
870
  };
@@ -764,7 +909,8 @@ var manifest_schema_default, init_manifest_schema = __esm({
764
909
  items: {
765
910
  type: "string",
766
911
  enum: [
767
- "tracker"
912
+ "tracker",
913
+ "messenger"
768
914
  ]
769
915
  },
770
916
  minItems: 1,
@@ -992,7 +1138,12 @@ var manifest_schema_default, init_manifest_schema = __esm({
992
1138
  items: {
993
1139
  type: "string",
994
1140
  enum: [
995
- "clipboard-write"
1141
+ "clipboard-write",
1142
+ "microphone",
1143
+ "camera",
1144
+ "geolocation",
1145
+ "web-share",
1146
+ "allow-downloads"
996
1147
  ]
997
1148
  },
998
1149
  uniqueItems: !0
@@ -1050,6 +1201,30 @@ var manifest_schema_default, init_manifest_schema = __esm({
1050
1201
  $ref: "#/definitions/SlotConfig"
1051
1202
  }
1052
1203
  },
1204
+ "issue.editor.action": {
1205
+ type: "array",
1206
+ description: "Issue Editor Action slot configurations",
1207
+ minItems: 1,
1208
+ items: {
1209
+ $ref: "#/definitions/SlotConfig"
1210
+ }
1211
+ },
1212
+ "queue.action": {
1213
+ type: "array",
1214
+ description: "Queue Action slot configurations",
1215
+ minItems: 1,
1216
+ items: {
1217
+ $ref: "#/definitions/SlotConfig"
1218
+ }
1219
+ },
1220
+ "queue.tab": {
1221
+ type: "array",
1222
+ description: "Queue Tab slot configurations",
1223
+ minItems: 1,
1224
+ items: {
1225
+ $ref: "#/definitions/SlotConfig"
1226
+ }
1227
+ },
1053
1228
  navigation: {
1054
1229
  type: "array",
1055
1230
  description: "Navigation slot configurations",
@@ -1098,6 +1273,14 @@ var manifest_schema_default, init_manifest_schema = __esm({
1098
1273
  $ref: "#/definitions/SlotConfig"
1099
1274
  }
1100
1275
  },
1276
+ "project.editor.action": {
1277
+ type: "array",
1278
+ description: "Project Editor Action slot configurations",
1279
+ minItems: 1,
1280
+ items: {
1281
+ $ref: "#/definitions/SlotConfig"
1282
+ }
1283
+ },
1101
1284
  "portfolio.action": {
1102
1285
  type: "array",
1103
1286
  description: "Portfolio Action slot configurations",
@@ -1122,6 +1305,14 @@ var manifest_schema_default, init_manifest_schema = __esm({
1122
1305
  $ref: "#/definitions/SlotConfig"
1123
1306
  }
1124
1307
  },
1308
+ "portfolio.editor.action": {
1309
+ type: "array",
1310
+ description: "Portfolio Editor Action slot configurations",
1311
+ minItems: 1,
1312
+ items: {
1313
+ $ref: "#/definitions/SlotConfig"
1314
+ }
1315
+ },
1125
1316
  "goal.action": {
1126
1317
  type: "array",
1127
1318
  description: "Goal Action slot configurations",
@@ -1146,6 +1337,14 @@ var manifest_schema_default, init_manifest_schema = __esm({
1146
1337
  $ref: "#/definitions/SlotConfig"
1147
1338
  }
1148
1339
  },
1340
+ "goal.editor.action": {
1341
+ type: "array",
1342
+ description: "Goal Editor Action slot configurations",
1343
+ minItems: 1,
1344
+ items: {
1345
+ $ref: "#/definitions/SlotConfig"
1346
+ }
1347
+ },
1149
1348
  "attachment.viewer.action": {
1150
1349
  type: "array",
1151
1350
  description: "Attachment Viewer Action slot configurations",
@@ -1172,6 +1371,22 @@ var manifest_schema_default, init_manifest_schema = __esm({
1172
1371
  }
1173
1372
  },
1174
1373
  additionalProperties: !1
1374
+ },
1375
+ messenger: {
1376
+ type: "object",
1377
+ description: "Messenger service slots",
1378
+ minProperties: 1,
1379
+ properties: {
1380
+ "user.card.info": {
1381
+ type: "array",
1382
+ description: "User Card Info slot configurations",
1383
+ minItems: 1,
1384
+ items: {
1385
+ $ref: "#/definitions/SlotConfig"
1386
+ }
1387
+ }
1388
+ },
1389
+ additionalProperties: !1
1175
1390
  }
1176
1391
  },
1177
1392
  additionalProperties: !1
@@ -1363,10 +1578,10 @@ var manifest_schema_default, init_manifest_schema = __esm({
1363
1578
  });
1364
1579
 
1365
1580
  // src/core/manifest/manifestManager.ts
1366
- var import_fs4, import_promises2, import_ajv, import_ajv_formats, validator, manifestPath, parseManifest, loadRaw, load2, validate, save2, update2, manifestManager, init_manifestManager = __esm({
1581
+ var import_fs3, import_promises, import_ajv, import_ajv_formats, validator, defaultManifestPath, parseManifest, loadRaw, load, validate, save, update, manifestManager, init_manifestManager = __esm({
1367
1582
  "src/core/manifest/manifestManager.ts"() {
1368
1583
  "use strict";
1369
- import_fs4 = require("fs"), import_promises2 = require("fs/promises"), import_ajv = __toESM(require("ajv")), import_ajv_formats = __toESM(require("ajv-formats"));
1584
+ import_fs3 = require("fs"), import_promises = require("fs/promises"), import_ajv = __toESM(require("ajv")), import_ajv_formats = __toESM(require("ajv-formats"));
1370
1585
  init_manifestPermissionsSchema2();
1371
1586
  init_formatValidationErrors();
1372
1587
  init_manifest_schema();
@@ -1385,7 +1600,7 @@ var import_fs4, import_promises2, import_ajv, import_ajv_formats, validator, man
1385
1600
  }
1386
1601
  }, ajv = new import_ajv.default({ allErrors: !0, strict: !1 });
1387
1602
  return (0, import_ajv_formats.default)(ajv), ajv.compile(schema);
1388
- })(), manifestPath = "./manifest.json", parseManifest = (content) => {
1603
+ })(), defaultManifestPath = "./manifest.json", parseManifest = (content) => {
1389
1604
  let manifest;
1390
1605
  try {
1391
1606
  manifest = JSON.parse(content);
@@ -1393,19 +1608,19 @@ var import_fs4, import_promises2, import_ajv, import_ajv_formats, validator, man
1393
1608
  throw error2 instanceof SyntaxError ? new Error(`File manifest.json contains invalid JSON: ${error2.message}`) : new Error(`Error reading manifest.json: ${error2.message}`);
1394
1609
  }
1395
1610
  return manifest;
1396
- }, loadRaw = async () => {
1397
- if (!(0, import_fs4.existsSync)(manifestPath))
1611
+ }, loadRaw = async (manifestPath = defaultManifestPath) => {
1612
+ if (!(0, import_fs3.existsSync)(manifestPath))
1398
1613
  throw new Error(`File manifest.json not found at path: ${manifestPath}`);
1399
1614
  try {
1400
- return await (0, import_promises2.readFile)(manifestPath, "utf8");
1615
+ return await (0, import_promises.readFile)(manifestPath, "utf8");
1401
1616
  } catch (error2) {
1402
1617
  throw error2 instanceof Error ? new Error(`Error reading manifest.json: ${error2.message}`) : new Error("Error loading manifest");
1403
1618
  }
1404
- }, load2 = async () => {
1405
- let manifestContent = await loadRaw();
1619
+ }, load = async (manifestPath = defaultManifestPath) => {
1620
+ let manifestContent = await loadRaw(manifestPath);
1406
1621
  return parseManifest(manifestContent);
1407
- }, validate = async () => {
1408
- let manifest = await load2();
1622
+ }, validate = async (manifestPath = defaultManifestPath) => {
1623
+ let manifest = await load(manifestPath);
1409
1624
  if (!validator(manifest) && validator.errors) {
1410
1625
  let errorMessages2 = formatValidationErrors(validator.errors);
1411
1626
  throw new Error(
@@ -1415,231 +1630,1593 @@ ${errorMessages2}
1415
1630
  \u{1F4A1} Ensure all required fields are filled according to the plugin documentation.`
1416
1631
  );
1417
1632
  }
1418
- }, save2 = async (manifest) => {
1633
+ }, save = async (manifest, manifestPath = defaultManifestPath) => {
1419
1634
  try {
1420
1635
  let content = JSON.stringify(manifest, null, 4);
1421
- await (0, import_promises2.writeFile)(manifestPath, content, "utf8");
1636
+ await (0, import_promises.writeFile)(manifestPath, content, "utf8");
1422
1637
  } catch (error2) {
1423
1638
  throw error2 instanceof Error ? new Error(`Error saving manifest.json: ${error2.message}`) : new Error("Error saving manifest");
1424
1639
  }
1425
- }, update2 = async (updates) => {
1426
- let updatedManifest = { ...await load2(), ...updates };
1427
- return await save2(updatedManifest), updatedManifest;
1640
+ }, update = async (updates, manifestPath = defaultManifestPath) => {
1641
+ let updatedManifest = { ...await load(manifestPath), ...updates };
1642
+ return await save(updatedManifest, manifestPath), updatedManifest;
1428
1643
  }, manifestManager = {
1429
- load: load2,
1644
+ load,
1430
1645
  loadRaw,
1431
1646
  validate,
1432
- save: save2,
1433
- update: update2
1647
+ save,
1648
+ update
1434
1649
  };
1435
1650
  }
1436
1651
  });
1437
1652
 
1438
- // src/utils/marketplace.ts
1439
- function validateMarketplaceAssets() {
1440
- let marketplaceDir = import_path3.default.resolve(MARKETPLACE_DIR);
1441
- ensurePathExists(
1442
- marketplaceDir,
1443
- "Marketplace folder not found. Create ./marketplace and add index.md and header-image.jpg before publishing."
1444
- ), ensurePathExists(
1445
- import_path3.default.join(marketplaceDir, MARKETPLACE_INDEX_FILE),
1446
- "Marketplace description not found. Add ./marketplace/index.md before publishing."
1447
- ), ensurePathExists(
1448
- import_path3.default.join(marketplaceDir, MARKETPLACE_HEADER_IMAGE_FILE),
1449
- "Marketplace header image not found. Add ./marketplace/header-image.jpg before publishing."
1450
- ), ensurePathExists(
1451
- import_path3.default.resolve(PUBLIC_DIR, PUBLIC_LOGO_FILE),
1452
- "Plugin logo not found. Add ./public/logo.svg before publishing."
1453
- );
1653
+ // src/core/doctor/helpers.ts
1654
+ function getErrorMessage(error2) {
1655
+ return error2 instanceof Error ? error2.message : String(error2);
1656
+ }
1657
+ var init_helpers = __esm({
1658
+ "src/core/doctor/helpers.ts"() {
1659
+ "use strict";
1660
+ }
1661
+ });
1662
+
1663
+ // src/core/doctor/manifestChecks.ts
1664
+ function isNonEmptyString(value) {
1665
+ return typeof value == "string" && !!value.trim();
1666
+ }
1667
+ function isSafeRelativePath(value) {
1668
+ if (import_path3.default.isAbsolute(value))
1669
+ return !1;
1670
+ let normalized = import_path3.default.normalize(value);
1671
+ return normalized !== ".." && !normalized.startsWith(`..${import_path3.default.sep}`);
1672
+ }
1673
+ function getManifestEntries(manifest) {
1674
+ let result = [];
1675
+ for (let service of SERVICES) {
1676
+ let serviceSlots = manifest.slots?.[service];
1677
+ if (serviceSlots) {
1678
+ for (let [slot, slotConfigs] of Object.entries(serviceSlots))
1679
+ if (!(!SERVICE_SLOTS.includes(slot) || !Array.isArray(slotConfigs)))
1680
+ for (let slotConfig of slotConfigs) {
1681
+ let slotRecord = slotConfig;
1682
+ result.push({
1683
+ service,
1684
+ slot,
1685
+ entrypoint: slotConfig.entrypoint,
1686
+ title: slotConfig.title,
1687
+ description: slotConfig.description,
1688
+ contextLevel: slotConfig.contextLevel,
1689
+ iconUrl: slotRecord.icon?.url
1690
+ });
1691
+ }
1692
+ }
1693
+ }
1694
+ return result;
1695
+ }
1696
+ function checkLocalizedString(missingValues, name, value) {
1697
+ isNonEmptyString(value?.ru) || missingValues.push(`${name}.ru`), isNonEmptyString(value?.en) || missingValues.push(`${name}.en`);
1698
+ }
1699
+ function checkManifestDetails(report, manifest, policy) {
1700
+ let entries = getManifestEntries(manifest);
1701
+ entries.length > 0 ? addCheck(report, {
1702
+ id: "manifest.entries",
1703
+ title: "Manifest slot entries",
1704
+ message: `Found ${entries.length} plugin slot entry(s).`,
1705
+ data: entries.map((entry) => ({
1706
+ service: entry.service,
1707
+ slot: entry.slot,
1708
+ entrypoint: entry.entrypoint,
1709
+ contextLevel: entry.contextLevel
1710
+ }))
1711
+ }) : addCheck(report, {
1712
+ id: "manifest.entries",
1713
+ title: "Manifest slot entries",
1714
+ status: "fail",
1715
+ message: "Manifest does not define any supported service slot entries.",
1716
+ action: `Add at least one slots.${SERVICES[0]} entry to manifest.json.`
1717
+ });
1718
+ let missingLocalizedStrings = [];
1719
+ checkLocalizedString(missingLocalizedStrings, "name", manifest.name), checkLocalizedString(missingLocalizedStrings, "description", manifest.description);
1720
+ for (let entry of entries)
1721
+ checkLocalizedString(
1722
+ missingLocalizedStrings,
1723
+ `slots.${entry.service}.${entry.slot}.title`,
1724
+ entry.title
1725
+ ), entry.description && checkLocalizedString(
1726
+ missingLocalizedStrings,
1727
+ `slots.${entry.service}.${entry.slot}.description`,
1728
+ entry.description
1729
+ );
1730
+ missingLocalizedStrings.length === 0 ? addCheck(report, {
1731
+ id: "manifest.localized-strings",
1732
+ title: "Localized strings",
1733
+ message: "Manifest localized strings are non-empty."
1734
+ }) : addCheck(report, {
1735
+ id: "manifest.localized-strings",
1736
+ title: "Localized strings",
1737
+ status: "fail",
1738
+ message: `Empty localized value(s): ${missingLocalizedStrings.join(", ")}.`,
1739
+ action: "Fill ru and en values before publishing."
1740
+ });
1741
+ let invalidEntrypoints = entries.map((entry) => entry.entrypoint).filter((entrypoint) => !isSafeRelativePath(entrypoint));
1742
+ return invalidEntrypoints.length > 0 ? addCheck(report, {
1743
+ id: "manifest.entrypoints.valid",
1744
+ title: "Manifest entrypoint paths",
1745
+ status: "fail",
1746
+ message: `Invalid entrypoint path(s): ${invalidEntrypoints.join(", ")}.`,
1747
+ action: "Use relative entrypoint paths inside dist, for example index.html."
1748
+ }) : entries.length > 0 && addCheck(report, {
1749
+ id: "manifest.entrypoints.valid",
1750
+ title: "Manifest entrypoint paths",
1751
+ message: "All manifest entrypoint paths are relative."
1752
+ }), manifest.permissions?.data?.length ? addCheck(report, {
1753
+ id: "manifest.permissions",
1754
+ title: "Manifest permissions",
1755
+ message: `Manifest declares ${manifest.permissions.data.length} data permission(s).`,
1756
+ data: manifest.permissions
1757
+ }) : addCheck(report, {
1758
+ id: "manifest.permissions",
1759
+ title: "Manifest permissions",
1760
+ status: policy.manifestPermissionsStatus,
1761
+ message: "Manifest permissions.data is empty.",
1762
+ action: "Add the data permissions required by the plugin before publishing."
1763
+ }), manifest.support?.length ? addCheck(report, {
1764
+ id: "manifest.support",
1765
+ title: "Support contacts",
1766
+ message: `Manifest declares ${manifest.support.length} support contact(s).`
1767
+ }) : addCheck(report, {
1768
+ id: "manifest.support",
1769
+ title: "Support contacts",
1770
+ status: policy.manifestSupportStatus,
1771
+ message: "Manifest support contacts are missing.",
1772
+ action: "Add at least one support contact to manifest.json before publishing."
1773
+ }), entries;
1774
+ }
1775
+ async function checkManifest(report, manifestPath, policy) {
1776
+ try {
1777
+ await manifestManager.validate(manifestPath);
1778
+ let manifest = await manifestManager.load(manifestPath);
1779
+ return report.manifest = {
1780
+ slug: manifest.slug,
1781
+ version: manifest.version
1782
+ }, addCheck(report, {
1783
+ id: "manifest.valid",
1784
+ title: "Manifest schema",
1785
+ message: "manifest.json is valid."
1786
+ }), {
1787
+ manifest,
1788
+ entries: checkManifestDetails(report, manifest, policy)
1789
+ };
1790
+ } catch (error2) {
1791
+ return addCheck(report, {
1792
+ id: "manifest.valid",
1793
+ title: "Manifest schema",
1794
+ status: "fail",
1795
+ message: getErrorMessage(error2),
1796
+ action: "Fix manifest.json before running build, debug, or submit."
1797
+ }), {
1798
+ entries: []
1799
+ };
1800
+ }
1801
+ }
1802
+ var import_path3, init_manifestChecks = __esm({
1803
+ "src/core/doctor/manifestChecks.ts"() {
1804
+ "use strict";
1805
+ import_path3 = __toESM(require("path"));
1806
+ init_constants();
1807
+ init_manifestManager();
1808
+ init_helpers();
1809
+ init_report();
1810
+ }
1811
+ });
1812
+
1813
+ // src/core/doctor/marketplaceChecks.ts
1814
+ function getMissingOrInvalidStatus(requiredPath, policy) {
1815
+ return requiredPath.path === "src" ? "fail" : policy.marketplaceAssetsStatus;
1816
+ }
1817
+ function checkMarketplaceAssets(report, projectRoot, policy) {
1818
+ for (let requiredPath of REQUIRED_PATHS) {
1819
+ let fullPath = import_path4.default.join(projectRoot, requiredPath.path), status = getMissingOrInvalidStatus(requiredPath, policy);
1820
+ if (!import_fs4.default.existsSync(fullPath)) {
1821
+ addCheck(report, {
1822
+ id: `marketplace.${requiredPath.path}`,
1823
+ title: requiredPath.title,
1824
+ status,
1825
+ message: `${requiredPath.path} is missing.`,
1826
+ action: `Add ${requiredPath.path} before publishing.`
1827
+ });
1828
+ continue;
1829
+ }
1830
+ let stat = import_fs4.default.statSync(fullPath), validKind = requiredPath.kind === "directory" ? stat.isDirectory() : stat.isFile();
1831
+ addCheck(report, {
1832
+ id: `marketplace.${requiredPath.path}`,
1833
+ title: requiredPath.title,
1834
+ status: validKind ? "pass" : status,
1835
+ message: validKind ? `Found ${requiredPath.path}.` : `${requiredPath.path} exists but is not a ${requiredPath.kind}.`,
1836
+ action: validKind ? void 0 : `Replace ${requiredPath.path} with a ${requiredPath.kind}.`
1837
+ });
1838
+ }
1839
+ }
1840
+ var import_fs4, import_path4, REQUIRED_PATHS, init_marketplaceChecks = __esm({
1841
+ "src/core/doctor/marketplaceChecks.ts"() {
1842
+ "use strict";
1843
+ import_fs4 = __toESM(require("fs")), import_path4 = __toESM(require("path"));
1844
+ init_report();
1845
+ REQUIRED_PATHS = [
1846
+ { path: "src", title: "Source directory", kind: "directory" },
1847
+ { path: "marketplace", title: "Marketplace directory", kind: "directory" },
1848
+ { path: "marketplace/index.md", title: "Marketplace description", kind: "file" },
1849
+ { path: "marketplace/header-image.jpg", title: "Marketplace header image", kind: "file" },
1850
+ { path: "public/logo.svg", title: "Plugin logo", kind: "file" }
1851
+ ];
1852
+ }
1853
+ });
1854
+
1855
+ // src/core/doctor/nodeChecks.ts
1856
+ function checkNodeVersion(report) {
1857
+ let version = process.versions.node, major = Number(version.split(".")[0]);
1858
+ if (Number.isInteger(major) && major >= REQUIRED_NODE_MAJOR) {
1859
+ addCheck(report, {
1860
+ id: "node.version",
1861
+ title: "Node.js version",
1862
+ message: `Node.js ${version} satisfies >=${REQUIRED_NODE_MAJOR}.`,
1863
+ data: {
1864
+ version,
1865
+ requiredMajor: REQUIRED_NODE_MAJOR
1866
+ }
1867
+ });
1868
+ return;
1869
+ }
1870
+ addCheck(report, {
1871
+ id: "node.version",
1872
+ title: "Node.js version",
1873
+ status: "fail",
1874
+ message: `Node.js ${version} does not satisfy >=${REQUIRED_NODE_MAJOR}.`,
1875
+ action: `Switch to Node.js ${REQUIRED_NODE_MAJOR} or newer.`,
1876
+ data: {
1877
+ version,
1878
+ requiredMajor: REQUIRED_NODE_MAJOR
1879
+ }
1880
+ });
1881
+ }
1882
+ var REQUIRED_NODE_MAJOR, init_nodeChecks = __esm({
1883
+ "src/core/doctor/nodeChecks.ts"() {
1884
+ "use strict";
1885
+ init_report();
1886
+ REQUIRED_NODE_MAJOR = 22;
1887
+ }
1888
+ });
1889
+
1890
+ // src/utils/packageManager.ts
1891
+ function defaultCommandExists(command) {
1892
+ if (!/^[a-zA-Z0-9_-]+$/.test(command))
1893
+ return !1;
1894
+ let result = (0, import_child_process.spawnSync)("sh", ["-c", `command -v ${command}`], {
1895
+ stdio: "ignore"
1896
+ });
1897
+ return !result.error && result.status === 0;
1898
+ }
1899
+ function detectFromPackageJson(projectRoot) {
1900
+ let packageJsonPath = import_path5.default.join(projectRoot, "package.json");
1901
+ if (import_fs5.default.existsSync(packageJsonPath))
1902
+ try {
1903
+ let raw = import_fs5.default.readFileSync(packageJsonPath, "utf8"), packageManager = JSON.parse(raw).packageManager;
1904
+ if (typeof packageManager != "string")
1905
+ return;
1906
+ if (packageManager.startsWith("pnpm@"))
1907
+ return "pnpm";
1908
+ if (packageManager.startsWith("npm@"))
1909
+ return "npm";
1910
+ } catch {
1911
+ return;
1912
+ }
1913
+ }
1914
+ function detectPackageManager(projectRoot = process.cwd()) {
1915
+ return import_fs5.default.existsSync(import_path5.default.join(projectRoot, "pnpm-lock.yaml")) ? "pnpm" : detectFromPackageJson(projectRoot) || "npm";
1916
+ }
1917
+ function resolvePackageManagerExecutable(packageManager, options = {}) {
1918
+ let commandExists = options.commandExists || defaultCommandExists;
1919
+ if (commandExists(packageManager))
1920
+ return {
1921
+ command: packageManager,
1922
+ argsPrefix: []
1923
+ };
1924
+ if (packageManager !== "npm" && commandExists("corepack"))
1925
+ return {
1926
+ command: "corepack",
1927
+ argsPrefix: [packageManager]
1928
+ };
1929
+ throw packageManager === "npm" ? new Error(
1930
+ "npm is not available in PATH. Install Node.js and npm, then rerun this command."
1931
+ ) : new Error(
1932
+ `${packageManager} is not available in PATH, and Corepack is not available either. Install Node.js >= 22 with Corepack, or run npm install -g corepack@latest && corepack enable once, then rerun this command.`
1933
+ );
1934
+ }
1935
+ function truncateOutput(value) {
1936
+ let normalized = value.trim();
1937
+ return normalized.length <= MAX_RUNTIME_OUTPUT_LENGTH ? normalized : `${normalized.slice(0, MAX_RUNTIME_OUTPUT_LENGTH)}...`;
1938
+ }
1939
+ function getRuntimeOutput(result) {
1940
+ return truncateOutput(
1941
+ [result.stdout?.toString(), result.stderr?.toString()].filter(Boolean).join(`
1942
+ `)
1943
+ );
1944
+ }
1945
+ function isCorepackKeyIdError(output) {
1946
+ return /Cannot find matching keyid/i.test(output);
1947
+ }
1948
+ function getPackageManagerRuntimeAction(output, packageManager) {
1949
+ return isCorepackKeyIdError(output) ? `Corepack cannot verify the pinned package manager signature. Update Corepack from the same registry used for global CLI installs: npm install -g corepack@latest && corepack enable. Then rerun: ${packageManager === "npm" ? "npm install" : `corepack ${packageManager} install`}. Do not use COREPACK_INTEGRITY_KEYS=0 because it disables signature checks.` : packageManager === "npm" ? "Fix the npm runtime, then rerun doctor. For freshly generated plugins, install Node.js >= 22 and run npm install from the plugin directory." : `Fix the ${packageManager} runtime, then rerun doctor. For Corepack-managed package managers, try: npm install -g corepack@latest && corepack enable.`;
1950
+ }
1951
+ function runPackageManagerRuntimeCheck(projectRoot, packageManager, executable) {
1952
+ let args = [...executable.argsPrefix, "--version"], commandLabel = [executable.command, ...args].join(" "), result = (0, import_child_process.spawnSync)(executable.command, args, {
1953
+ cwd: projectRoot,
1954
+ encoding: "utf8",
1955
+ timeout: PACKAGE_MANAGER_RUNTIME_TIMEOUT_MS
1956
+ }), output = getRuntimeOutput(result);
1957
+ if (!result.error && result.status === 0)
1958
+ return {
1959
+ ok: !0,
1960
+ packageManager,
1961
+ command: executable.command,
1962
+ args,
1963
+ commandLabel,
1964
+ message: `${commandLabel} returned ${output || "success"}.`,
1965
+ version: output || void 0,
1966
+ status: result.status,
1967
+ signal: result.signal,
1968
+ output: output || null
1969
+ };
1970
+ let message = result.error ? result.error.message : output || `${commandLabel} exited with code ${result.status}.`;
1971
+ return {
1972
+ ok: !1,
1973
+ packageManager,
1974
+ command: executable.command,
1975
+ args,
1976
+ commandLabel,
1977
+ message,
1978
+ action: getPackageManagerRuntimeAction(output || message, packageManager),
1979
+ status: result.status,
1980
+ signal: result.signal,
1981
+ output: output || null
1982
+ };
1983
+ }
1984
+ var import_child_process, import_fs5, import_path5, PACKAGE_MANAGER_RUNTIME_TIMEOUT_MS, MAX_RUNTIME_OUTPUT_LENGTH, PackageManagerRuntimeError, init_packageManager = __esm({
1985
+ "src/utils/packageManager.ts"() {
1986
+ "use strict";
1987
+ import_child_process = require("child_process"), import_fs5 = __toESM(require("fs")), import_path5 = __toESM(require("path")), PACKAGE_MANAGER_RUNTIME_TIMEOUT_MS = 15e3, MAX_RUNTIME_OUTPUT_LENGTH = 1e3, PackageManagerRuntimeError = class extends Error {
1988
+ constructor(check) {
1989
+ super(check.message), this.name = "PackageManagerRuntimeError", this.action = check.action, this.check = check;
1990
+ }
1991
+ };
1992
+ }
1993
+ });
1994
+
1995
+ // src/core/doctor/packageChecks.ts
1996
+ function readPackageJson(projectRoot) {
1997
+ let packageJsonPath = import_path6.default.join(projectRoot, "package.json");
1998
+ if (!import_fs6.default.existsSync(packageJsonPath))
1999
+ return {
2000
+ path: packageJsonPath,
2001
+ error: "package.json not found"
2002
+ };
2003
+ try {
2004
+ let raw = import_fs6.default.readFileSync(packageJsonPath, "utf8");
2005
+ return {
2006
+ path: packageJsonPath,
2007
+ packageJson: JSON.parse(raw)
2008
+ };
2009
+ } catch (error2) {
2010
+ return {
2011
+ path: packageJsonPath,
2012
+ error: getErrorMessage(error2)
2013
+ };
2014
+ }
2015
+ }
2016
+ function getScript(packageJson, name) {
2017
+ if (typeof packageJson.scripts != "object" || packageJson.scripts === null)
2018
+ return;
2019
+ let value = packageJson.scripts[name];
2020
+ return typeof value == "string" && value.trim() ? value : void 0;
2021
+ }
2022
+ function getDependencyVersion(packageJson, name) {
2023
+ let dependencySources = [packageJson.dependencies, packageJson.devDependencies];
2024
+ for (let source of dependencySources) {
2025
+ if (typeof source != "object" || source === null)
2026
+ continue;
2027
+ let value = source[name];
2028
+ if (typeof value == "string" && value.trim())
2029
+ return value;
2030
+ }
2031
+ }
2032
+ function addPackageManagerRuntimeCheck(report, runtimeCheck) {
2033
+ if (runtimeCheck.ok) {
2034
+ addCheck(report, {
2035
+ id: "package-manager.runtime",
2036
+ title: "Package manager runtime",
2037
+ message: runtimeCheck.message,
2038
+ data: {
2039
+ packageManager: runtimeCheck.packageManager,
2040
+ command: runtimeCheck.command,
2041
+ args: runtimeCheck.args,
2042
+ version: runtimeCheck.version || null
2043
+ }
2044
+ });
2045
+ return;
2046
+ }
2047
+ addCheck(report, {
2048
+ id: "package-manager.runtime",
2049
+ title: "Package manager runtime",
2050
+ status: "fail",
2051
+ message: runtimeCheck.message,
2052
+ action: runtimeCheck.action,
2053
+ data: {
2054
+ packageManager: runtimeCheck.packageManager,
2055
+ command: runtimeCheck.command,
2056
+ args: runtimeCheck.args,
2057
+ status: runtimeCheck.status,
2058
+ signal: runtimeCheck.signal,
2059
+ output: runtimeCheck.output
2060
+ }
2061
+ });
2062
+ }
2063
+ function getPackageManagerInstallAction(packageManager) {
2064
+ return packageManager === "npm" ? "Install Node.js >= 22 with npm, then rerun npm install." : `Install and enable Corepack once: npm install -g corepack@latest && corepack enable. Then rerun corepack ${packageManager} install.`;
2065
+ }
2066
+ function checkScript(report, packageJson, script, required) {
2067
+ let value = getScript(packageJson, script);
2068
+ if (value) {
2069
+ addCheck(report, {
2070
+ id: `package-json.script.${script}`,
2071
+ title: `${script} script`,
2072
+ message: `${script} script is "${value}".`
2073
+ });
2074
+ return;
2075
+ }
2076
+ addCheck(report, {
2077
+ id: `package-json.script.${script}`,
2078
+ title: `${script} script`,
2079
+ status: required ? "fail" : "warn",
2080
+ message: `Missing package.json scripts.${script}.`,
2081
+ action: required ? `Add scripts.${script}; CLI commands expect it.` : `Add scripts.${script} if this plugin should support this check.`
2082
+ });
2083
+ }
2084
+ function checkPluginSdkDependency(report, packageJson) {
2085
+ let detectedPackages = COMMON_SDK_PACKAGES.filter(
2086
+ (packageName) => getDependencyVersion(packageJson, packageName)
2087
+ ), detectedGenericPackages = GENERIC_SDK_PACKAGES.filter(
2088
+ (packageName) => getDependencyVersion(packageJson, packageName)
2089
+ ), missingGenericPackages = GENERIC_SDK_PACKAGES.filter(
2090
+ (packageName) => !getDependencyVersion(packageJson, packageName)
2091
+ );
2092
+ if (detectedPackages.length > 0) {
2093
+ addCheck(report, {
2094
+ id: "package-json.sdk-dependency",
2095
+ title: "Plugin SDK dependency",
2096
+ message: `Uses common plugin SDK package(s): ${detectedPackages.join(", ")}.`,
2097
+ data: detectedPackages
2098
+ }), detectedGenericPackages.length > 0 && missingGenericPackages.length > 0 && addCheck(report, {
2099
+ id: "package-json.sdk-generic-pair",
2100
+ title: "Generic SDK dependency pair",
2101
+ status: "warn",
2102
+ message: `Generic SDK dependency set is incomplete. Missing: ${missingGenericPackages.join(", ")}.`,
2103
+ action: "Generated generic React templates depend on both @weavix/sdk-core and @weavix/sdk-react.",
2104
+ data: {
2105
+ detected: detectedGenericPackages,
2106
+ missing: missingGenericPackages
2107
+ }
2108
+ });
2109
+ return;
2110
+ }
2111
+ addCheck(report, {
2112
+ id: "package-json.sdk-dependency",
2113
+ title: "Plugin SDK dependency",
2114
+ status: "warn",
2115
+ message: "No common plugin SDK package was found in dependencies.",
2116
+ action: "Add @weavix/sdk-core + @weavix/sdk-react for generic plugins, or @weavix/tracker-plugin-sdk-react for Tracker plugins."
2117
+ });
2118
+ }
2119
+ function checkPackageJson(report, projectRoot) {
2120
+ let result = readPackageJson(projectRoot);
2121
+ if (!result.packageJson) {
2122
+ addCheck(report, {
2123
+ id: "package-json.valid",
2124
+ title: "package.json",
2125
+ status: "fail",
2126
+ message: result.error || "package.json cannot be read.",
2127
+ action: `Create a valid package.json at ${result.path}.`
2128
+ });
2129
+ return;
2130
+ }
2131
+ return addCheck(report, {
2132
+ id: "package-json.valid",
2133
+ title: "package.json",
2134
+ message: `Found valid package.json at ${result.path}.`
2135
+ }), typeof result.packageJson.packageManager == "string" ? addCheck(report, {
2136
+ id: "package-json.package-manager",
2137
+ title: "Pinned package manager",
2138
+ message: `packageManager is ${result.packageJson.packageManager}.`
2139
+ }) : addCheck(report, {
2140
+ id: "package-json.package-manager",
2141
+ title: "Pinned package manager",
2142
+ status: "warn",
2143
+ message: "packageManager is missing. CLI will fall back to lockfiles or npm.",
2144
+ action: 'Add packageManager, for example "npm@11.6.4".'
2145
+ }), checkScript(report, result.packageJson, "build", !0), checkScript(report, result.packageJson, "lint", !0), checkScript(report, result.packageJson, "dev", !1), checkScript(report, result.packageJson, "typecheck", !1), checkScript(report, result.packageJson, "test", !1), checkPluginSdkDependency(report, result.packageJson), result.packageJson;
2146
+ }
2147
+ function checkPackageManager(report, projectRoot) {
2148
+ let projectPackageManager = detectPackageManager(projectRoot);
2149
+ report.packageManager = projectPackageManager, projectPackageManager !== CLI_PACKAGE_MANAGER && addCheck(report, {
2150
+ id: "package-manager.cli-compat",
2151
+ title: "CLI package manager compatibility",
2152
+ status: "warn",
2153
+ message: `Detected ${projectPackageManager}, but existing CLI build/debug/submit commands run ${CLI_PACKAGE_MANAGER}.`,
2154
+ action: "Use npm for generated plugins until CLI command execution is made package-manager aware.",
2155
+ data: {
2156
+ packageManager: projectPackageManager,
2157
+ cliPackageManager: CLI_PACKAGE_MANAGER
2158
+ }
2159
+ });
2160
+ try {
2161
+ let executable = resolvePackageManagerExecutable(CLI_PACKAGE_MANAGER);
2162
+ addCheck(report, {
2163
+ id: "package-manager.executable",
2164
+ title: "CLI package manager executable",
2165
+ message: `CLI commands run ${[executable.command, ...executable.argsPrefix].join(
2166
+ " "
2167
+ )}.`,
2168
+ data: {
2169
+ packageManager: projectPackageManager,
2170
+ cliPackageManager: CLI_PACKAGE_MANAGER,
2171
+ executable
2172
+ }
2173
+ }), addPackageManagerRuntimeCheck(
2174
+ report,
2175
+ runPackageManagerRuntimeCheck(projectRoot, CLI_PACKAGE_MANAGER, executable)
2176
+ );
2177
+ } catch (error2) {
2178
+ addCheck(report, {
2179
+ id: "package-manager.executable",
2180
+ title: "CLI package manager executable",
2181
+ status: "fail",
2182
+ message: getErrorMessage(error2),
2183
+ action: getPackageManagerInstallAction(CLI_PACKAGE_MANAGER),
2184
+ data: {
2185
+ packageManager: projectPackageManager,
2186
+ cliPackageManager: CLI_PACKAGE_MANAGER
2187
+ }
2188
+ });
2189
+ }
2190
+ }
2191
+ var import_fs6, import_path6, CLI_PACKAGE_MANAGER, COMMON_SDK_PACKAGES, GENERIC_SDK_PACKAGES, init_packageChecks = __esm({
2192
+ "src/core/doctor/packageChecks.ts"() {
2193
+ "use strict";
2194
+ import_fs6 = __toESM(require("fs")), import_path6 = __toESM(require("path"));
2195
+ init_packageManager();
2196
+ init_helpers();
2197
+ init_report();
2198
+ CLI_PACKAGE_MANAGER = "npm", COMMON_SDK_PACKAGES = [
2199
+ "@weavix/sdk-core",
2200
+ "@weavix/sdk-react",
2201
+ "@weavix/tracker-plugin-sdk",
2202
+ "@weavix/tracker-plugin-sdk-react",
2203
+ "@yandex-weavix/tracker-plugin-sdk-core",
2204
+ "@yandex-weavix/tracker-plugin-sdk-react"
2205
+ ], GENERIC_SDK_PACKAGES = ["@weavix/sdk-core", "@weavix/sdk-react"];
2206
+ }
2207
+ });
2208
+
2209
+ // src/utils/project.ts
2210
+ function resolveProjectRoot(startDir = process.cwd()) {
2211
+ let current = import_path7.default.resolve(startDir);
2212
+ for (; ; ) {
2213
+ if (import_fs7.default.existsSync(import_path7.default.join(current, MANIFEST_FILE)))
2214
+ return current;
2215
+ let parent = import_path7.default.dirname(current);
2216
+ if (parent === current)
2217
+ throw new Error(
2218
+ `Could not find ${MANIFEST_FILE}. Run this command inside a plugin project.`
2219
+ );
2220
+ current = parent;
2221
+ }
2222
+ }
2223
+ function getManifestPath(projectRoot = process.cwd()) {
2224
+ return import_path7.default.join(resolveProjectRoot(projectRoot), MANIFEST_FILE);
2225
+ }
2226
+ var import_fs7, import_path7, MANIFEST_FILE, init_project = __esm({
2227
+ "src/utils/project.ts"() {
2228
+ "use strict";
2229
+ import_fs7 = __toESM(require("fs")), import_path7 = __toESM(require("path")), MANIFEST_FILE = "manifest.json";
2230
+ }
2231
+ });
2232
+
2233
+ // src/core/doctor/projectChecks.ts
2234
+ function checkProjectRoot(report) {
2235
+ try {
2236
+ let projectRoot = resolveProjectRoot();
2237
+ return report.projectRoot = projectRoot, report.manifestPath = getManifestPath(projectRoot), addCheck(report, {
2238
+ id: "project-root.resolved",
2239
+ title: "Project root",
2240
+ message: `Found plugin project root at ${projectRoot}.`
2241
+ }), projectRoot;
2242
+ } catch (error2) {
2243
+ addCheck(report, {
2244
+ id: "project-root.resolved",
2245
+ title: "Project root",
2246
+ status: "fail",
2247
+ message: getErrorMessage(error2),
2248
+ action: "Run doctor inside a generated plugin project."
2249
+ });
2250
+ return;
2251
+ }
2252
+ }
2253
+ var init_projectChecks = __esm({
2254
+ "src/core/doctor/projectChecks.ts"() {
2255
+ "use strict";
2256
+ init_project();
2257
+ init_helpers();
2258
+ init_report();
2259
+ }
2260
+ });
2261
+
2262
+ // src/core/doctor/checks.ts
2263
+ async function runDoctorChecks(options) {
2264
+ let report = createDoctorReport(), policy = createDoctorPolicy(options);
2265
+ report.mode = policy.mode, checkNodeVersion(report);
2266
+ let projectRoot = checkProjectRoot(report);
2267
+ if (!projectRoot)
2268
+ return await checkDistribution2(report, void 0, options, policy), report;
2269
+ let { manifest, entries } = await checkManifest(report, report.manifestPath, policy);
2270
+ return checkPackageJson(report, projectRoot) && checkPackageManager(report, projectRoot), manifest && await checkDist(report, projectRoot, entries, policy), checkMarketplaceAssets(report, projectRoot, policy), await checkDistribution2(report, projectRoot, options, policy), report;
2271
+ }
2272
+ var init_checks = __esm({
2273
+ "src/core/doctor/checks.ts"() {
2274
+ "use strict";
2275
+ init_doctorChecks2();
2276
+ init_distChecks();
2277
+ init_manifestChecks();
2278
+ init_marketplaceChecks();
2279
+ init_nodeChecks();
2280
+ init_packageChecks();
2281
+ init_policy();
2282
+ init_projectChecks();
2283
+ init_report();
2284
+ }
2285
+ });
2286
+
2287
+ // src/commands/doctor/index.ts
2288
+ async function doctor(options = {}) {
2289
+ let report = await runDoctorChecks(options);
2290
+ await finishDoctor(report, options);
2291
+ }
2292
+ var init_doctor = __esm({
2293
+ "src/commands/doctor/index.ts"() {
2294
+ "use strict";
2295
+ init_checks();
2296
+ init_report();
2297
+ }
2298
+ });
2299
+
2300
+ // src/distributions/external/auth.ts
2301
+ var auth_exports = {};
2302
+ __export(auth_exports, {
2303
+ getAuthHeader: () => getAuthHeader,
2304
+ getPlatformHeaders: () => getPlatformHeaders
2305
+ });
2306
+ function getAuthHeader() {
2307
+ let token = externalAuthManager.token;
2308
+ return token ? `OAuth ${token}` : null;
2309
+ }
2310
+ function getPlatformHeaders() {
2311
+ let orgId = readConfig()?.api?.platformOrgId;
2312
+ return orgId ? { "X-Org-ID": orgId } : {};
2313
+ }
2314
+ var init_auth = __esm({
2315
+ "src/distributions/external/auth.ts"() {
2316
+ "use strict";
2317
+ init_manager();
2318
+ init_authManager();
2319
+ }
2320
+ });
2321
+
2322
+ // src/distribution/auth.ts
2323
+ var impl4, getAuthHeader2, getPlatformHeaders2, init_auth2 = __esm({
2324
+ "src/distribution/auth.ts"() {
2325
+ "use strict";
2326
+ init_flag();
2327
+ impl4 = (init_auth(), __toCommonJS(auth_exports)), { getAuthHeader: getAuthHeader2, getPlatformHeaders: getPlatformHeaders2 } = impl4;
2328
+ }
2329
+ });
2330
+
2331
+ // src/utils/verbose.ts
2332
+ function setVerboseEnabled(value) {
2333
+ verboseEnabled = value;
2334
+ }
2335
+ function isVerboseEnabled() {
2336
+ return verboseEnabled;
2337
+ }
2338
+ function writeVerboseArtifact(relativePath, content) {
2339
+ let targetPath = import_path8.default.resolve(".yaweavix-debug", relativePath);
2340
+ return import_fs8.default.mkdirSync(import_path8.default.dirname(targetPath), { recursive: !0 }), import_fs8.default.writeFileSync(targetPath, content), targetPath;
2341
+ }
2342
+ var import_fs8, import_path8, verboseEnabled, init_verbose = __esm({
2343
+ "src/utils/verbose.ts"() {
2344
+ "use strict";
2345
+ import_fs8 = __toESM(require("fs")), import_path8 = __toESM(require("path")), verboseEnabled = !1;
2346
+ }
2347
+ });
2348
+
2349
+ // src/utils/logger.ts
2350
+ function success(message) {
2351
+ console.info(import_picocolors.default.green(`\u2705 ${message}`)), newLine();
2352
+ }
2353
+ function error(messageOrErr, err) {
2354
+ let message = messageOrErr instanceof Error ? messageOrErr.message : messageOrErr;
2355
+ console.error(import_picocolors.default.red(`\u274C ${message}`)), err instanceof Error && console.error(import_picocolors.default.red(err.message)), newLine();
2356
+ }
2357
+ function warning(message) {
2358
+ console.warn(import_picocolors.default.yellow(`\u26A0\uFE0F ${message}`)), newLine();
2359
+ }
2360
+ function info(message) {
2361
+ console.info(message), newLine();
2362
+ }
2363
+ function verbose(message) {
2364
+ isVerboseEnabled() && (console.info(import_picocolors.default.dim(message)), newLine());
2365
+ }
2366
+ function suggest(command) {
2367
+ console.info(`Run: ${command}`), newLine();
2368
+ }
2369
+ function newLine(count = 1) {
2370
+ console.info(`
2371
+ `.repeat(count - 1));
2372
+ }
2373
+ function separator(char = "\u2500", length = 60) {
2374
+ console.info(import_picocolors.default.dim(char.repeat(length))), newLine();
2375
+ }
2376
+ function commands(title, data) {
2377
+ newLine(), title && (console.info(import_picocolors.default.bold(import_picocolors.default.cyan(`${title}:`))), newLine()), data.forEach((cmd) => {
2378
+ console.info(import_picocolors.default.dim(" $ ") + import_picocolors.default.white(cmd));
2379
+ }), newLine();
2380
+ }
2381
+ var import_picocolors, logger, logger_default, init_logger = __esm({
2382
+ "src/utils/logger.ts"() {
2383
+ "use strict";
2384
+ import_picocolors = __toESM(require("picocolors"));
2385
+ init_verbose();
2386
+ logger = {
2387
+ success,
2388
+ error,
2389
+ warning,
2390
+ info,
2391
+ verbose,
2392
+ suggest,
2393
+ newLine,
2394
+ separator,
2395
+ commands
2396
+ }, logger_default = logger;
2397
+ }
2398
+ });
2399
+
2400
+ // src/distribution/hosts.ts
2401
+ var impl5, getS3Endpoint2, getMdsEndpoint2, getS3Region2, getBuckets2, getPluginDownloadBase2, getPlatformBaseUrl2, getPlatformApiPrefix2, getTrackerBaseUrl2, getOAuthTokenUrl2, getUpdateCheckInfo2, init_hosts2 = __esm({
2402
+ "src/distribution/hosts.ts"() {
2403
+ "use strict";
2404
+ init_flag();
2405
+ impl5 = (init_hosts(), __toCommonJS(hosts_exports)), {
2406
+ getS3Endpoint: getS3Endpoint2,
2407
+ getMdsEndpoint: getMdsEndpoint2,
2408
+ getS3Region: getS3Region2,
2409
+ getBuckets: getBuckets2,
2410
+ getPluginDownloadBase: getPluginDownloadBase2,
2411
+ getPlatformBaseUrl: getPlatformBaseUrl2,
2412
+ getPlatformApiPrefix: getPlatformApiPrefix2,
2413
+ getTrackerBaseUrl: getTrackerBaseUrl2,
2414
+ getOAuthTokenUrl: getOAuthTokenUrl2,
2415
+ getUpdateCheckInfo: getUpdateCheckInfo2
2416
+ } = impl5;
2417
+ }
2418
+ });
2419
+
2420
+ // src/api/constants.ts
2421
+ var init_constants2 = __esm({
2422
+ "src/api/constants.ts"() {
2423
+ "use strict";
2424
+ init_hosts2();
2425
+ init_hosts2();
2426
+ }
2427
+ });
2428
+
2429
+ // src/api/requestDebug.ts
2430
+ function redactHeaders(headers) {
2431
+ let result = {};
2432
+ for (let [key, value] of Object.entries(headers))
2433
+ if (key.toLowerCase() === "authorization") {
2434
+ let [scheme] = value.split(" ");
2435
+ result[key] = scheme ? `${scheme} ${REDACTED}` : REDACTED;
2436
+ } else
2437
+ result[key] = value;
2438
+ return result;
2439
+ }
2440
+ function formatDebugBody(body, formData) {
2441
+ if (formData) {
2442
+ let size = "";
2443
+ try {
2444
+ let length = formData.getLengthSync?.();
2445
+ typeof length == "number" && (size = `, ~${length} bytes`);
2446
+ } catch {
2447
+ }
2448
+ return `[multipart/form-data${size}] (binary body, e.g. plugin archive \u2014 not dumped)`;
2449
+ }
2450
+ return typeof body == "string" ? body : "(none)";
2451
+ }
2452
+ function buildFailureDebug(params) {
2453
+ let { method, url, status, headers, body, formData } = params;
2454
+ return [
2455
+ "Platform API request failed \u2014 debug info (Authorization redacted):",
2456
+ ` method: ${method}`,
2457
+ ` url: ${url}`,
2458
+ ` status: ${status ?? "(no HTTP response \u2014 network/transport error)"}`,
2459
+ ` headers: ${JSON.stringify(redactHeaders(headers), null, 2)}`,
2460
+ ` body: ${formatDebugBody(body, formData)}`
2461
+ ].join(`
2462
+ `);
2463
+ }
2464
+ var REDACTED, init_requestDebug = __esm({
2465
+ "src/api/requestDebug.ts"() {
2466
+ "use strict";
2467
+ REDACTED = "****redacted****";
2468
+ }
2469
+ });
2470
+
2471
+ // src/api/platformApiRequest.ts
2472
+ function buildRequestHeaders(headers, formData) {
2473
+ let authHeader = getAuthHeader2();
2474
+ if (!authHeader)
2475
+ throw new Error(`Not authenticated. Run "${CLI_NAME2} login" first.`);
2476
+ let requestHeaders = {
2477
+ Accept: "*/*",
2478
+ Authorization: authHeader,
2479
+ ...getPlatformHeaders2(),
2480
+ ...headers
2481
+ };
2482
+ return formData || (requestHeaders["Content-Type"] = "application/json"), requestHeaders;
2483
+ }
2484
+ function buildRequestBody(method, body, formData) {
2485
+ if (formData) {
2486
+ let formHeaders = formData.getHeaders?.();
2487
+ return {
2488
+ body: formData,
2489
+ headers: formHeaders || {}
2490
+ };
2491
+ }
2492
+ return body && method !== "GET" ? { body: JSON.stringify(body) } : {};
2493
+ }
2494
+ function buildQueryString2(queryParams) {
2495
+ if (!queryParams || Object.keys(queryParams).length === 0)
2496
+ return "";
2497
+ let params = new URLSearchParams();
2498
+ return Object.entries(queryParams).forEach(([key, value]) => {
2499
+ params.append(key, String(value));
2500
+ }), `?${params.toString()}`;
2501
+ }
2502
+ async function parseResponse2(response) {
2503
+ 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();
2504
+ }
2505
+ async function platformApiRequest(endpoint, options = {}) {
2506
+ let { method = "GET", body, headers = {}, formData, queryParams } = options, requestHeaders = buildRequestHeaders(headers, formData), { body: requestBody, headers: additionalHeaders } = buildRequestBody(
2507
+ method,
2508
+ body,
2509
+ formData
2510
+ ), requestOptions = {
2511
+ method,
2512
+ headers: { ...requestHeaders, ...additionalHeaders },
2513
+ body: requestBody
2514
+ }, queryString = buildQueryString2(queryParams), url = `${getPlatformBaseUrl2()}${getPlatformApiPrefix2()}${endpoint}${queryString}`, controller = new AbortController(), timeout = setTimeout(() => controller.abort(), PLATFORM_API_TIMEOUT_MS), responseStatus;
2515
+ if (isVerboseEnabled() && (logger_default.info(
2516
+ `[platform-api-debug] Request: method=${method} url=${url} hasBody=${!!body} hasFormData=${!!formData} timeoutMs=${PLATFORM_API_TIMEOUT_MS}`
2517
+ ), body !== void 0 && logger_default.info(`[platform-api-debug] Request body: ${JSON.stringify(body)}`), formData)) {
2518
+ let debugPath = writeVerboseArtifact(
2519
+ "requests/latest-form-data.txt",
2520
+ `method=${method}
2521
+ url=${url}
2522
+ headers=${JSON.stringify({ ...requestHeaders, ...additionalHeaders }, null, 2)}
2523
+ formData=present
2524
+ `
2525
+ );
2526
+ logger_default.info(`[platform-api-debug] Saved form-data request metadata to ${debugPath}`);
2527
+ }
2528
+ try {
2529
+ let response = await (0, import_node_fetch2.default)(url, {
2530
+ ...requestOptions,
2531
+ signal: controller.signal
2532
+ });
2533
+ if (responseStatus = response.status, isVerboseEnabled() && logger_default.info(
2534
+ `[platform-api-debug] Response: method=${method} url=${url} status=${response.status} contentType=${response.headers.get("content-type") ?? "n/a"}`
2535
+ ), !response.ok) {
2536
+ let errorText = await response.text(), errorMessage = errorText;
2537
+ try {
2538
+ let errorJson = JSON.parse(errorText);
2539
+ errorJson.message && (errorMessage = errorJson.message);
2540
+ } catch {
2541
+ }
2542
+ throw new Error(`HTTP ${response.status} ${response.statusText}: ${errorMessage}`);
2543
+ }
2544
+ return parseResponse2(response);
2545
+ } catch (error2) {
2546
+ throw logger_default.error(
2547
+ buildFailureDebug({
2548
+ method,
2549
+ url,
2550
+ status: responseStatus,
2551
+ headers: requestOptions.headers,
2552
+ body: requestBody,
2553
+ formData
2554
+ })
2555
+ ), error2 instanceof Error && error2.name === "AbortError" ? new Error(
2556
+ `Platform API request timed out after ${PLATFORM_API_TIMEOUT_MS}ms: ${method} ${url}`
2557
+ ) : error2;
2558
+ } finally {
2559
+ clearTimeout(timeout);
2560
+ }
2561
+ }
2562
+ var import_node_fetch2, PLATFORM_API_TIMEOUT_MS, init_platformApiRequest = __esm({
2563
+ "src/api/platformApiRequest.ts"() {
2564
+ "use strict";
2565
+ import_node_fetch2 = __toESM(require("node-fetch"));
2566
+ init_auth2();
2567
+ init_meta2();
2568
+ init_logger();
2569
+ init_verbose();
2570
+ init_constants2();
2571
+ init_requestDebug();
2572
+ PLATFORM_API_TIMEOUT_MS = Number(process.env.TRACKER_CLI_PLATFORM_TIMEOUT_MS || 3e4);
2573
+ }
2574
+ });
2575
+
2576
+ // src/api/platform.ts
2577
+ async function createPlugin(archiveBuffer, archiveName) {
2578
+ let formData = new import_form_data.default();
2579
+ return formData.append("archive", archiveBuffer, {
2580
+ filename: archiveName,
2581
+ contentType: "application/zip"
2582
+ }), platformApiRequest("/plugins", {
2583
+ method: "POST",
2584
+ formData
2585
+ });
2586
+ }
2587
+ async function updatePluginArchive(pluginId, archiveBuffer, archiveName) {
2588
+ let formData = new import_form_data.default();
2589
+ return formData.append("archive", archiveBuffer, {
2590
+ filename: archiveName,
2591
+ contentType: "application/zip"
2592
+ }), platformApiRequest(`/plugins/${pluginId}/archive`, {
2593
+ method: "PUT",
2594
+ formData
2595
+ });
2596
+ }
2597
+ async function updateCatalogEntry(pluginId, catalogData) {
2598
+ return platformApiRequest(`/plugins/${pluginId}/catalog-entry`, {
2599
+ method: "PUT",
2600
+ body: catalogData
2601
+ });
2602
+ }
2603
+ async function updateCatalogImage(pluginId, imageBuffer, imageName) {
2604
+ let formData = new import_form_data.default();
2605
+ return formData.append("image", imageBuffer, {
2606
+ filename: imageName,
2607
+ contentType: "image/jpeg"
2608
+ }), platformApiRequest(`/plugins/${pluginId}/catalog-image`, {
2609
+ method: "PUT",
2610
+ formData
2611
+ });
2612
+ }
2613
+ async function submitPlugin(pluginId, version) {
2614
+ return platformApiRequest(`/plugins/${pluginId}/submit`, {
2615
+ method: "POST",
2616
+ queryParams: {
2617
+ version
2618
+ }
2619
+ });
2620
+ }
2621
+ async function getPluginInfo(pluginId) {
2622
+ return platformApiRequest(`/plugins/${pluginId}`, {
2623
+ method: "GET"
2624
+ });
2625
+ }
2626
+ async function getMyPlugins() {
2627
+ return platformApiRequest("/plugins/my", {
2628
+ method: "GET"
2629
+ });
2630
+ }
2631
+ async function checkSlugAvailability(slug) {
2632
+ return platformApiRequest(`/slugs/${slug}/available`, {
2633
+ method: "GET"
2634
+ });
2635
+ }
2636
+ var import_form_data, init_platform = __esm({
2637
+ "src/api/platform.ts"() {
2638
+ "use strict";
2639
+ import_form_data = __toESM(require("form-data"));
2640
+ init_platformApiRequest();
2641
+ }
2642
+ });
2643
+
2644
+ // src/utils/getPluginId.ts
2645
+ async function getPluginId(pluginId) {
2646
+ if (pluginId)
2647
+ return pluginId;
2648
+ try {
2649
+ let manifest = await manifestManager.load();
2650
+ if (!manifest.id)
2651
+ throw new Error("Plugin ID not found in manifest.json");
2652
+ return manifest.id;
2653
+ } catch {
2654
+ throw new Error("Plugin ID must be provided as argument or present in manifest.json");
2655
+ }
2656
+ }
2657
+ var init_getPluginId = __esm({
2658
+ "src/utils/getPluginId.ts"() {
2659
+ "use strict";
2660
+ init_manifestManager();
2661
+ }
2662
+ });
2663
+
2664
+ // src/api/utils.ts
2665
+ var init_utils = __esm({
2666
+ "src/api/utils.ts"() {
2667
+ "use strict";
2668
+ }
2669
+ });
2670
+
2671
+ // src/utils/pluginDisplay.ts
2672
+ function showPluginInfo(data) {
2673
+ printHeader("\u{1F4E6} Plugin"), logger_default.newLine(), printPluginId(data.id), printField("Slug", import_picocolors2.default.magenta(data.slug)), printField("Name", import_picocolors2.default.white(data.name)), printField("Status", getStatusBadgeByLabel(data.status.toUpperCase())), data.moderationTicketKey && printField("Moderation", import_picocolors2.default.cyan(data.moderationTicketKey)), data.createdAt && printCreated(data.createdAt), data.updatedAt && printUpdated(data.updatedAt);
2674
+ }
2675
+ function showPluginVersions(versions) {
2676
+ if (!versions || versions.length === 0) {
2677
+ console.info(import_picocolors2.default.dim(" No versions found")), logger_default.newLine();
2678
+ return;
2679
+ }
2680
+ printHeader(`\u{1F9FE} Versions \xB7 ${versions.length}`), logger_default.newLine(), versions.forEach((version, index) => {
2681
+ console.info(` ${import_picocolors2.default.bold(String(index + 1) + ".")} ${import_picocolors2.default.cyan(version.versionId)}`), printField("Status", getStatusBadgeByLabel(version.status.toUpperCase())), printField("Version", import_picocolors2.default.white(version.version)), printCreated(version.createdAt), logger_default.newLine();
2682
+ });
2683
+ }
2684
+ function showPluginList(plugins) {
2685
+ if (!plugins || plugins.length === 0) {
2686
+ console.info(import_picocolors2.default.dim(" No plugins found")), logger_default.newLine();
2687
+ return;
2688
+ }
2689
+ printHeader(`\u{1F4CB} Your Plugins \xB7 ${plugins.length}`), logger_default.newLine(), plugins.forEach((plugin) => {
2690
+ console.info(
2691
+ ` ${import_picocolors2.default.magenta(plugin.slug)} ${import_picocolors2.default.dim("\xB7")} ${getStatusBadgeByLabel(plugin.status.toUpperCase())} ${import_picocolors2.default.dim("\xB7")} ${import_picocolors2.default.cyan(plugin.id)}`
2692
+ ), logger_default.newLine();
2693
+ });
2694
+ }
2695
+ function showPluginCreated(data) {
2696
+ printSuccessHeader("\u2705 Plugin Created"), logger_default.newLine(), printPluginId(data.id);
2697
+ }
2698
+ var import_picocolors2, printHeader, printSuccessHeader, getStatusBadgeByLabel, formatDate, printField, printPluginId, printCreated, printUpdated, init_pluginDisplay = __esm({
2699
+ "src/utils/pluginDisplay.ts"() {
2700
+ "use strict";
2701
+ import_picocolors2 = __toESM(require("picocolors"));
2702
+ init_utils();
2703
+ init_logger();
2704
+ printHeader = (title) => {
2705
+ console.info(import_picocolors2.default.bold(import_picocolors2.default.white(title)));
2706
+ }, printSuccessHeader = (title) => {
2707
+ console.info(import_picocolors2.default.bold(import_picocolors2.default.green(title)));
2708
+ }, getStatusBadgeByLabel = (label) => {
2709
+ let normalized = label.toLowerCase();
2710
+ return normalized.includes("approved") ? import_picocolors2.default.black(import_picocolors2.default.bgGreen(` ${label} `)) : normalized.includes("pending") || normalized.includes("review") ? import_picocolors2.default.black(import_picocolors2.default.bgYellow(` ${label} `)) : normalized.includes("rejected") ? import_picocolors2.default.white(import_picocolors2.default.bgRed(` ${label} `)) : normalized.includes("draft") || normalized.includes("unknown") ? import_picocolors2.default.black(import_picocolors2.default.bgWhite(` ${label} `)) : import_picocolors2.default.black(import_picocolors2.default.bgBlue(` ${label} `));
2711
+ }, formatDate = (dateString) => dateString ? new Date(dateString).toLocaleString("ru-RU", {
2712
+ year: "numeric",
2713
+ month: "2-digit",
2714
+ day: "2-digit",
2715
+ hour: "2-digit",
2716
+ minute: "2-digit"
2717
+ }) : "-", printField = (label, value, minWidth = 12) => {
2718
+ console.info(` ${import_picocolors2.default.dim(label.padEnd(minWidth))} ${value}`);
2719
+ }, printPluginId = (pluginId) => {
2720
+ printField("Plugin ID", import_picocolors2.default.cyan(pluginId));
2721
+ }, printCreated = (createdAt) => {
2722
+ printField("Created", import_picocolors2.default.white(formatDate(createdAt)));
2723
+ }, printUpdated = (updatedAt) => {
2724
+ printField("Updated", import_picocolors2.default.white(formatDate(updatedAt)));
2725
+ };
2726
+ }
2727
+ });
2728
+
2729
+ // src/commands/info/platform.ts
2730
+ async function infoPlatform(pluginId) {
2731
+ let actualPluginId = await getPluginId(pluginId);
2732
+ logger_default.info(`\u23F3 Fetching plugin info for ID: ${actualPluginId}...`);
2733
+ try {
2734
+ let pluginInfo = await getPluginInfo(actualPluginId);
2735
+ showPluginInfo(pluginInfo), pluginInfo.versions && pluginInfo.versions.length > 0 && (logger_default.newLine(), showPluginVersions(pluginInfo.versions));
2736
+ } catch (error2) {
2737
+ throw logger_default.error(`Failed to fetch plugin info for ID: ${actualPluginId}`), error2;
2738
+ }
2739
+ }
2740
+ var init_platform2 = __esm({
2741
+ "src/commands/info/platform.ts"() {
2742
+ "use strict";
2743
+ init_platform();
2744
+ init_getPluginId();
2745
+ init_logger();
2746
+ init_pluginDisplay();
2747
+ }
2748
+ });
2749
+
2750
+ // src/commands/list/platform.ts
2751
+ async function listPlatform() {
2752
+ logger_default.info("\u23F3 Fetching my plugins...");
2753
+ try {
2754
+ let plugins = await getMyPlugins();
2755
+ showPluginList(plugins);
2756
+ } catch (error2) {
2757
+ throw logger_default.error("Failed to fetch plugins list"), error2;
2758
+ }
2759
+ }
2760
+ var init_platform3 = __esm({
2761
+ "src/commands/list/platform.ts"() {
2762
+ "use strict";
2763
+ init_platform();
2764
+ init_logger();
2765
+ init_pluginDisplay();
2766
+ }
2767
+ });
2768
+
2769
+ // src/commands/submit/options.ts
2770
+ var import_commander, skipChecksOption, init_options = __esm({
2771
+ "src/commands/submit/options.ts"() {
2772
+ "use strict";
2773
+ import_commander = require("commander"), skipChecksOption = new import_commander.Option(
2774
+ "--skip-checks",
2775
+ "skip pre-submit validation (manifest, assets, lint, typecheck, tests, audit)"
2776
+ );
2777
+ }
2778
+ });
2779
+
2780
+ // src/utils/marketplace.ts
2781
+ function validateMarketplaceAssets() {
2782
+ let marketplaceDir = import_path9.default.resolve(MARKETPLACE_DIR);
2783
+ ensurePathExists(
2784
+ marketplaceDir,
2785
+ "Marketplace folder not found. Create ./marketplace and add index.md and header-image.jpg before publishing."
2786
+ ), ensurePathExists(
2787
+ import_path9.default.join(marketplaceDir, MARKETPLACE_INDEX_FILE),
2788
+ "Marketplace description not found. Add ./marketplace/index.md before publishing."
2789
+ ), ensurePathExists(
2790
+ import_path9.default.join(marketplaceDir, MARKETPLACE_HEADER_IMAGE_FILE),
2791
+ "Marketplace header image not found. Add ./marketplace/header-image.jpg before publishing."
2792
+ ), ensurePathExists(
2793
+ import_path9.default.resolve(PUBLIC_DIR, PUBLIC_LOGO_FILE),
2794
+ "Plugin logo not found. Add ./public/logo.svg before publishing."
2795
+ );
2796
+ }
2797
+ function validateArchiveSources() {
2798
+ ensurePathExists(import_path9.default.resolve(DIST_DIR), "Dist folder not found. Build the project first."), ensurePathExists(
2799
+ import_path9.default.resolve(SRC_DIR),
2800
+ "Source folder not found. Add ./src before publishing."
2801
+ ), ensurePathExists(import_path9.default.resolve(MANIFEST_FILE2), "manifest.json not found in plugin root."), validateMarketplaceAssets();
2802
+ }
2803
+ async function getMarketplaceCatalogEntry() {
2804
+ let indexPath = import_path9.default.resolve(MARKETPLACE_DIR, MARKETPLACE_INDEX_FILE);
2805
+ ensurePathExists(
2806
+ indexPath,
2807
+ "Marketplace description not found. Add ./marketplace/index.md before uploading."
2808
+ ), await validateManifestPublishingFields();
2809
+ let longDescription = import_fs9.default.readFileSync(indexPath, "utf-8").trim(), manifest = await manifestManager.load();
2810
+ return {
2811
+ name: manifest.name.ru,
2812
+ description: manifest.description.ru,
2813
+ longDescription,
2814
+ tags: manifest.keywords ?? []
2815
+ };
2816
+ }
2817
+ function getMarketplaceHeaderImage() {
2818
+ let imagePath = import_path9.default.resolve(MARKETPLACE_DIR, MARKETPLACE_HEADER_IMAGE_FILE);
2819
+ return ensurePathExists(
2820
+ imagePath,
2821
+ "Marketplace header image not found. Add ./marketplace/header-image.jpg before uploading."
2822
+ ), {
2823
+ buffer: import_fs9.default.readFileSync(imagePath),
2824
+ filename: MARKETPLACE_HEADER_IMAGE_FILE
2825
+ };
2826
+ }
2827
+ var import_fs9, import_path9, MARKETPLACE_DIR, MARKETPLACE_INDEX_FILE, MARKETPLACE_HEADER_IMAGE_FILE, PUBLIC_DIR, PUBLIC_LOGO_FILE, MANIFEST_FILE2, DIST_DIR, SRC_DIR, ensurePathExists, validateManifestPublishingFields, ensureManifestCatalogFields, marketplacePaths, init_marketplace = __esm({
2828
+ "src/utils/marketplace.ts"() {
2829
+ "use strict";
2830
+ import_fs9 = __toESM(require("fs")), import_path9 = __toESM(require("path"));
2831
+ init_manifestManager();
2832
+ init_logger();
2833
+ MARKETPLACE_DIR = "marketplace", MARKETPLACE_INDEX_FILE = "index.md", MARKETPLACE_HEADER_IMAGE_FILE = "header-image.jpg", PUBLIC_DIR = "public", PUBLIC_LOGO_FILE = "logo.svg", MANIFEST_FILE2 = "manifest.json", DIST_DIR = "dist", SRC_DIR = "src", ensurePathExists = (targetPath, errorMessage) => {
2834
+ import_fs9.default.existsSync(targetPath) || (logger_default.error(errorMessage), process.exit(1));
2835
+ }, validateManifestPublishingFields = async () => {
2836
+ let manifest = await manifestManager.load();
2837
+ ensureManifestCatalogFields(manifest);
2838
+ }, ensureManifestCatalogFields = (manifest) => {
2839
+ (!manifest.name?.ru || !manifest.name?.en) && (logger_default.error(
2840
+ 'Manifest field "name" is required for publishing. Add localized "name.ru" and "name.en" to ./manifest.json.'
2841
+ ), process.exit(1)), (!manifest.description?.ru || !manifest.description?.en) && (logger_default.error(
2842
+ 'Manifest field "description" is required for publishing. Add localized "description.ru" and "description.en" to ./manifest.json.'
2843
+ ), process.exit(1));
2844
+ };
2845
+ marketplacePaths = {
2846
+ distDir: DIST_DIR,
2847
+ srcDir: SRC_DIR,
2848
+ marketplaceDir: MARKETPLACE_DIR,
2849
+ manifestFile: MANIFEST_FILE2
2850
+ };
2851
+ }
2852
+ });
2853
+
2854
+ // src/utils/buildArchive.ts
2855
+ async function buildArchive() {
2856
+ return validateArchiveSources(), (await manifestManager.load()).manifest_version === void 0 && (logger_default.error(
2857
+ `manifest_version is missing in manifest.json. Run "${CLI_NAME2} up" or add "manifest_version": 1 manually before uploading.`
2858
+ ), process.exit(1)), new Promise((resolve2, reject) => {
2859
+ let archive = (0, import_archiver.default)("zip", { zlib: { level: 9 } }), chunks = [];
2860
+ archive.on("data", (chunk) => chunks.push(chunk)), archive.on("end", () => {
2861
+ let buffer = Buffer.concat(chunks);
2862
+ if (logger_default.info(`\u{1F4E6} Archive created (${buffer.length} bytes)`), isVerboseEnabled()) {
2863
+ let debugPath = writeVerboseArtifact("archive/latest-upload.zip", buffer);
2864
+ logger_default.info(`[platform-api-debug] Saved archive copy to ${debugPath}`);
2865
+ }
2866
+ resolve2(buffer);
2867
+ }), archive.on("error", reject), archive.glob("**/*", {
2868
+ cwd: process.cwd(),
2869
+ ignore: ["node_modules/**", "dist/**"],
2870
+ dot: !1
2871
+ });
2872
+ for (let dotfile of [".npmrc", ".nvmrc"]) {
2873
+ let dotfilePath = import_path10.default.resolve(dotfile);
2874
+ import_fs10.default.existsSync(dotfilePath) && archive.file(dotfilePath, { name: dotfile });
2875
+ }
2876
+ archive.file(import_path10.default.resolve(marketplacePaths.manifestFile), { name: "src/manifest.json" }), archive.glob(
2877
+ "**/*",
2878
+ {
2879
+ cwd: import_path10.default.resolve(marketplacePaths.distDir),
2880
+ dot: !1
2881
+ },
2882
+ { prefix: "dist/" }
2883
+ ), archive.finalize();
2884
+ });
2885
+ }
2886
+ var import_fs10, import_path10, import_archiver, init_buildArchive = __esm({
2887
+ "src/utils/buildArchive.ts"() {
2888
+ "use strict";
2889
+ import_fs10 = __toESM(require("fs")), import_path10 = __toESM(require("path")), import_archiver = __toESM(require("archiver"));
2890
+ init_manifestManager();
2891
+ init_meta2();
2892
+ init_logger();
2893
+ init_marketplace();
2894
+ init_verbose();
2895
+ }
2896
+ });
2897
+
2898
+ // src/utils/execCommand.ts
2899
+ var import_execa, execCommand, init_execCommand = __esm({
2900
+ "src/utils/execCommand.ts"() {
2901
+ "use strict";
2902
+ import_execa = require("execa"), execCommand = async (command, cwd = process.cwd(), env) => {
2903
+ await (0, import_execa.execa)(command, {
2904
+ cwd,
2905
+ shell: !0,
2906
+ stdio: "inherit",
2907
+ env: env ? { ...process.env, ...env } : void 0
2908
+ });
2909
+ };
2910
+ }
2911
+ });
2912
+
2913
+ // src/commands/constants/templateCommands.ts
2914
+ function getPluginCommands(projectRoot = process.cwd()) {
2915
+ return COMMANDS[detectPackageManager(projectRoot)];
2916
+ }
2917
+ var COMMANDS, pluginCmd, init_templateCommands = __esm({
2918
+ "src/commands/constants/templateCommands.ts"() {
2919
+ "use strict";
2920
+ init_packageManager();
2921
+ COMMANDS = {
2922
+ npm: {
2923
+ install: "npm install",
2924
+ build: "npm run build",
2925
+ dev: "npm run dev",
2926
+ lint: "npm run lint",
2927
+ typecheck: "npm run typecheck",
2928
+ test: "npm test",
2929
+ audit: "npm audit --audit-level=critical"
2930
+ },
2931
+ pnpm: {
2932
+ install: "pnpm install",
2933
+ build: "pnpm run build",
2934
+ dev: "pnpm run dev",
2935
+ lint: "pnpm run lint",
2936
+ typecheck: "pnpm run typecheck",
2937
+ test: "pnpm test",
2938
+ audit: "pnpm audit --audit-level=critical"
2939
+ }
2940
+ };
2941
+ pluginCmd = COMMANDS.npm;
2942
+ }
2943
+ });
2944
+
2945
+ // src/commands/build.ts
2946
+ var build, init_build = __esm({
2947
+ "src/commands/build.ts"() {
2948
+ "use strict";
2949
+ init_execCommand();
2950
+ init_logger();
2951
+ init_templateCommands();
2952
+ build = async ({ environment = "production" } = {}) => {
2953
+ logger_default.info("\u{1F528} Building project...");
2954
+ let pluginCmd2 = getPluginCommands();
2955
+ await execCommand(pluginCmd2.install), await execCommand(
2956
+ pluginCmd2.build,
2957
+ process.cwd(),
2958
+ environment ? { VITE_DEPLOY_ENV: environment } : void 0
2959
+ );
2960
+ };
2961
+ }
2962
+ });
2963
+
2964
+ // src/utils/pluginPackageScripts.ts
2965
+ function readPluginPackageScripts(cwd = process.cwd()) {
2966
+ let packageJsonPath = import_path11.default.join(cwd, "package.json");
2967
+ return import_fs11.default.existsSync(packageJsonPath) ? JSON.parse(import_fs11.default.readFileSync(packageJsonPath, "utf-8")).scripts ?? {} : null;
2968
+ }
2969
+ function hasPluginScript(name, cwd = process.cwd()) {
2970
+ return !!readPluginPackageScripts(cwd)?.[name];
2971
+ }
2972
+ var import_fs11, import_path11, init_pluginPackageScripts = __esm({
2973
+ "src/utils/pluginPackageScripts.ts"() {
2974
+ "use strict";
2975
+ import_fs11 = __toESM(require("fs")), import_path11 = __toESM(require("path"));
2976
+ }
2977
+ });
2978
+
2979
+ // src/commands/submit/utils/runSubmitPrechecks.ts
2980
+ async function runSubmitPrechecks(options = {}) {
2981
+ if (options.skip) {
2982
+ logger_default.warning("Skipping pre-submit checks (--skip-checks).");
2983
+ return;
2984
+ }
2985
+ logger_default.separator(), logger_default.info("\u{1F50D} Pre-submit checks"), logger_default.separator();
2986
+ let pluginCmd2 = getPluginCommands();
2987
+ await runStep("Validate manifest.json", () => manifestManager.validate()), await runStep("Check publishing metadata and assets", async () => {
2988
+ await validateManifestPublishingFields(), validateMarketplaceAssets();
2989
+ }), await runShellStep("Install dependencies", pluginCmd2.install), await runShellStep("Run linter", pluginCmd2.lint), hasPluginScript("typecheck") ? await runShellStep("Run typecheck", pluginCmd2.typecheck) : logger_default.verbose('Skipping typecheck (no "typecheck" script in package.json).'), hasPluginScript("test") ? await runShellStep("Run tests", pluginCmd2.test) : logger_default.warning(
2990
+ 'No "test" script in package.json \u2014 add tests before publishing, or run submit with --skip-checks.'
2991
+ ), await runShellStep("Check dependency vulnerabilities", pluginCmd2.audit), logger_default.separator(), logger_default.success("Pre-submit checks passed"), logger_default.separator();
2992
+ }
2993
+ var import_picocolors3, stepStart, stepDone, runStep, runShellStep, init_runSubmitPrechecks = __esm({
2994
+ "src/commands/submit/utils/runSubmitPrechecks.ts"() {
2995
+ "use strict";
2996
+ import_picocolors3 = __toESM(require("picocolors"));
2997
+ init_manifestManager();
2998
+ init_execCommand();
2999
+ init_logger();
3000
+ init_marketplace();
3001
+ init_pluginPackageScripts();
3002
+ init_templateCommands();
3003
+ stepStart = (label) => {
3004
+ console.info(`${import_picocolors3.default.cyan("\u25B8")} ${label}`);
3005
+ }, stepDone = (label) => {
3006
+ console.info(`${import_picocolors3.default.green("\u2713")} ${label}`), console.info("");
3007
+ }, runStep = async (label, run) => {
3008
+ stepStart(label), await run(), stepDone(label);
3009
+ }, runShellStep = async (label, command) => {
3010
+ stepStart(label), console.info(import_picocolors3.default.dim(` $ ${command}`)), await execCommand(command), stepDone(label);
3011
+ };
3012
+ }
3013
+ });
3014
+
3015
+ // src/commands/submit/utils/validateSlug.ts
3016
+ function promptForSlug() {
3017
+ return new Promise((resolve2) => {
3018
+ let rl = readline.createInterface({
3019
+ input: process.stdin,
3020
+ output: process.stdout
3021
+ });
3022
+ rl.question("Enter a new slug: ", (answer) => {
3023
+ rl.close(), resolve2(answer.trim());
3024
+ });
3025
+ });
3026
+ }
3027
+ async function validateAndGetUniqueSlug(currentSlug) {
3028
+ let slugToCheck = currentSlug, isValid = !1;
3029
+ for (; !isValid; )
3030
+ try {
3031
+ if ((await checkSlugAvailability(slugToCheck)).available)
3032
+ return isValid = !0, slugToCheck;
3033
+ 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);
3034
+ } catch (error2) {
3035
+ throw logger_default.error(`Failed to check slug availability: ${error2.message}`), error2;
3036
+ }
3037
+ return slugToCheck;
3038
+ }
3039
+ var readline, init_validateSlug = __esm({
3040
+ "src/commands/submit/utils/validateSlug.ts"() {
3041
+ "use strict";
3042
+ readline = __toESM(require("readline"));
3043
+ init_platform();
3044
+ init_logger();
3045
+ }
3046
+ });
3047
+
3048
+ // src/commands/submit/platform.ts
3049
+ async function submitPlatform(options = {}) {
3050
+ await runSubmitPrechecks({ skip: options.skipChecks });
3051
+ let manifest = await manifestManager.load();
3052
+ await build(), logger_default.info("\u{1F4E6} Creating archive...");
3053
+ let archiveBuffer = await buildArchive(), archiveName = `${manifest.slug}-${manifest.version}.zip`, pluginId;
3054
+ if (manifest.id)
3055
+ pluginId = manifest.id, logger_default.info("\u{1F4E4} Updating plugin archive..."), await updatePluginArchive(pluginId, archiveBuffer, archiveName);
3056
+ else {
3057
+ let validatedSlug = await validateAndGetUniqueSlug(manifest.slug);
3058
+ validatedSlug !== manifest.slug && await manifestManager.update({ slug: validatedSlug }), logger_default.info("\u23F3 Creating plugin...");
3059
+ let createdPlugin = await createPlugin(archiveBuffer, archiveName);
3060
+ showPluginCreated(createdPlugin), pluginId = createdPlugin.id, await manifestManager.update({ id: pluginId });
3061
+ }
3062
+ let catalogEntry = await getMarketplaceCatalogEntry();
3063
+ logger_default.info("\u{1F4DD} Updating catalog entry from ./marketplace/index.md..."), await updateCatalogEntry(pluginId, catalogEntry);
3064
+ let headerImage = getMarketplaceHeaderImage();
3065
+ logger_default.info("\u{1F5BC}\uFE0F Uploading catalog image from ./marketplace/header-image.jpg..."), await updateCatalogImage(pluginId, headerImage.buffer, headerImage.filename), await submitPlugin(pluginId, manifest.version), logger_default.success("Plugin submitted for review!"), logger_default.info(` Version : ${manifest.version}`), logger_default.newLine();
3066
+ }
3067
+ var init_platform4 = __esm({
3068
+ "src/commands/submit/platform.ts"() {
3069
+ "use strict";
3070
+ init_platform();
3071
+ init_manifestManager();
3072
+ init_buildArchive();
3073
+ init_logger();
3074
+ init_marketplace();
3075
+ init_pluginDisplay();
3076
+ init_build();
3077
+ init_runSubmitPrechecks();
3078
+ init_validateSlug();
3079
+ }
3080
+ });
3081
+
3082
+ // src/core/cliConfig/registerCommand.ts
3083
+ async function promptString(message, current) {
3084
+ return (await (0, import_prompts.input)({
3085
+ message: current ? `${message} (current: ${current})` : `${message} (optional)`,
3086
+ default: current,
3087
+ required: !1
3088
+ }))?.trim() || void 0;
3089
+ }
3090
+ async function runConfigSet(cliName) {
3091
+ let existing = readConfig() ?? {};
3092
+ logger_default.info(
3093
+ "Configure CLI overrides. Empty input clears the value (and falls back to defaults where applicable)."
3094
+ );
3095
+ 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(
3096
+ "Production bucket (static)",
3097
+ existing.buckets?.production?.static
3098
+ ), productionConfig = await promptString(
3099
+ "Production bucket (config)",
3100
+ existing.buckets?.production?.config
3101
+ ), pluginDownloadProduction = await promptString(
3102
+ "Plugin download base URL",
3103
+ existing.pluginDownloadBase?.production
3104
+ ), platformBaseUrl = await promptString(
3105
+ "Platform API base URL",
3106
+ existing.api?.platformBaseUrl
3107
+ ), oauthUrl = await promptString("OAuth token URL", existing.auth?.oauthUrl);
3108
+ writeConfig({
3109
+ s3: { endpoint: s3Endpoint, region: s3Region },
3110
+ mds: { endpoint: mdsEndpoint },
3111
+ buckets: {
3112
+ production: { static: productionStatic, config: productionConfig }
3113
+ },
3114
+ pluginDownloadBase: { production: pluginDownloadProduction },
3115
+ api: { platformBaseUrl },
3116
+ auth: { oauthUrl }
3117
+ }), logger_default.success(`Configuration saved \u2192 ${getConfigPath()}`), logger_default.info(`Inspect with "${cliName} config show" or revert with "${cliName} config clear".`);
3118
+ }
3119
+ function runConfigShow(cliName) {
3120
+ let cfg = readConfig();
3121
+ if (!cfg) {
3122
+ logger_default.info(
3123
+ `No configuration found at ${getConfigPath()}. Run "${cliName} config set" to create one.`
3124
+ );
3125
+ return;
3126
+ }
3127
+ logger_default.info(`Configuration at ${getConfigPath()}:`), logger_default.info(JSON.stringify(cfg, null, 2));
1454
3128
  }
1455
- function validateArchiveSources() {
1456
- ensurePathExists(import_path3.default.resolve(DIST_DIR), "Dist folder not found. Build the project first."), ensurePathExists(
1457
- import_path3.default.resolve(SRC_DIR),
1458
- "Source folder not found. Add ./src before publishing."
1459
- ), ensurePathExists(import_path3.default.resolve(MANIFEST_FILE), "manifest.json not found in plugin root."), validateMarketplaceAssets();
3129
+ function runConfigClear() {
3130
+ clearConfig(), logger_default.success(`Configuration removed (${getConfigPath()})`);
1460
3131
  }
1461
- var import_fs5, import_path3, MARKETPLACE_DIR, MARKETPLACE_INDEX_FILE, MARKETPLACE_HEADER_IMAGE_FILE, PUBLIC_DIR, PUBLIC_LOGO_FILE, MANIFEST_FILE, DIST_DIR, SRC_DIR, ensurePathExists, validateManifestPublishingFields, ensureManifestCatalogFields, marketplacePaths, init_marketplace = __esm({
1462
- "src/utils/marketplace.ts"() {
3132
+ function registerConfigCommand(program, cliName) {
3133
+ let config = program.command("config").description("manage CLI configuration");
3134
+ 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);
3135
+ }
3136
+ var import_prompts, init_registerCommand = __esm({
3137
+ "src/core/cliConfig/registerCommand.ts"() {
1463
3138
  "use strict";
1464
- import_fs5 = __toESM(require("fs")), import_path3 = __toESM(require("path"));
1465
- init_manifestManager();
3139
+ import_prompts = require("@inquirer/prompts");
1466
3140
  init_logger();
1467
- MARKETPLACE_DIR = "marketplace", MARKETPLACE_INDEX_FILE = "index.md", MARKETPLACE_HEADER_IMAGE_FILE = "header-image.jpg", PUBLIC_DIR = "public", PUBLIC_LOGO_FILE = "logo.svg", MANIFEST_FILE = "manifest.json", DIST_DIR = "dist", SRC_DIR = "src", ensurePathExists = (targetPath, errorMessage) => {
1468
- import_fs5.default.existsSync(targetPath) || (logger_default.error(errorMessage), process.exit(1));
1469
- }, validateManifestPublishingFields = async () => {
1470
- let manifest = await manifestManager.load();
1471
- ensureManifestCatalogFields(manifest);
1472
- }, ensureManifestCatalogFields = (manifest) => {
1473
- (!manifest.name?.ru || !manifest.name?.en) && (logger_default.error(
1474
- 'Manifest field "name" is required for publishing. Add localized "name.ru" and "name.en" to ./manifest.json.'
1475
- ), process.exit(1)), (!manifest.description?.ru || !manifest.description?.en) && (logger_default.error(
1476
- 'Manifest field "description" is required for publishing. Add localized "description.ru" and "description.en" to ./manifest.json.'
1477
- ), process.exit(1));
1478
- };
1479
- marketplacePaths = {
1480
- distDir: DIST_DIR,
1481
- srcDir: SRC_DIR,
1482
- marketplaceDir: MARKETPLACE_DIR,
1483
- manifestFile: MANIFEST_FILE
1484
- };
3141
+ init_manager();
1485
3142
  }
1486
3143
  });
1487
3144
 
1488
- // src/utils/pluginPackageScripts.ts
1489
- function readPluginPackageScripts(cwd = process.cwd()) {
1490
- let packageJsonPath = import_path4.default.join(cwd, "package.json");
1491
- return import_fs6.default.existsSync(packageJsonPath) ? JSON.parse(import_fs6.default.readFileSync(packageJsonPath, "utf-8")).scripts ?? {} : null;
3145
+ // src/utils/withErrorHandling.ts
3146
+ function withErrorHandling(fn) {
3147
+ return async (...args) => {
3148
+ try {
3149
+ await fn(...args);
3150
+ } catch (error2) {
3151
+ error2 instanceof Error && error2.name === "ExitPromptError" && process.exit(0), logger_default.error(error2), printErrorHints(error2), process.exit(1);
3152
+ }
3153
+ };
1492
3154
  }
1493
- function hasPluginScript(name, cwd = process.cwd()) {
1494
- return !!readPluginPackageScripts(cwd)?.[name];
3155
+ function getErrorMessage2(error2) {
3156
+ return error2 instanceof Error ? error2.message : String(error2);
1495
3157
  }
1496
- var import_fs6, import_path4, init_pluginPackageScripts = __esm({
1497
- "src/utils/pluginPackageScripts.ts"() {
1498
- "use strict";
1499
- import_fs6 = __toESM(require("fs")), import_path4 = __toESM(require("path"));
3158
+ function printErrorHints(error2) {
3159
+ if (error2 instanceof PackageManagerRuntimeError) {
3160
+ error2.action && logger_default.info(`Action: ${error2.action}`), logger_default.info(`Run ${CLI_NAME2} doctor from the plugin directory for full local diagnostics.`);
3161
+ return;
1500
3162
  }
1501
- });
1502
-
1503
- // src/commands/submit/utils/runSubmitPrechecks.ts
1504
- async function runSubmitPrechecks(options = {}) {
1505
- if (options.skip) {
1506
- logger_default.warning("Skipping pre-submit checks (--skip-checks).");
3163
+ let message = getErrorMessage2(error2);
3164
+ if (isCorepackKeyIdError(message)) {
3165
+ logger_default.info(`Action: ${getPackageManagerRuntimeAction(message, "pnpm")}`);
1507
3166
  return;
1508
3167
  }
1509
- logger_default.separator(), logger_default.info("\u{1F50D} Pre-submit checks"), logger_default.separator(), await runStep("Validate manifest.json", () => manifestManager.validate()), await runStep("Check publishing metadata and assets", async () => {
1510
- await validateManifestPublishingFields(), validateMarketplaceAssets();
1511
- }), await runShellStep("Install dependencies", pluginCmd.install), await runShellStep("Run linter", pluginCmd.lint), hasPluginScript("typecheck") ? await runShellStep("Run typecheck", pluginCmd.typecheck) : logger_default.verbose('Skipping typecheck (no "typecheck" script in package.json).'), hasPluginScript("test") ? await runShellStep("Run tests", pluginCmd.test) : logger_default.warning(
1512
- 'No "test" script in package.json \u2014 add tests before publishing, or run submit with --skip-checks.'
1513
- ), await runShellStep("Check dependency vulnerabilities", pluginCmd.audit), logger_default.separator(), logger_default.success("Pre-submit checks passed"), logger_default.separator();
3168
+ /\b(manifest\.json|manifest validation|package manager|corepack|pnpm|npm|build|dist)\b/i.test(
3169
+ message
3170
+ ) && logger_default.info(`Run ${CLI_NAME2} doctor from the plugin directory for local diagnostics.`);
1514
3171
  }
1515
- var import_picocolors4, stepStart, stepDone, runStep, runShellStep, init_runSubmitPrechecks = __esm({
1516
- "src/commands/submit/utils/runSubmitPrechecks.ts"() {
3172
+ var init_withErrorHandling = __esm({
3173
+ "src/utils/withErrorHandling.ts"() {
1517
3174
  "use strict";
1518
- import_picocolors4 = __toESM(require("picocolors"));
1519
- init_manifestManager();
1520
- init_execCommand();
3175
+ init_meta2();
1521
3176
  init_logger();
1522
- init_marketplace();
1523
- init_pluginPackageScripts();
1524
- init_templateCommands();
1525
- stepStart = (label) => {
1526
- console.info(`${import_picocolors4.default.cyan("\u25B8")} ${label}`);
1527
- }, stepDone = (label) => {
1528
- console.info(`${import_picocolors4.default.green("\u2713")} ${label}`), console.info("");
1529
- }, runStep = async (label, run) => {
1530
- stepStart(label), await run(), stepDone(label);
1531
- }, runShellStep = async (label, command) => {
1532
- stepStart(label), console.info(import_picocolors4.default.dim(` $ ${command}`)), await execCommand(command), stepDone(label);
1533
- };
3177
+ init_packageManager();
1534
3178
  }
1535
3179
  });
1536
3180
 
1537
- // src/utils/buildArchive.ts
1538
- async function buildArchive() {
1539
- return validateArchiveSources(), (await manifestManager.load()).manifest_version === void 0 && (logger_default.error(
1540
- `manifest_version is missing in manifest.json. Run "${CLI_NAME2} up" or add "manifest_version": 1 manually before uploading.`
1541
- ), process.exit(1)), new Promise((resolve2, reject) => {
1542
- let archive = (0, import_archiver.default)("zip", { zlib: { level: 9 } }), chunks = [];
1543
- archive.on("data", (chunk) => chunks.push(chunk)), archive.on("end", () => {
1544
- let buffer = Buffer.concat(chunks);
1545
- if (logger_default.info(`\u{1F4E6} Archive created (${buffer.length} bytes)`), isVerboseEnabled()) {
1546
- let debugPath = writeVerboseArtifact("archive/latest-upload.zip", buffer);
1547
- logger_default.info(`[platform-api-debug] Saved archive copy to ${debugPath}`);
1548
- }
1549
- resolve2(buffer);
1550
- }), archive.on("error", reject), archive.glob("**/*", {
1551
- cwd: process.cwd(),
1552
- ignore: ["node_modules/**", "dist/**", "**/.DS_Store"],
1553
- dot: !0
1554
- }), archive.file(import_path5.default.resolve(marketplacePaths.manifestFile), { name: "src/manifest.json" }), archive.glob(
1555
- "**/*",
1556
- {
1557
- cwd: import_path5.default.resolve(marketplacePaths.distDir),
1558
- ignore: ["**/.DS_Store"]
1559
- },
1560
- { prefix: "dist/" }
1561
- ), archive.finalize();
3181
+ // src/distributions/external/login.ts
3182
+ async function loginExternal() {
3183
+ let tokenUrl = getOAuthTokenUrl();
3184
+ console.info(
3185
+ import_picocolors4.default.dim("Get your OAuth token at: ") + import_picocolors4.default.cyan(`${ESC}]8;;${tokenUrl}${BEL}${tokenUrl}${ESC}]8;;${BEL}`)
3186
+ ), console.info("");
3187
+ let token = await (0, import_prompts2.input)({
3188
+ message: "Enter your OAuth token:",
3189
+ required: !0
3190
+ }), orgId = await (0, import_prompts2.input)({
3191
+ message: "Enter your Organization ID (X-Org-ID):",
3192
+ required: !0
1562
3193
  });
3194
+ externalAuthManager.saveAuthData(token.trim());
3195
+ let cfg = readConfig() ?? {};
3196
+ writeConfig({ ...cfg, api: { ...cfg.api, platformOrgId: orgId.trim() } }), logger_default.success("OAuth token and organization ID saved successfully."), logger_default.info('You can now use "weavix submit" to submit your plugin for review.');
1563
3197
  }
1564
- var import_path5, import_archiver, init_buildArchive = __esm({
1565
- "src/utils/buildArchive.ts"() {
1566
- "use strict";
1567
- import_path5 = __toESM(require("path")), import_archiver = __toESM(require("archiver"));
1568
- init_manifestManager();
1569
- init_meta2();
1570
- init_logger();
1571
- init_marketplace();
1572
- init_verbose();
1573
- }
1574
- });
1575
-
1576
- // src/distributions/external/submit.ts
1577
- async function submitExternal(options = {}) {
1578
- await runSubmitPrechecks({ skip: options.skipChecks });
1579
- let manifest = await manifestManager.load(), issueKey = (await pluginStateManager.load()).trackerIssueKey;
1580
- if (issueKey)
1581
- try {
1582
- await getIssue(issueKey);
1583
- } catch {
1584
- issueKey = void 0;
1585
- }
1586
- let pluginId = manifest.id ?? (0, import_crypto.randomUUID)();
1587
- manifest.id || await manifestManager.update({ id: pluginId });
1588
- let manifestJson = await manifestManager.loadRaw();
1589
- if (issueKey) {
1590
- logger_default.verbose(`\u23F3 Updating issue ${issueKey} with latest manifest...`);
1591
- let issueDescription = buildIssueDescription({
1592
- pluginId,
1593
- slug: manifest.slug,
1594
- version: manifest.version,
1595
- manifestJson
1596
- });
1597
- await updatePluginIssue(issueKey, { description: issueDescription });
1598
- } else if (options.ticket === !1) {
1599
- logger_default.warning(
1600
- "Tracker issue is required for tracker-backed submit. Skipping ticket creation."
1601
- );
1602
- return;
1603
- } else {
1604
- logger_default.info("\u23F3 Creating plugin issue in Tracker...");
1605
- let issue = await createPluginIssue({
1606
- pluginId,
1607
- slug: manifest.slug,
1608
- version: manifest.version,
1609
- manifestJson
1610
- });
1611
- await pluginStateManager.update({ trackerIssueKey: issue.key }), issueKey = issue.key, logger_default.info(` Tracker issue : ${issueKey}`);
1612
- }
1613
- logger_default.info("\u{1F528} Building plugin..."), await build(), logger_default.info("\u{1F4E6} Creating archive...");
1614
- let archiveBuffer = await buildArchive(), archiveName = `${manifest.slug}-${manifest.version}.zip`;
1615
- logger_default.verbose(`\u2B06\uFE0F Attaching ${archiveName} to ${issueKey}...`), await attachFileToIssue(issueKey, archiveBuffer, archiveName), await addIssueComment(
1616
- issueKey,
1617
- `Updated bundle: \`${archiveName}\` (${archiveBuffer.length} bytes)`
1618
- ), logger_default.verbose(`\u23F3 Fetching available transitions for ${issueKey}...`);
1619
- let transitions = await getIssueTransitions(issueKey), submitTransition = transitions.find(
1620
- (t) => t.display?.toLowerCase().includes(SUBMIT_TRANSITION_DISPLAY) || t.id?.toLowerCase().includes("waitingforapprove") || t.id?.toLowerCase().includes("waiting")
1621
- );
1622
- if (!submitTransition) {
1623
- let available = transitions.map((t) => `"${t.display ?? t.id}"`).join(", ");
1624
- logger_default.error(
1625
- `Could not find a "Waiting for approve" transition on ${issueKey}. Available: ${available}`
1626
- );
3198
+ function logoutExternal() {
3199
+ if (!externalAuthManager.data) {
3200
+ logger_default.warning("You are not logged in.");
1627
3201
  return;
1628
3202
  }
1629
- logger_default.info("\u{1F680} Submitting plugin for review..."), await executeIssueTransition(issueKey, submitTransition.id), await addIssueComment(issueKey, `Submitted version \`${manifest.version}\` for review.`), logger_default.success("Plugin submitted for review!"), logger_default.info(` Tracker issue : ${issueKey}`), logger_default.info(` Version : ${manifest.version}`), logger_default.newLine();
3203
+ externalAuthManager.removeAuthData();
3204
+ let cfg = readConfig();
3205
+ if (cfg?.api?.platformOrgId) {
3206
+ let nextApi = { ...cfg.api };
3207
+ delete nextApi.platformOrgId, writeConfig({ ...cfg, api: nextApi });
3208
+ }
3209
+ logger_default.success("Successfully logged out.");
1630
3210
  }
1631
- var import_crypto, SUBMIT_TRANSITION_DISPLAY, init_submit = __esm({
1632
- "src/distributions/external/submit.ts"() {
3211
+ var import_prompts2, import_picocolors4, ESC, BEL, init_login = __esm({
3212
+ "src/distributions/external/login.ts"() {
1633
3213
  "use strict";
1634
- import_crypto = require("crypto");
1635
- init_build();
1636
- init_runSubmitPrechecks();
1637
- init_manifestManager();
1638
- init_pluginStateManager();
1639
- init_buildArchive();
3214
+ import_prompts2 = require("@inquirer/prompts"), import_picocolors4 = __toESM(require("picocolors"));
3215
+ init_manager();
1640
3216
  init_logger();
1641
- init_tracker();
1642
- SUBMIT_TRANSITION_DISPLAY = "waiting for approve";
3217
+ init_authManager();
3218
+ init_hosts();
3219
+ ESC = "\x1B", BEL = "\x07";
1643
3220
  }
1644
3221
  });
1645
3222
 
@@ -1653,167 +3230,20 @@ function registerDistributionCommands(program) {
1653
3230
  withErrorHandling(async () => {
1654
3231
  logoutExternal();
1655
3232
  })
1656
- ), program.command("submit").description("build plugin, create a Tracker issue in PLUGINMOD, and submit for review").addOption(skipChecksOption).action(withErrorHandling(submitExternal)), program.command("list").description("list all your plugins and their moderation status").action(withErrorHandling(listExternal)), program.command("info [issue-key]").description(
1657
- "show moderation status of a plugin (uses .tracker-plugin issue key if not provided)"
1658
- ).action(withErrorHandling(infoExternal));
3233
+ ), program.command("submit").description("build plugin and submit it to the platform for review").addOption(skipChecksOption).action(withErrorHandling(submitPlatform)), program.command("doctor").description("validate local plugin project, external config and auth").option("--network", "verify OAuth token with Tracker /myself", !1).option("--publish", "treat publish-readiness checks as failures", !1).option("--json", "machine-readable output", !1).action((options) => withErrorHandling(doctor)(options)), program.command("list").description("list all your plugins and their moderation status").action(withErrorHandling(listPlatform)), program.command("info [plugin-id]").description("show plugin status (uses plugin id from manifest if not provided)").action(withErrorHandling(infoPlatform));
1659
3234
  }
1660
3235
  var init_registerCommands = __esm({
1661
3236
  "src/distributions/external/registerCommands.ts"() {
1662
3237
  "use strict";
3238
+ init_doctor();
3239
+ init_platform2();
3240
+ init_platform3();
1663
3241
  init_options();
3242
+ init_platform4();
1664
3243
  init_registerCommand();
1665
3244
  init_withErrorHandling();
1666
- init_info();
1667
- init_list();
1668
3245
  init_login();
1669
3246
  init_meta();
1670
- init_submit();
1671
- }
1672
- });
1673
-
1674
- // src/distributions/external/hosts.ts
1675
- var hosts_exports = {};
1676
- __export(hosts_exports, {
1677
- getBuckets: () => getBuckets,
1678
- getMdsEndpoint: () => getMdsEndpoint,
1679
- getOAuthTokenUrl: () => getOAuthTokenUrl,
1680
- getPlatformBaseUrl: () => getPlatformBaseUrl,
1681
- getPluginDownloadBase: () => getPluginDownloadBase,
1682
- getS3Endpoint: () => getS3Endpoint,
1683
- getS3Region: () => getS3Region,
1684
- getTrackerBaseUrl: () => getTrackerBaseUrl,
1685
- getUpdateCheckInfo: () => getUpdateCheckInfo
1686
- });
1687
- function requireConfig() {
1688
- let cfg = readConfig();
1689
- if (!cfg)
1690
- throw new Error('CLI is not configured. Run "weavix config set" to configure.');
1691
- return cfg;
1692
- }
1693
- function getS3Endpoint() {
1694
- let cfg = requireConfig();
1695
- if (!cfg.s3?.endpoint)
1696
- throw new Error('S3 endpoint is not configured. Run "weavix config set" to configure.');
1697
- return cfg.s3.endpoint;
1698
- }
1699
- function getMdsEndpoint() {
1700
- let cfg = requireConfig();
1701
- if (!cfg.mds?.endpoint)
1702
- throw new Error('MDS endpoint is not configured. Run "weavix config set" to configure.');
1703
- return cfg.mds.endpoint;
1704
- }
1705
- function getS3Region() {
1706
- let cfg = requireConfig();
1707
- if (!cfg.s3?.region)
1708
- throw new Error('S3 region is not configured. Run "weavix config set" to configure.');
1709
- return cfg.s3.region;
1710
- }
1711
- function getBuckets() {
1712
- let production = requireConfig().buckets?.production;
1713
- if (!production?.static || !production?.config)
1714
- throw new Error('S3 buckets are not configured. Run "weavix config set" to configure.');
1715
- let prod = { static: production.static, config: production.config };
1716
- return { testing: prod, production: prod };
1717
- }
1718
- function getPluginDownloadBase(env) {
1719
- if (env === "debug")
1720
- return "http://localhost:5173/plugins-debug";
1721
- let base = requireConfig().pluginDownloadBase?.production;
1722
- if (!base)
1723
- throw new Error(
1724
- 'Plugin download base is not configured. Run "weavix config set" to configure.'
1725
- );
1726
- return base;
1727
- }
1728
- function getPlatformBaseUrl() {
1729
- let cfg = requireConfig();
1730
- if (!cfg.api?.platformBaseUrl)
1731
- throw new Error(
1732
- 'Platform API URL is not configured. Run "weavix config set" to configure.'
1733
- );
1734
- return cfg.api.platformBaseUrl;
1735
- }
1736
- function getTrackerBaseUrl() {
1737
- return TRACKER_BASE_URL2;
1738
- }
1739
- function getOAuthTokenUrl() {
1740
- let cfg = requireConfig();
1741
- if (!cfg.auth?.oauthUrl)
1742
- throw new Error('OAuth URL is not configured. Run "weavix config set" to configure.');
1743
- return cfg.auth.oauthUrl;
1744
- }
1745
- function getUpdateCheckInfo() {
1746
- return null;
1747
- }
1748
- var TRACKER_BASE_URL2, init_hosts = __esm({
1749
- "src/distributions/external/hosts.ts"() {
1750
- "use strict";
1751
- init_manager();
1752
- TRACKER_BASE_URL2 = "https://api.tracker.yandex.net/v3";
1753
- }
1754
- });
1755
-
1756
- // src/distributions/external/templateSubstitution.ts
1757
- var templateSubstitution_exports = {};
1758
- __export(templateSubstitution_exports, {
1759
- applySubstitutions: () => applySubstitutions,
1760
- overlayDirName: () => overlayDirName,
1761
- templateDeps: () => templateDeps
1762
- });
1763
- function rewritePackageJson(content) {
1764
- let pkg = JSON.parse(content);
1765
- if (pkg.dependencies) {
1766
- let next = {};
1767
- for (let [name, version] of Object.entries(pkg.dependencies)) {
1768
- let renamed = PACKAGE_RENAME[name] ?? name;
1769
- next[renamed] = ADDED_DEPS[renamed] ?? version;
1770
- }
1771
- for (let [name, version] of Object.entries(ADDED_DEPS))
1772
- name in next || (next[name] = version);
1773
- pkg.dependencies = Object.fromEntries(
1774
- Object.entries(next).sort(([a], [b]) => a.localeCompare(b))
1775
- );
1776
- }
1777
- return JSON.stringify(pkg, null, 4) + `
1778
- `;
1779
- }
1780
- function rewriteImports(content) {
1781
- let result = content;
1782
- for (let [from, to] of Object.entries(PACKAGE_RENAME)) {
1783
- let escaped = from.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1784
- result = result.replace(new RegExp(escaped, "g"), to);
1785
- }
1786
- return result;
1787
- }
1788
- function rewriteNpmrc(content) {
1789
- return content.split(`
1790
- `).filter((line) => !/^registry\s*=\s*https?:\/\/npm\.yandex-team\.ru/.test(line.trim())).join(`
1791
- `);
1792
- }
1793
- function applySubstitutions(filePath, content) {
1794
- let name = import_path6.default.basename(filePath), ext = import_path6.default.extname(filePath);
1795
- if (name === "package.json")
1796
- return Buffer.from(rewritePackageJson(content.toString("utf8")), "utf8");
1797
- if (name === "npmrc.template" || name === ".npmrc")
1798
- return Buffer.from(rewriteNpmrc(content.toString("utf8")), "utf8");
1799
- if ([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"].includes(ext)) {
1800
- let original = content.toString("utf8"), rewritten = rewriteImports(original);
1801
- if (rewritten !== original)
1802
- return Buffer.from(rewritten, "utf8");
1803
- }
1804
- return content;
1805
- }
1806
- var import_path6, PACKAGE_RENAME, ADDED_DEPS, templateDeps, overlayDirName, init_templateSubstitution = __esm({
1807
- "src/distributions/external/templateSubstitution.ts"() {
1808
- "use strict";
1809
- import_path6 = __toESM(require("path")), PACKAGE_RENAME = {
1810
- "@yandex-data-ui/tracker-plugin-sdk-react": "@weavix/sdk-react",
1811
- "@yandex-data-ui/tracker-pub-api-types": "@weavix/tracker-api-types"
1812
- }, ADDED_DEPS = {
1813
- "@weavix/sdk-core": "latest",
1814
- "@weavix/sdk-react": "latest",
1815
- "@weavix/tracker-api-types": "latest"
1816
- }, templateDeps = ["@weavix/sdk-core", "@weavix/sdk-react", "@weavix/tracker-api-types"], overlayDirName = "_external";
1817
3247
  }
1818
3248
  });
1819
3249
 
@@ -1823,26 +3253,11 @@ init_meta2();
1823
3253
 
1824
3254
  // src/distribution/registerCommands.ts
1825
3255
  init_flag();
1826
- var impl3 = (init_registerCommands(), __toCommonJS(registerCommands_exports)), { registerDistributionCommands: registerDistributionCommands2 } = impl3;
1827
-
1828
- // src/utils/checkUpdate.ts
1829
- var import_node_fetch2 = __toESM(require("node-fetch"));
1830
-
1831
- // src/distribution/hosts.ts
1832
- init_flag();
1833
- var impl4 = (init_hosts(), __toCommonJS(hosts_exports)), {
1834
- getS3Endpoint: getS3Endpoint2,
1835
- getMdsEndpoint: getMdsEndpoint2,
1836
- getS3Region: getS3Region2,
1837
- getBuckets: getBuckets2,
1838
- getPluginDownloadBase: getPluginDownloadBase2,
1839
- getPlatformBaseUrl: getPlatformBaseUrl2,
1840
- getTrackerBaseUrl: getTrackerBaseUrl2,
1841
- getOAuthTokenUrl: getOAuthTokenUrl2,
1842
- getUpdateCheckInfo: getUpdateCheckInfo2
1843
- } = impl4;
3256
+ var impl6 = (init_registerCommands(), __toCommonJS(registerCommands_exports)), { registerDistributionCommands: registerDistributionCommands2 } = impl6;
1844
3257
 
1845
3258
  // src/utils/checkUpdate.ts
3259
+ var import_node_fetch3 = __toESM(require("node-fetch"));
3260
+ init_hosts2();
1846
3261
  init_logger();
1847
3262
  var SEMVER_RE = /^(\d+)\.(\d+)\.(\d+)$/, DIAGNOSTIC_FLAGS = /* @__PURE__ */ new Set(["--version", "-V", "--help", "-h", "help"]), parse = (v) => {
1848
3263
  let m = SEMVER_RE.exec(v);
@@ -1857,7 +3272,7 @@ var SEMVER_RE = /^(\d+)\.(\d+)\.(\d+)$/, DIAGNOSTIC_FLAGS = /* @__PURE__ */ new
1857
3272
  let current = parse(version);
1858
3273
  if (current)
1859
3274
  try {
1860
- let response = await (0, import_node_fetch2.default)(`${info2.registryUrl}/${info2.packageName}/latest`);
3275
+ let response = await (0, import_node_fetch3.default)(`${info2.registryUrl}/${info2.packageName}/latest`);
1861
3276
  if (!response.ok) return;
1862
3277
  let json = await response.json(), latest = parse(json.version);
1863
3278
  if (!latest) return;
@@ -1877,131 +3292,33 @@ Run: ${installCmd}`);
1877
3292
  }
1878
3293
  };
1879
3294
 
3295
+ // src/utils/shouldRunUpdateCheck.ts
3296
+ function shouldRunUpdateCheck(argv) {
3297
+ return !(argv.includes("doctor") && argv.includes("--json"));
3298
+ }
3299
+
1880
3300
  // src/index.ts
1881
3301
  init_build();
1882
3302
 
1883
3303
  // src/commands/create/index.ts
1884
- var path13 = __toESM(require("path")), import_prompts3 = require("@inquirer/prompts");
1885
-
1886
- // src/core/manifest/constants.ts
1887
- var DATA_PERMISSIONS = [
1888
- // top 10
1889
- "tracker:issues:read",
1890
- "tracker:issues:write",
1891
- "tracker:issuetypes:read",
1892
- "tracker:statuses:read",
1893
- "tracker:queues:read",
1894
- "tracker:fields:read",
1895
- "tracker:entities:read",
1896
- "tracker:attachments:read",
1897
- "tracker:attachments:write",
1898
- // in alphabetical order
1899
- "tracker:applications:read",
1900
- "tracker:boards:read",
1901
- "tracker:boards:write",
1902
- "tracker:bulk:read",
1903
- "tracker:bulk:write",
1904
- "tracker:bulkchange:read",
1905
- "tracker:bulkchange:write",
1906
- "tracker:charts:read",
1907
- "tracker:commentTemplates:read",
1908
- "tracker:commentTemplates:write",
1909
- "tracker:components:read",
1910
- "tracker:components:write",
1911
- "tracker:data:read",
1912
- "tracker:departments:read",
1913
- "tracker:entities:write",
1914
- "tracker:externalEventTypes:write",
1915
- "tracker:externalEvents:write",
1916
- "tracker:fields:write",
1917
- "tracker:filterFolders:write",
1918
- "tracker:filters:read",
1919
- "tracker:filters:write",
1920
- "tracker:goals:read",
1921
- "tracker:goals:write",
1922
- "tracker:groups:read",
1923
- "tracker:issueTemplates:read",
1924
- "tracker:issueTemplates:write",
1925
- "tracker:links:read",
1926
- "tracker:linktypes:read",
1927
- "tracker:liveBoards:write",
1928
- "tracker:localFields:read",
1929
- "tracker:maillists:read",
1930
- "tracker:maillists:write",
1931
- "tracker:myself:read",
1932
- "tracker:myself:write",
1933
- "tracker:priorities:read",
1934
- "tracker:queues:write",
1935
- "tracker:reminders:read",
1936
- "tracker:reminders:write",
1937
- "tracker:remotelinks:read",
1938
- "tracker:reports:read",
1939
- "tracker:reports:write",
1940
- "tracker:resolutions:read",
1941
- "tracker:resources:read",
1942
- "tracker:resources:write",
1943
- "tracker:roles:read",
1944
- "tracker:screens:read",
1945
- "tracker:services:read",
1946
- "tracker:sprints:read",
1947
- "tracker:sprints:write",
1948
- "tracker:system:write",
1949
- "tracker:tags:read",
1950
- "tracker:translations:read",
1951
- "tracker:users:read",
1952
- "tracker:users:write",
1953
- "tracker:versions:read",
1954
- "tracker:versions:write",
1955
- "tracker:workflows:read",
1956
- "tracker:workflows:write",
1957
- "tracker:worklog:read",
1958
- "tracker:worklog:write"
1959
- ], TOP_DATA_PERMISSIONS = DATA_PERMISSIONS.slice(0, 10);
1960
- var TEMPLATES = [
1961
- "default",
1962
- "issue.action",
1963
- "issue.block",
1964
- "issue.tab",
1965
- "issue.comment.action",
1966
- "navigation",
1967
- "trigger.action",
1968
- "project.action",
1969
- "project.block",
1970
- "project.tab",
1971
- "portfolio.action",
1972
- "portfolio.block",
1973
- "portfolio.tab",
1974
- "goal.action",
1975
- "goal.block",
1976
- "goal.tab",
1977
- "attachment.viewer.action",
1978
- "board.tab"
1979
- ];
1980
- var TEMPLATE_SLOTS = {
1981
- default: [],
1982
- "issue.action": ["issue.action"],
1983
- "issue.block": ["issue.block"],
1984
- "issue.tab": ["issue.tab"],
1985
- "issue.comment.action": ["issue.comment.action"],
1986
- navigation: ["navigation"],
1987
- "trigger.action": ["trigger.create.action", "trigger.edit.action"],
1988
- "project.action": ["project.action"],
1989
- "project.block": ["project.block"],
1990
- "project.tab": ["project.tab"],
1991
- "portfolio.action": ["portfolio.action"],
1992
- "portfolio.block": ["portfolio.block"],
1993
- "portfolio.tab": ["portfolio.tab"],
1994
- "goal.action": ["goal.action"],
1995
- "goal.block": ["goal.block"],
1996
- "goal.tab": ["goal.tab"],
1997
- "attachment.viewer.action": ["attachment.viewer.action"],
1998
- "board.tab": ["board.tab"]
1999
- };
2000
-
2001
- // src/commands/create/index.ts
3304
+ var path18 = __toESM(require("path")), import_prompts3 = require("@inquirer/prompts");
3305
+ init_constants();
2002
3306
  init_meta2();
2003
3307
  init_logger();
2004
3308
 
3309
+ // src/commands/create/templateChoices.ts
3310
+ init_constants();
3311
+ var DEFERRED_TEMPLATE_REASON = "will be added later", DEFERRED_TEMPLATES = /* @__PURE__ */ new Set(["user-card-info", "user-card-calendar"]);
3312
+ function getTemplateChoices(service) {
3313
+ return TEMPLATES.filter((templateName) => TEMPLATE_SERVICE[templateName] === service).map(
3314
+ (templateName) => ({
3315
+ name: templateName,
3316
+ value: templateName,
3317
+ disabled: DEFERRED_TEMPLATES.has(templateName) ? DEFERRED_TEMPLATE_REASON : void 0
3318
+ })
3319
+ );
3320
+ }
3321
+
2005
3322
  // src/commands/create/utils/getWelcomeMessage.ts
2006
3323
  var import_picocolors5 = __toESM(require("picocolors")), getWelcomeMessage = (pwd) => `
2007
3324
  ${import_picocolors5.default.bold(import_picocolors5.default.white("\u{1F680} Create new tracker plugin"))}
@@ -2012,25 +3329,27 @@ ${import_picocolors5.default.dim("Press")} ${import_picocolors5.default.yellow("
2012
3329
  `;
2013
3330
 
2014
3331
  // src/commands/create/utils/initManifest.ts
2015
- var fs5 = __toESM(require("fs")), path7 = __toESM(require("path"));
3332
+ var fs11 = __toESM(require("fs")), path13 = __toESM(require("path"));
2016
3333
 
2017
3334
  // src/commands/create/utils/generateManifest.ts
3335
+ init_constants();
3336
+ var FULL_CONTEXT_TEMPLATES = /* @__PURE__ */ new Set(["user-card-info", "user-card-calendar"]);
2018
3337
  function buildSlots(template, slotTitle) {
2019
3338
  let slotNames = TEMPLATE_SLOTS[template];
2020
3339
  if (slotNames.length === 0) return;
2021
- let slotEntry = {
3340
+ let service = TEMPLATE_SERVICE[template], contextLevel = FULL_CONTEXT_TEMPLATES.has(template) ? "full" : "basic", slotEntry = {
2022
3341
  entrypoint: "index.html",
2023
3342
  title: { ru: slotTitle, en: slotTitle },
2024
- contextLevel: "basic"
3343
+ contextLevel
2025
3344
  };
2026
3345
  return {
2027
- tracker: Object.fromEntries(slotNames.map((slotName) => [slotName, [slotEntry]]))
3346
+ [service]: Object.fromEntries(slotNames.map((slotName) => [slotName, [slotEntry]]))
2028
3347
  };
2029
3348
  }
2030
3349
  var generateManifest = (answers) => ({
2031
3350
  $schema: "./manifest.schema.json",
2032
3351
  manifest_version: 1,
2033
- supported_services: ["tracker"],
3352
+ supported_services: [TEMPLATE_SERVICE[answers.template]],
2034
3353
  slug: answers.packageSlug,
2035
3354
  version: answers.version,
2036
3355
  name: {
@@ -2048,55 +3367,58 @@ var generateManifest = (answers) => ({
2048
3367
 
2049
3368
  // src/commands/create/utils/initManifest.ts
2050
3369
  var initManifest = ({ answers, targetDir }) => {
2051
- let generatedManifest = generateManifest(answers), manifestPath2 = path7.join(targetDir, "manifest.json");
2052
- fs5.writeFileSync(manifestPath2, JSON.stringify(generatedManifest, null, 2), "utf-8");
3370
+ let generatedManifest = generateManifest(answers), manifestPath = path13.join(targetDir, "manifest.json");
3371
+ fs11.writeFileSync(manifestPath, JSON.stringify(generatedManifest, null, 2), "utf-8");
2053
3372
  };
2054
3373
 
2055
3374
  // src/commands/create/utils/initTemplate.ts
2056
- var fs8 = __toESM(require("fs")), path12 = __toESM(require("path"));
3375
+ var fs14 = __toESM(require("fs")), path17 = __toESM(require("path"));
2057
3376
 
2058
3377
  // src/distribution/templateSubstitution.ts
2059
3378
  init_flag();
2060
- var impl5 = (init_templateSubstitution(), __toCommonJS(templateSubstitution_exports)), { applySubstitutions: applySubstitutions2, overlayDirName: overlayDirName2, templateDeps: templateDeps2 } = impl5;
3379
+ var isInternal = !1, templateDeps = [
3380
+ "@weavix/tracker-plugin-sdk",
3381
+ "@weavix/tracker-plugin-sdk-react",
3382
+ "@weavix/tracker-api-types"
3383
+ ], overlayDirName = isInternal ? "_internal" : "_external";
2061
3384
 
2062
3385
  // src/utils/copyDirectory.ts
2063
- var fs6 = __toESM(require("fs")), import_path7 = __toESM(require("path")), import_tinyglobby = require("tinyglobby");
2064
- var resolveTargetFileName = (file) => file.endsWith(".template") ? "." + file.replace(".template", "") : file, copyDirectory = async (sourceDir, targetDir) => {
2065
- let files = await (0, import_tinyglobby.glob)(["**/*"], {
3386
+ var fs12 = __toESM(require("fs")), import_path12 = __toESM(require("path")), import_tinyglobby2 = require("tinyglobby"), resolveTargetFileName = (file) => file.endsWith(".template") ? "." + file.replace(".template", "") : file, copyDirectory = async (sourceDir, targetDir) => {
3387
+ let files = await (0, import_tinyglobby2.glob)(["**/*"], {
2066
3388
  cwd: sourceDir,
2067
3389
  onlyFiles: !0,
2068
3390
  dot: !0
2069
3391
  });
2070
3392
  await Promise.all(
2071
3393
  files.map(async (file) => {
2072
- let sourcePath = import_path7.default.join(sourceDir, file), targetFile = resolveTargetFileName(file), targetPath = import_path7.default.join(targetDir, targetFile);
2073
- await fs6.promises.mkdir(import_path7.default.dirname(targetPath), { recursive: !0 });
2074
- let content = await fs6.promises.readFile(sourcePath), rewritten = applySubstitutions2(file, content);
2075
- await fs6.promises.writeFile(targetPath, rewritten);
3394
+ let sourcePath = import_path12.default.join(sourceDir, file), targetFile = resolveTargetFileName(file), targetPath = import_path12.default.join(targetDir, targetFile);
3395
+ await fs12.promises.mkdir(import_path12.default.dirname(targetPath), { recursive: !0 });
3396
+ let content = await fs12.promises.readFile(sourcePath);
3397
+ await fs12.promises.writeFile(targetPath, content);
2076
3398
  })
2077
3399
  );
2078
3400
  };
2079
3401
 
2080
3402
  // src/utils/getProjectPath.ts
2081
- var import_path8 = __toESM(require("path")), isDevelopment = () => __dirname.includes("/src/"), getProjectPath = (relativePath) => isDevelopment() ? import_path8.default.resolve(__dirname, "..", "..", relativePath) : import_path8.default.resolve(__dirname, relativePath), getTemplatesBaseDir = () => getProjectPath("templates"), getTemplatePath = (filename) => import_path8.default.join(getTemplatesBaseDir(), "_shared", filename);
3403
+ var import_path13 = __toESM(require("path")), isDevelopment = () => __dirname.includes("/src/"), getProjectPath = (relativePath) => isDevelopment() ? import_path13.default.resolve(__dirname, "..", "..", relativePath) : import_path13.default.resolve(__dirname, relativePath), getTemplatesBaseDir = () => getProjectPath("templates"), getTemplatePath = (filename) => import_path13.default.join(getTemplatesBaseDir(), "_shared", filename), getOverlayTemplatePath = (overlayDir, filename) => import_path13.default.join(getTemplatesBaseDir(), overlayDir, filename);
2082
3404
 
2083
3405
  // src/commands/create/utils/initTemplate.ts
2084
3406
  init_logger();
2085
3407
 
2086
3408
  // src/commands/create/utils/updatePackageJson.ts
2087
- var fs7 = __toESM(require("fs")), path11 = __toESM(require("path")), updatePackageJson = (targetDir, packageSlug) => {
2088
- let packageJsonPath = path11.join(targetDir, "package.json");
2089
- if (fs7.existsSync(packageJsonPath)) {
2090
- let packageJson = JSON.parse(fs7.readFileSync(packageJsonPath, "utf-8"));
2091
- packageJson.name = packageSlug, fs7.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 4) + `
3409
+ var fs13 = __toESM(require("fs")), path16 = __toESM(require("path")), updatePackageJson = (targetDir, packageSlug) => {
3410
+ let packageJsonPath = path16.join(targetDir, "package.json");
3411
+ if (fs13.existsSync(packageJsonPath)) {
3412
+ let packageJson = JSON.parse(fs13.readFileSync(packageJsonPath, "utf-8"));
3413
+ packageJson.name = packageSlug, fs13.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 4) + `
2092
3414
  `);
2093
3415
  }
2094
3416
  };
2095
3417
 
2096
3418
  // src/commands/create/utils/initTemplate.ts
2097
3419
  var initTemplate = async ({ answers, targetDir }) => {
2098
- fs8.existsSync(targetDir) || fs8.mkdirSync(targetDir, { recursive: !0 });
2099
- let templatesBaseDir = getTemplatesBaseDir(), templatesDir = path12.join(templatesBaseDir, answers.template), sharedDir = path12.join(templatesBaseDir, "_shared"), overlayDir = path12.join(templatesBaseDir, overlayDirName2);
3420
+ fs14.existsSync(targetDir) || fs14.mkdirSync(targetDir, { recursive: !0 });
3421
+ let templatesBaseDir = getTemplatesBaseDir(), templatesDir = path17.join(templatesBaseDir, answers.template), sharedDir = path17.join(templatesBaseDir, "_shared"), overlayDir = path17.join(templatesBaseDir, overlayDirName);
2100
3422
  await copyDirectory(sharedDir, targetDir), await copyDirectory(overlayDir, targetDir), await copyDirectory(templatesDir, targetDir), updatePackageJson(targetDir, answers.packageSlug), logger_default.info("Created template with marketplace publication requirements."), logger_default.info(
2101
3423
  "Before publishing, add ./marketplace/index.md, ./marketplace/header-image.jpg (784:325), and ./public/logo.svg (square)."
2102
3424
  );
@@ -2119,12 +3441,23 @@ async function create() {
2119
3441
  message: "Enter support email:",
2120
3442
  required: !0,
2121
3443
  validate: (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) || "Please enter a valid email address"
2122
- }), template = await (0, import_prompts3.select)({
2123
- message: "Select a template:",
2124
- choices: TEMPLATES.map((templateName) => ({
2125
- name: templateName,
2126
- value: templateName
3444
+ }), service = CREATE_SERVICES2.length === 1 ? CREATE_SERVICES2[0] : await (0, import_prompts3.select)({
3445
+ message: "Select a service:",
3446
+ choices: CREATE_SERVICES2.map((serviceName) => ({
3447
+ name: serviceName,
3448
+ value: serviceName
2127
3449
  }))
3450
+ }), templateChoices = getTemplateChoices(service);
3451
+ if (templateChoices.every((choice) => choice.disabled)) {
3452
+ logger_default.warning(`No selectable templates are available for ${service} yet.`), logger_default.info(
3453
+ templateChoices.map((choice) => `- ${choice.name} ${choice.disabled ?? ""}`.trim()).join(`
3454
+ `)
3455
+ );
3456
+ return;
3457
+ }
3458
+ let template = await (0, import_prompts3.select)({
3459
+ message: "Select a template:",
3460
+ choices: templateChoices
2128
3461
  }), dataPermissions = await (0, import_prompts3.checkbox)({
2129
3462
  message: "Select data permissions (some popular options):",
2130
3463
  choices: TOP_DATA_PERMISSIONS.map((permission) => ({
@@ -2137,25 +3470,26 @@ async function create() {
2137
3470
  pluginName,
2138
3471
  pluginDescription,
2139
3472
  supportEmail,
3473
+ service,
2140
3474
  template,
2141
3475
  permissions: {
2142
3476
  data: dataPermissions
2143
3477
  },
2144
3478
  version: DEFAULT_VERSION
2145
- }, targetDir = path13.join(process.cwd(), answers.packageSlug);
3479
+ }, targetDir = path18.join(process.cwd(), answers.packageSlug);
2146
3480
  await initTemplate({
2147
3481
  answers,
2148
3482
  targetDir
2149
3483
  }), initManifest({
2150
3484
  answers,
2151
3485
  targetDir
2152
- }), logger_default.newLine(), logger_default.success("\u2705 Plugin created successfully!"), logger_default.newLine(), logger_default.info("\u{1F680} To start development:"), logger_default.commands("", [`cd ${answers.packageSlug}`, "npm install", `${CLI_NAME2} debug`]), logger_default.newLine(), logger_default.info(
2153
- "\u{1F4CC} Important: After running debug, the plugin will be available in the Tracker interface,"
2154
- ), logger_default.info("not at localhost. Open Tracker and check the plugin in the appropriate context.");
3486
+ }), logger_default.newLine(), logger_default.success("\u2705 Plugin created successfully!"), logger_default.info("\u{1F680} To start development:"), logger_default.commands("", [`cd ${answers.packageSlug}`, "npm install", `${CLI_NAME2} debug`]), logger_default.info(
3487
+ "\u{1F4CC} Important: After running debug, the plugin will be available in the Tracker interface, not at localhost. Open Tracker and check the plugin in the appropriate context."
3488
+ );
2155
3489
  }
2156
3490
 
2157
3491
  // src/commands/debug/index.ts
2158
- var import_fs10 = __toESM(require("fs")), import_path12 = __toESM(require("path"));
3492
+ var import_fs15 = __toESM(require("fs")), import_path17 = __toESM(require("path"));
2159
3493
  init_manifestManager();
2160
3494
 
2161
3495
  // src/core/s3config/constants.ts
@@ -2179,10 +3513,11 @@ var registerCleanup = (cleanup) => {
2179
3513
  init_templateCommands();
2180
3514
 
2181
3515
  // src/commands/debug/utils/createDebugConfig.ts
2182
- var import_fs7 = __toESM(require("fs")), import_path9 = __toESM(require("path"));
3516
+ var import_fs12 = __toESM(require("fs")), import_path14 = __toESM(require("path"));
2183
3517
  init_manifestManager();
2184
3518
 
2185
3519
  // src/utils/convertManifestToConfig.ts
3520
+ init_hosts2();
2186
3521
  function buildPluginDownloadUrl(env, id, version) {
2187
3522
  return env === "debug" ? getPluginDownloadBase2(env) : `${getPluginDownloadBase2(env)}/${id}/${version}`;
2188
3523
  }
@@ -2226,21 +3561,21 @@ var convertManifestToConfig = (manifest, environment) => {
2226
3561
 
2227
3562
  // src/commands/debug/utils/createDebugConfig.ts
2228
3563
  var createDebugConfig = async () => {
2229
- let manifest = await manifestManager.load(), config = convertManifestToConfig(manifest, "debug"), configPath = import_path9.default.join(process.cwd(), CONFIG_FILE_NAME);
2230
- import_fs7.default.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
3564
+ let manifest = await manifestManager.load(), config = convertManifestToConfig(manifest, "debug"), configPath = import_path14.default.join(process.cwd(), CONFIG_FILE_NAME);
3565
+ import_fs12.default.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
2231
3566
  };
2232
3567
 
2233
3568
  // src/commands/debug/utils/lockFile.ts
2234
- var import_fs8 = __toESM(require("fs")), import_path10 = __toESM(require("path")), LOCK_FILE_NAME = ".tracker-cli-debug.lock", getLockFilePath = () => import_path10.default.join(process.cwd(), LOCK_FILE_NAME), getRunningDebugPid = () => {
3569
+ var import_fs13 = __toESM(require("fs")), import_path15 = __toESM(require("path")), LOCK_FILE_NAME = ".yaweavix-debug.lock", getLockFilePath = () => import_path15.default.join(process.cwd(), LOCK_FILE_NAME), getRunningDebugPid = () => {
2235
3570
  let lockPath = getLockFilePath();
2236
- if (!import_fs8.default.existsSync(lockPath))
3571
+ if (!import_fs13.default.existsSync(lockPath))
2237
3572
  return null;
2238
3573
  try {
2239
- let pid = JSON.parse(import_fs8.default.readFileSync(lockPath, "utf-8")).pid;
3574
+ let pid = JSON.parse(import_fs13.default.readFileSync(lockPath, "utf-8")).pid;
2240
3575
  return process.kill(pid, 0), pid;
2241
3576
  } catch {
2242
3577
  try {
2243
- import_fs8.default.unlinkSync(lockPath);
3578
+ import_fs13.default.unlinkSync(lockPath);
2244
3579
  } catch {
2245
3580
  }
2246
3581
  return null;
@@ -2248,19 +3583,19 @@ var import_fs8 = __toESM(require("fs")), import_path10 = __toESM(require("path")
2248
3583
  }, createLockFile = () => {
2249
3584
  let lockPath = getLockFilePath(), lockData = {
2250
3585
  pid: process.pid
2251
- }, fd = import_fs8.default.openSync(lockPath, "wx");
2252
- import_fs8.default.writeSync(fd, JSON.stringify(lockData, null, 2)), import_fs8.default.closeSync(fd);
3586
+ }, fd = import_fs13.default.openSync(lockPath, "wx");
3587
+ import_fs13.default.writeSync(fd, JSON.stringify(lockData, null, 2)), import_fs13.default.closeSync(fd);
2253
3588
  }, removeLockFile = () => {
2254
3589
  let lockPath = getLockFilePath();
2255
- import_fs8.default.existsSync(lockPath) && import_fs8.default.unlinkSync(lockPath);
3590
+ import_fs13.default.existsSync(lockPath) && import_fs13.default.unlinkSync(lockPath);
2256
3591
  };
2257
3592
 
2258
3593
  // src/commands/debug/utils/watchManifest.ts
2259
- var import_fs9 = __toESM(require("fs")), import_path11 = __toESM(require("path"));
3594
+ var import_fs14 = __toESM(require("fs")), import_path16 = __toESM(require("path"));
2260
3595
  init_manifestManager();
2261
3596
  init_logger();
2262
3597
  var watchManifest = () => {
2263
- let manifestPath2 = import_path11.default.join(process.cwd(), "manifest.json"), debounceTimer = null, watcher = import_fs9.default.watch(manifestPath2, async (eventType) => {
3598
+ let manifestPath = import_path16.default.join(process.cwd(), "manifest.json"), debounceTimer = null, watcher = import_fs14.default.watch(manifestPath, async (eventType) => {
2264
3599
  eventType === "change" && (debounceTimer && clearTimeout(debounceTimer), debounceTimer = setTimeout(async () => {
2265
3600
  try {
2266
3601
  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");
@@ -2284,12 +3619,12 @@ Please stop the existing instance before starting a new one.
2284
3619
  If you lost the terminal tab, you can kill the process with:
2285
3620
  kill ${runningPid}`
2286
3621
  ), process.exit(1));
2287
- let configPath = import_path12.default.join(process.cwd(), CONFIG_FILE_NAME);
3622
+ let configPath = import_path17.default.join(process.cwd(), CONFIG_FILE_NAME);
2288
3623
  options.lint && await manifestManager.validate(), await createDebugConfig();
2289
3624
  let watcher = watchManifest(), cleanup = () => {
2290
- watcher.close(), import_fs10.default.existsSync(configPath) && import_fs10.default.unlinkSync(configPath), removeLockFile();
3625
+ watcher.close(), import_fs15.default.existsSync(configPath) && import_fs15.default.unlinkSync(configPath), removeLockFile();
2291
3626
  };
2292
- registerCleanup(cleanup), createLockFile(), logger_default.newLine(), logger_default.info("\u{1F527} Debug mode started!"), logger_default.newLine(), logger_default.info("\u{1F4CC} The plugin is now available in the Tracker interface."), logger_default.info("Open Tracker and check the plugin functionality in the appropriate context."), logger_default.newLine(), logger_default.info("\u26A0\uFE0F Do not try to open localhost in the browser - the plugin works"), logger_default.info("only inside Tracker through a special loading mechanism."), logger_default.newLine(), logger_default.info("\u{1F504} Code changes will be automatically reloaded."), logger_default.info("Press Ctrl+C to stop."), logger_default.newLine(), await execCommand(pluginCmd.dev), cleanup();
3627
+ registerCleanup(cleanup), createLockFile(), logger_default.newLine(), logger_default.info("\u{1F527} Debug mode started!"), logger_default.newLine(), logger_default.info("\u{1F4CC} The plugin is now available in the Tracker interface."), logger_default.info("Open Tracker and check the plugin functionality in the appropriate context."), logger_default.newLine(), logger_default.info("\u26A0\uFE0F Do not try to open localhost in the browser - the plugin works"), logger_default.info("only inside Tracker through a special loading mechanism."), logger_default.newLine(), logger_default.info("\u{1F504} Code changes will be automatically reloaded."), logger_default.info("Press Ctrl+C to stop."), logger_default.newLine(), await execCommand(getPluginCommands().dev), cleanup();
2293
3628
  }
2294
3629
 
2295
3630
  // src/commands/lint.ts
@@ -2298,22 +3633,26 @@ init_execCommand();
2298
3633
  init_logger();
2299
3634
  init_templateCommands();
2300
3635
  async function lint() {
2301
- logger_default.info("\u{1F50D} Running manifest.json validation..."), await manifestManager.validate(), logger_default.info("\u{1F50D} Running code lint check..."), await execCommand(pluginCmd.lint);
3636
+ logger_default.info("\u{1F50D} Running manifest.json validation..."), await manifestManager.validate(), logger_default.info("\u{1F50D} Running code lint check..."), await execCommand(getPluginCommands().lint);
2302
3637
  }
2303
3638
 
3639
+ // src/commands/up/index.ts
3640
+ var import_fs18 = require("fs"), import_promises4 = require("fs/promises");
3641
+ init_execCommand();
3642
+
2304
3643
  // src/commands/up/utils/copyTemplateFiles.ts
2305
- var import_fs11 = require("fs"), import_promises3 = require("fs/promises");
2306
- var copyTemplateFiles = async (filenames) => {
3644
+ var import_fs16 = require("fs"), import_promises2 = require("fs/promises"), import_path18 = __toESM(require("path"));
3645
+ var copyTemplateFiles = async (files) => {
2307
3646
  await Promise.all(
2308
- filenames.map(async (filename) => {
2309
- let templatePath = getTemplatePath(filename), targetPath = `./${filename}`;
2310
- if ((0, import_fs11.existsSync)(templatePath) && (0, import_fs11.existsSync)(targetPath)) {
2311
- let content = await (0, import_promises3.readFile)(templatePath), rewritten = applySubstitutions2(filename, content);
2312
- await (0, import_promises3.writeFile)(targetPath, rewritten);
2313
- }
3647
+ files.map(async (file) => {
3648
+ let templatePath, targetPath, force = !1;
3649
+ typeof file == "string" ? (templatePath = getTemplatePath(file), targetPath = `./${file}`) : (templatePath = file.sourcePath ?? getTemplatePath(file.source ?? file.target), targetPath = `./${file.target}`, force = file.force ?? !1), (0, import_fs16.existsSync)(templatePath) && (force || (0, import_fs16.existsSync)(targetPath)) && (await (0, import_promises2.mkdir)(import_path18.default.dirname(targetPath), { recursive: !0 }), await (0, import_promises2.copyFile)(templatePath, targetPath));
2314
3650
  })
2315
3651
  );
2316
- };
3652
+ }, overlayFileCopy = (overlayDir, sourceFilename, targetFilename) => ({
3653
+ sourcePath: getOverlayTemplatePath(overlayDir, sourceFilename),
3654
+ target: targetFilename
3655
+ });
2317
3656
 
2318
3657
  // src/commands/up/utils/updateManifestCompatibility.ts
2319
3658
  init_manifestManager();
@@ -2337,34 +3676,49 @@ async function updateManifestCompatibility() {
2337
3676
  }
2338
3677
 
2339
3678
  // src/commands/up/utils/updatePackageDependencies.ts
2340
- var import_fs12 = require("fs"), import_promises4 = require("fs/promises");
3679
+ var import_fs17 = require("fs"), import_promises3 = require("fs/promises");
2341
3680
  var updatePackageDependencies = async (dependencies) => {
2342
3681
  let packageJsonPath = "./package.json", templatePackageJsonPath = getTemplatePath("package.json");
2343
- if (!(0, import_fs12.existsSync)(packageJsonPath) || !(0, import_fs12.existsSync)(templatePackageJsonPath))
3682
+ if (!(0, import_fs17.existsSync)(packageJsonPath) || !(0, import_fs17.existsSync)(templatePackageJsonPath))
2344
3683
  return;
2345
- let packageJsonContent = await (0, import_promises4.readFile)(packageJsonPath, "utf-8"), templatePackageJsonRaw = await (0, import_promises4.readFile)(templatePackageJsonPath), templatePackageJsonContent = applySubstitutions2(
2346
- "package.json",
2347
- templatePackageJsonRaw
2348
- ).toString("utf8"), packageJson = JSON.parse(packageJsonContent), templatePackageJson = JSON.parse(templatePackageJsonContent), updated = !1;
3684
+ let packageJsonContent = await (0, import_promises3.readFile)(packageJsonPath, "utf-8"), templatePackageJsonContent = await (0, import_promises3.readFile)(templatePackageJsonPath, "utf-8"), packageJson = JSON.parse(packageJsonContent), templatePackageJson = JSON.parse(templatePackageJsonContent), updated = !1;
2349
3685
  dependencies.forEach((dep) => {
2350
3686
  packageJson.dependencies?.[dep] && templatePackageJson.dependencies?.[dep] && packageJson.dependencies[dep] !== templatePackageJson.dependencies[dep] && (packageJson.dependencies[dep] = templatePackageJson.dependencies[dep], updated = !0);
2351
- }), updated && await (0, import_promises4.writeFile)(packageJsonPath, JSON.stringify(packageJson, null, 4) + `
3687
+ }), updated && await (0, import_promises3.writeFile)(packageJsonPath, JSON.stringify(packageJson, null, 4) + `
2352
3688
  `, "utf-8");
2353
3689
  };
2354
3690
 
2355
3691
  // src/commands/up/index.ts
2356
- var templateFiles = ["manifest.schema.json", "vite.config.ts"];
3692
+ var npmrcPath = "./.npmrc", npmrcTemplateFilename = "npmrc.template", sharedFiles = [
3693
+ "manifest.schema.json",
3694
+ "vite.config.ts",
3695
+ { source: "proxy.ts", target: "proxy.ts", force: !0 }
3696
+ ];
3697
+ async function isNpmrcOutdated() {
3698
+ let templatePath = getOverlayTemplatePath(overlayDirName, npmrcTemplateFilename);
3699
+ if (!(0, import_fs18.existsSync)(npmrcPath) || !(0, import_fs18.existsSync)(templatePath))
3700
+ return !1;
3701
+ let [currentNpmrc, templateNpmrc] = await Promise.all([
3702
+ (0, import_promises4.readFile)(npmrcPath, "utf-8"),
3703
+ (0, import_promises4.readFile)(templatePath, "utf-8")
3704
+ ]);
3705
+ return currentNpmrc !== templateNpmrc;
3706
+ }
2357
3707
  async function up() {
2358
- await copyTemplateFiles(templateFiles), await updateManifestCompatibility(), await updatePackageDependencies(templateDeps2);
3708
+ let shouldCleanNpmCache = await isNpmrcOutdated();
3709
+ await copyTemplateFiles([
3710
+ ...sharedFiles,
3711
+ { ...overlayFileCopy(overlayDirName, npmrcTemplateFilename, ".npmrc"), force: !0 }
3712
+ ]), await updateManifestCompatibility(), await updatePackageDependencies(templateDeps), shouldCleanNpmCache && await execCommand("npm cache clean --force"), await execCommand("npm i");
2359
3713
  }
2360
3714
 
2361
3715
  // src/utils/getVersion.ts
2362
- var import_fs13 = require("fs"), import_path13 = require("path"), UNKNOWN_VERSION = "unknown", CANDIDATES = ["..", "../.."], findVersionInPackageJson = (startDir) => {
3716
+ var import_fs19 = require("fs"), import_path19 = require("path"), UNKNOWN_VERSION = "unknown", CANDIDATES = ["..", "../.."], findVersionInPackageJson = (startDir) => {
2363
3717
  for (let rel of CANDIDATES) {
2364
- let path18 = (0, import_path13.resolve)(startDir, rel, "package.json");
2365
- if ((0, import_fs13.existsSync)(path18))
3718
+ let path24 = (0, import_path19.resolve)(startDir, rel, "package.json");
3719
+ if ((0, import_fs19.existsSync)(path24))
2366
3720
  try {
2367
- let pkg = JSON.parse((0, import_fs13.readFileSync)(path18, "utf-8"));
3721
+ let pkg = JSON.parse((0, import_fs19.readFileSync)(path24, "utf-8"));
2368
3722
  if (typeof pkg.version == "string") return pkg.version;
2369
3723
  } catch {
2370
3724
  }
@@ -2377,10 +3731,10 @@ init_verbose();
2377
3731
  init_withErrorHandling();
2378
3732
  async function main() {
2379
3733
  let program = new import_commander2.Command(), version = getVersion();
2380
- await checkUpdate(version), program.name(CLI_NAME2).description(CLI_DESCRIPTION2).version(version).option("--verbose", "enable verbose output"), CLI_HELP_TEXT2 && program.addHelpText("before", CLI_HELP_TEXT2), program.hook("preAction", (thisCommand) => {
3734
+ shouldRunUpdateCheck(process.argv.slice(2)) && await checkUpdate(version), program.name(CLI_NAME2).description(CLI_DESCRIPTION2).version(version).option("--verbose", "enable verbose output"), CLI_HELP_TEXT2 && program.addHelpText("before", CLI_HELP_TEXT2), program.hook("preAction", (thisCommand) => {
2381
3735
  setVerboseEnabled(!!thisCommand.opts().verbose);
2382
3736
  }), 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(
2383
3737
  "start a tunnel to connect your local code with the app running in the development environment"
2384
- ).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);
3738
+ ).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(typeof process.exitCode == "number" ? process.exitCode : 0);
2385
3739
  }
2386
3740
  main();