@weavix/cli 0.7.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.js CHANGED
@@ -58,9 +58,6 @@ var impl, CLI_NAME2, CLI_DESCRIPTION2, CLI_HELP_TEXT2, CREATE_SERVICES2, init_me
58
58
  });
59
59
 
60
60
  // src/core/cliConfig/manager.ts
61
- function getConfigPath() {
62
- return CONFIG_FILE;
63
- }
64
61
  function readConfig() {
65
62
  if (cached !== void 0)
66
63
  return cached;
@@ -76,9 +73,6 @@ function readConfig() {
76
73
  function writeConfig(config) {
77
74
  (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;
78
75
  }
79
- function clearConfig() {
80
- (0, import_fs.existsSync)(CONFIG_FILE) && (0, import_fs.rmSync)(CONFIG_FILE), cached = null;
81
- }
82
76
  var import_fs, os, import_path, CONFIG_DIR, CONFIG_FILE, cached, init_manager = __esm({
83
77
  "src/core/cliConfig/manager.ts"() {
84
78
  "use strict";
@@ -86,94 +80,6 @@ var import_fs, os, import_path, CONFIG_DIR, CONFIG_FILE, cached, init_manager =
86
80
  }
87
81
  });
88
82
 
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
- };
100
- }
101
- var init_policy = __esm({
102
- "src/core/doctor/policy.ts"() {
103
- "use strict";
104
- }
105
- });
106
-
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: []
117
- };
118
- }
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"() {
168
- "use strict";
169
- STATUS_DISPLAY = {
170
- pass: { icon: "\u2713", label: "PASS" },
171
- warn: { icon: "\u26A0", label: "WARN" },
172
- fail: { icon: "\u2717", label: "FAIL" }
173
- };
174
- }
175
- });
176
-
177
83
  // src/core/auth/keyringAuthStorage.ts
178
84
  var fs, import_keyring, parseAuthData, readLegacyAuthData, removeLegacyAuthData, createKeyringAuthStorage, init_keyringAuthStorage = __esm({
179
85
  "src/core/auth/keyringAuthStorage.ts"() {
@@ -257,192 +163,511 @@ var os2, path2, authFile, authStorage, getToken, externalAuthManager, init_authM
257
163
  }
258
164
  });
259
165
 
166
+ // src/distributions/external/auth.ts
167
+ var auth_exports = {};
168
+ __export(auth_exports, {
169
+ getAuthHeader: () => getAuthHeader,
170
+ getPlatformHeaders: () => getPlatformHeaders
171
+ });
172
+ function getAuthHeader() {
173
+ let token = externalAuthManager.token;
174
+ return token ? `OAuth ${token}` : null;
175
+ }
176
+ function getPlatformHeaders() {
177
+ let orgId = readConfig()?.api?.platformOrgId;
178
+ return orgId ? { "X-Org-ID": orgId } : {};
179
+ }
180
+ var init_auth = __esm({
181
+ "src/distributions/external/auth.ts"() {
182
+ "use strict";
183
+ init_manager();
184
+ init_authManager();
185
+ }
186
+ });
187
+
188
+ // src/distribution/auth.ts
189
+ var impl2, getAuthHeader2, getPlatformHeaders2, init_auth2 = __esm({
190
+ "src/distribution/auth.ts"() {
191
+ "use strict";
192
+ init_flag();
193
+ impl2 = (init_auth(), __toCommonJS(auth_exports)), { getAuthHeader: getAuthHeader2, getPlatformHeaders: getPlatformHeaders2 } = impl2;
194
+ }
195
+ });
196
+
197
+ // src/utils/verbose.ts
198
+ function setVerboseEnabled(value) {
199
+ verboseEnabled = value;
200
+ }
201
+ function isVerboseEnabled() {
202
+ return verboseEnabled;
203
+ }
204
+ function writeVerboseArtifact(relativePath, content) {
205
+ let targetPath = import_path2.default.resolve(".yaweavix-debug", relativePath);
206
+ return import_fs2.default.mkdirSync(import_path2.default.dirname(targetPath), { recursive: !0 }), import_fs2.default.writeFileSync(targetPath, content), targetPath;
207
+ }
208
+ var import_fs2, import_path2, verboseEnabled, init_verbose = __esm({
209
+ "src/utils/verbose.ts"() {
210
+ "use strict";
211
+ import_fs2 = __toESM(require("fs")), import_path2 = __toESM(require("path")), verboseEnabled = !1;
212
+ }
213
+ });
214
+
215
+ // src/utils/logger.ts
216
+ function success(message) {
217
+ console.info(import_picocolors.default.green(`\u2705 ${message}`)), newLine();
218
+ }
219
+ function error(messageOrErr, err) {
220
+ let message = messageOrErr instanceof Error ? messageOrErr.message : messageOrErr;
221
+ console.error(import_picocolors.default.red(`\u274C ${message}`)), err instanceof Error && console.error(import_picocolors.default.red(err.message)), newLine();
222
+ }
223
+ function warning(message) {
224
+ console.warn(import_picocolors.default.yellow(`\u26A0\uFE0F ${message}`)), newLine();
225
+ }
226
+ function info(message) {
227
+ console.info(message), newLine();
228
+ }
229
+ function verbose(message) {
230
+ isVerboseEnabled() && (console.info(import_picocolors.default.dim(message)), newLine());
231
+ }
232
+ function suggest(command) {
233
+ console.info(`Run: ${command}`), newLine();
234
+ }
235
+ function newLine(count = 1) {
236
+ console.info(`
237
+ `.repeat(count - 1));
238
+ }
239
+ function separator(char = "\u2500", length = 60) {
240
+ console.info(import_picocolors.default.dim(char.repeat(length))), newLine();
241
+ }
242
+ function commands(title, data) {
243
+ newLine(), title && (console.info(import_picocolors.default.bold(import_picocolors.default.cyan(`${title}:`))), newLine()), data.forEach((cmd) => {
244
+ console.info(import_picocolors.default.dim(" $ ") + import_picocolors.default.white(cmd));
245
+ }), newLine();
246
+ }
247
+ var import_picocolors, logger, logger_default, init_logger = __esm({
248
+ "src/utils/logger.ts"() {
249
+ "use strict";
250
+ import_picocolors = __toESM(require("picocolors"));
251
+ init_verbose();
252
+ logger = {
253
+ success,
254
+ error,
255
+ warning,
256
+ info,
257
+ verbose,
258
+ suggest,
259
+ newLine,
260
+ separator,
261
+ commands
262
+ }, logger_default = logger;
263
+ }
264
+ });
265
+
260
266
  // src/distributions/external/hosts.ts
261
267
  var hosts_exports = {};
262
268
  __export(hosts_exports, {
263
- getBuckets: () => getBuckets,
264
- getMdsEndpoint: () => getMdsEndpoint,
265
269
  getOAuthTokenUrl: () => getOAuthTokenUrl,
266
270
  getPlatformApiPrefix: () => getPlatformApiPrefix,
267
271
  getPlatformBaseUrl: () => getPlatformBaseUrl,
268
272
  getPluginDownloadBase: () => getPluginDownloadBase,
269
- getS3Endpoint: () => getS3Endpoint,
270
- getS3Region: () => getS3Region,
271
- getTrackerBaseUrl: () => getTrackerBaseUrl,
272
273
  getUpdateCheckInfo: () => getUpdateCheckInfo
273
274
  });
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;
279
- }
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;
285
- }
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
275
  function getPluginDownloadBase(env) {
306
276
  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;
277
+ return PLUGIN_DEBUG_DOWNLOAD_BASE;
278
+ throw new Error(`Plugin download base is not available for environment "${env}".`);
279
+ }
280
+ function normalizeBaseUrl(value) {
281
+ return value.replace(/\/+$/, "");
314
282
  }
315
283
  function getPlatformBaseUrl() {
316
- return readConfig()?.api?.platformBaseUrl ?? PLATFORM_BASE_URL;
284
+ let envOverride = process.env[PLATFORM_BASE_URL_ENV]?.trim();
285
+ return envOverride ? normalizeBaseUrl(envOverride) : PLATFORM_BASE_URL;
317
286
  }
318
287
  function getPlatformApiPrefix() {
319
288
  return "/api/cli/v1";
320
289
  }
321
- function getTrackerBaseUrl() {
322
- return TRACKER_BASE_URL;
323
- }
324
290
  function getOAuthTokenUrl() {
325
- return readConfig()?.auth?.oauthUrl ?? OAUTH_TOKEN_URL;
291
+ return OAUTH_TOKEN_URL;
326
292
  }
327
293
  function getUpdateCheckInfo() {
328
294
  return null;
329
295
  }
330
- var TRACKER_BASE_URL, PLATFORM_BASE_URL, OAUTH_TOKEN_URL, init_hosts = __esm({
296
+ var PLATFORM_BASE_URL, PLATFORM_BASE_URL_ENV, OAUTH_TOKEN_URL, PLUGIN_DEBUG_DOWNLOAD_BASE, init_hosts = __esm({
331
297
  "src/distributions/external/hosts.ts"() {
332
298
  "use strict";
333
- init_manager();
334
- TRACKER_BASE_URL = "https://api.tracker.yandex.net/v3", PLATFORM_BASE_URL = "https://plugins.cli-api.tracker.yandex.net", OAUTH_TOKEN_URL = "https://oauth.yandex.ru/authorize?response_type=token&client_id=f57901dffe3849cbb3dbb5f616158e28";
299
+ PLATFORM_BASE_URL = "https://plugins.cli-api.tracker.yandex.net", PLATFORM_BASE_URL_ENV = "TRACKER_CLI_PLATFORM_BASE_URL", OAUTH_TOKEN_URL = "https://oauth.yandex.ru/authorize?response_type=token&client_id=f57901dffe3849cbb3dbb5f616158e28", PLUGIN_DEBUG_DOWNLOAD_BASE = "http://localhost:5173/plugins-debug";
335
300
  }
336
301
  });
337
302
 
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)
353
- throw new Error(`Not authenticated. Run "${CLI_NAME} login" first.`);
354
- let requestHeaders = {
355
- Authorization: `OAuth ${token}`,
356
- "X-Org-ID": ORG_ID,
357
- Accept: "application/json",
358
- ...headers
359
- }, requestBody;
360
- if (formData) {
361
- let formHeaders = formData.getHeaders?.();
362
- Object.assign(requestHeaders, formHeaders), requestBody = formData;
363
- } else body && method !== "GET" && (requestHeaders["Content-Type"] = "application/json", requestBody = JSON.stringify(body));
364
- let queryString = buildQueryString(queryParams), url = `${TRACKER_BASE_URL2}${endpoint}${queryString}`, response = await (0, import_node_fetch.default)(url, {
365
- method,
366
- headers: requestHeaders,
367
- body: requestBody
368
- });
369
- if (!response.ok) {
370
- let errorText = await response.text(), errorMessage = `Tracker API error ${response.status}: ${errorText}`;
371
- try {
372
- let errorJson = JSON.parse(errorText);
373
- errorJson.message && (errorMessage = `Tracker API error ${response.status}: ${errorJson.message}`);
374
- } catch {
375
- }
376
- throw new Error(errorMessage);
377
- }
378
- return parseResponse(response);
379
- }
380
- var import_node_fetch, TRACKER_BASE_URL2, ORG_ID, init_trackerApiRequest = __esm({
381
- "src/distributions/external/trackerApiRequest.ts"() {
303
+ // src/distribution/hosts.ts
304
+ var impl3, getS3Endpoint, getMdsEndpoint, getS3Region, getBuckets, getPluginDownloadBase2, getPlatformBaseUrl2, getPlatformApiPrefix2, getTrackerBaseUrl, getOAuthTokenUrl2, getUpdateCheckInfo2, init_hosts2 = __esm({
305
+ "src/distribution/hosts.ts"() {
382
306
  "use strict";
383
- import_node_fetch = __toESM(require("node-fetch"));
384
- init_authManager();
385
- init_meta();
386
- TRACKER_BASE_URL2 = "https://api.tracker.yandex.net/v3", ORG_ID = "8470884";
307
+ init_flag();
308
+ impl3 = (init_hosts(), __toCommonJS(hosts_exports)), {
309
+ getS3Endpoint,
310
+ getMdsEndpoint,
311
+ getS3Region,
312
+ getBuckets,
313
+ getPluginDownloadBase: getPluginDownloadBase2,
314
+ getPlatformBaseUrl: getPlatformBaseUrl2,
315
+ getPlatformApiPrefix: getPlatformApiPrefix2,
316
+ getTrackerBaseUrl,
317
+ getOAuthTokenUrl: getOAuthTokenUrl2,
318
+ getUpdateCheckInfo: getUpdateCheckInfo2
319
+ } = impl3;
387
320
  }
388
321
  });
389
322
 
390
- // src/distributions/external/doctorChecks.ts
391
- var doctorChecks_exports = {};
392
- __export(doctorChecks_exports, {
393
- checkDistribution: () => checkDistribution
323
+ // src/api/constants.ts
324
+ var mockedCategories, init_constants = __esm({
325
+ "src/api/constants.ts"() {
326
+ "use strict";
327
+ init_hosts2();
328
+ init_hosts2();
329
+ mockedCategories = {
330
+ items: [
331
+ {
332
+ slug: "integrations",
333
+ name: {
334
+ ru: "\u0418\u043D\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438",
335
+ en: "Integrations"
336
+ }
337
+ },
338
+ {
339
+ slug: "analytics",
340
+ name: {
341
+ ru: "\u0410\u043D\u0430\u043B\u0438\u0442\u0438\u043A\u0430",
342
+ en: "Analytics"
343
+ }
344
+ },
345
+ {
346
+ slug: "planning",
347
+ name: {
348
+ ru: "\u041F\u043B\u0430\u043D\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435",
349
+ en: "Planning"
350
+ }
351
+ },
352
+ {
353
+ slug: "development",
354
+ name: {
355
+ ru: "\u0420\u0430\u0437\u0440\u0430\u0431\u043E\u0442\u043A\u0430",
356
+ en: "Development"
357
+ }
358
+ },
359
+ {
360
+ slug: "automations",
361
+ name: {
362
+ ru: "\u0410\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438",
363
+ en: "Automations"
364
+ }
365
+ },
366
+ {
367
+ slug: "productivity",
368
+ name: {
369
+ ru: "\u041F\u0440\u043E\u0434\u0443\u043A\u0442\u0438\u0432\u043D\u043E\u0441\u0442\u044C",
370
+ en: "Productivity"
371
+ }
372
+ },
373
+ {
374
+ slug: "entertainment",
375
+ name: {
376
+ ru: "\u0420\u0430\u0437\u0432\u043B\u0435\u0447\u0435\u043D\u0438\u044F",
377
+ en: "Entertainment"
378
+ }
379
+ },
380
+ {
381
+ slug: "ai-assistants",
382
+ name: {
383
+ ru: "\u0418\u0418-\u043F\u043E\u043C\u043E\u0449\u043D\u0438\u043A\u0438",
384
+ en: "AI Assistants"
385
+ }
386
+ },
387
+ {
388
+ slug: "support",
389
+ name: {
390
+ ru: "\u041F\u043E\u0434\u0434\u0435\u0440\u0436\u043A\u0430",
391
+ en: "Support"
392
+ }
393
+ },
394
+ {
395
+ slug: "security",
396
+ name: {
397
+ ru: "\u0411\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u043E\u0441\u0442\u044C",
398
+ en: "Security"
399
+ }
400
+ }
401
+ ]
402
+ };
403
+ }
394
404
  });
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
405
+
406
+ // src/api/requestDebug.ts
407
+ function redactHeaders(headers) {
408
+ let result = {};
409
+ for (let [key, value] of Object.entries(headers))
410
+ if (key.toLowerCase() === "authorization") {
411
+ let [scheme] = value.split(" ");
412
+ result[key] = scheme ? `${scheme} ${REDACTED}` : REDACTED;
413
+ } else
414
+ result[key] = value;
415
+ return result;
416
+ }
417
+ function formatDebugBody(body, formData) {
418
+ if (formData) {
419
+ let size = "";
420
+ try {
421
+ let length = formData.getLengthSync?.();
422
+ typeof length == "number" && (size = `, ~${length} bytes`);
423
+ } catch {
416
424
  }
417
- });
425
+ return `[multipart/form-data${size}] (binary body, e.g. plugin archive \u2014 not dumped)`;
426
+ }
427
+ return typeof body == "string" ? body : "(none)";
418
428
  }
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
+ function buildFailureDebug(params) {
430
+ let { method, url, status, headers, body, formData } = params;
431
+ return [
432
+ "Platform API request failed \u2014 debug info (Authorization redacted):",
433
+ ` method: ${method}`,
434
+ ` url: ${url}`,
435
+ ` status: ${status ?? "(no HTTP response \u2014 network/transport error)"}`,
436
+ ` headers: ${JSON.stringify(redactHeaders(headers), null, 2)}`,
437
+ ` body: ${formatDebugBody(body, formData)}`
438
+ ].join(`
439
+ `);
440
+ }
441
+ var REDACTED, init_requestDebug = __esm({
442
+ "src/api/requestDebug.ts"() {
443
+ "use strict";
444
+ REDACTED = "****redacted****";
445
+ }
446
+ });
447
+
448
+ // src/api/platformApiRequest.ts
449
+ function setPlatformIamToken(token) {
450
+ platformIamToken = token?.trim() || void 0;
451
+ }
452
+ function buildRequestHeaders(headers, formData) {
453
+ let authHeader = getAuthHeader2();
454
+ if (!platformIamToken && !authHeader)
455
+ throw new Error(`Not authenticated. Run "${CLI_NAME2} login" first.`);
456
+ let requestHeaders = {
457
+ Accept: "*/*",
458
+ ...platformIamToken ? { "x-iam-token": platformIamToken } : { Authorization: authHeader },
459
+ ...getPlatformHeaders2(),
460
+ ...headers
461
+ };
462
+ return formData || (requestHeaders["Content-Type"] = "application/json"), requestHeaders;
463
+ }
464
+ function buildRequestBody(method, body, formData) {
465
+ if (formData) {
466
+ let formHeaders = formData.getHeaders?.();
467
+ return {
468
+ body: formData,
469
+ headers: formHeaders || {}
429
470
  };
430
- addCheck(report, {
431
- id: "distribution.hosts",
432
- title: "External host configuration",
433
- message: "External host configuration resolved.",
434
- data
471
+ }
472
+ return body && method !== "GET" ? { body: JSON.stringify(body) } : {};
473
+ }
474
+ function buildQueryString(queryParams) {
475
+ if (!queryParams || Object.keys(queryParams).length === 0)
476
+ return "";
477
+ let params = new URLSearchParams();
478
+ return Object.entries(queryParams).forEach(([key, value]) => {
479
+ params.append(key, String(value));
480
+ }), `?${params.toString()}`;
481
+ }
482
+ async function parseResponse(response) {
483
+ 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();
484
+ }
485
+ async function platformApiRequest(endpoint, options = {}) {
486
+ let { method = "GET", body, headers = {}, formData, queryParams } = options, requestHeaders = buildRequestHeaders(headers, formData), { body: requestBody, headers: additionalHeaders } = buildRequestBody(
487
+ method,
488
+ body,
489
+ formData
490
+ ), requestOptions = {
491
+ method,
492
+ headers: { ...requestHeaders, ...additionalHeaders },
493
+ body: requestBody
494
+ }, queryString = buildQueryString(queryParams), url = `${getPlatformBaseUrl2()}${getPlatformApiPrefix2()}${endpoint}${queryString}`, controller = new AbortController(), timeout = setTimeout(() => controller.abort(), PLATFORM_API_TIMEOUT_MS), responseStatus;
495
+ if (isVerboseEnabled() && (logger_default.info(
496
+ `[platform-api-debug] Request: method=${method} url=${url} hasBody=${!!body} hasFormData=${!!formData} timeoutMs=${PLATFORM_API_TIMEOUT_MS}`
497
+ ), body !== void 0 && logger_default.info(`[platform-api-debug] Request body: ${JSON.stringify(body)}`), formData)) {
498
+ let debugPath = writeVerboseArtifact(
499
+ "requests/latest-form-data.txt",
500
+ `method=${method}
501
+ url=${url}
502
+ headers=${JSON.stringify({ ...requestHeaders, ...additionalHeaders }, null, 2)}
503
+ formData=present
504
+ `
505
+ );
506
+ logger_default.info(`[platform-api-debug] Saved form-data request metadata to ${debugPath}`);
507
+ }
508
+ try {
509
+ let response = await (0, import_node_fetch.default)(url, {
510
+ ...requestOptions,
511
+ signal: controller.signal
435
512
  });
513
+ if (responseStatus = response.status, isVerboseEnabled() && logger_default.info(
514
+ `[platform-api-debug] Response: method=${method} url=${url} status=${response.status} contentType=${response.headers.get("content-type") ?? "n/a"}`
515
+ ), !response.ok) {
516
+ let errorText = await response.text(), errorMessage = errorText;
517
+ try {
518
+ let errorJson = JSON.parse(errorText);
519
+ errorJson.message && (errorMessage = errorJson.message);
520
+ } catch {
521
+ }
522
+ throw new PlatformApiError(
523
+ response.status,
524
+ `HTTP ${response.status} ${response.statusText}: ${errorMessage}`
525
+ );
526
+ }
527
+ return parseResponse(response);
436
528
  } 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
- });
529
+ throw logger_default.error(
530
+ buildFailureDebug({
531
+ method,
532
+ url,
533
+ status: responseStatus,
534
+ headers: requestOptions.headers,
535
+ body: requestBody,
536
+ formData
537
+ })
538
+ ), error2 instanceof Error && error2.name === "AbortError" ? new Error(
539
+ `Platform API request timed out after ${PLATFORM_API_TIMEOUT_MS}ms: ${method} ${url}`
540
+ ) : error2;
541
+ } finally {
542
+ clearTimeout(timeout);
543
+ }
544
+ }
545
+ var import_node_fetch, PlatformApiError, PLATFORM_API_TIMEOUT_MS, platformIamToken, init_platformApiRequest = __esm({
546
+ "src/api/platformApiRequest.ts"() {
547
+ "use strict";
548
+ import_node_fetch = __toESM(require("node-fetch"));
549
+ init_auth2();
550
+ init_meta2();
551
+ init_logger();
552
+ init_verbose();
553
+ init_constants();
554
+ init_requestDebug();
555
+ PlatformApiError = class extends Error {
556
+ constructor(status, message) {
557
+ super(message), this.status = status, this.name = "PlatformApiError";
558
+ }
559
+ }, PLATFORM_API_TIMEOUT_MS = Number(process.env.TRACKER_CLI_PLATFORM_TIMEOUT_MS || 3e4);
560
+ }
561
+ });
562
+
563
+ // src/api/user.ts
564
+ async function verifyToken() {
565
+ try {
566
+ return await platformApiRequest("/plugins/my", { method: "GET" }), !0;
567
+ } catch {
568
+ return !1;
569
+ }
570
+ }
571
+ var init_user = __esm({
572
+ "src/api/user.ts"() {
573
+ "use strict";
574
+ init_platformApiRequest();
575
+ }
576
+ });
577
+
578
+ // src/core/doctor/policy.ts
579
+ function createDoctorPolicy(options) {
580
+ let publish = !!options.publish, publishOnlyStatus = publish ? "fail" : "warn";
581
+ return {
582
+ mode: publish ? "publish" : "debug",
583
+ marketplaceAssetsStatus: publishOnlyStatus,
584
+ manifestPermissionsStatus: publishOnlyStatus,
585
+ manifestSupportStatus: publishOnlyStatus,
586
+ distMissingStatus: publishOnlyStatus,
587
+ authMissingStatus: publishOnlyStatus
588
+ };
589
+ }
590
+ var init_policy = __esm({
591
+ "src/core/doctor/policy.ts"() {
592
+ "use strict";
444
593
  }
594
+ });
595
+
596
+ // src/core/doctor/report.ts
597
+ function createDoctorReport() {
598
+ return {
599
+ ok: !1,
600
+ summary: {
601
+ passed: 0,
602
+ warnings: 0,
603
+ failures: 0
604
+ },
605
+ checks: []
606
+ };
607
+ }
608
+ function addCheck(report, check) {
609
+ report.checks.push({
610
+ ...check,
611
+ status: check.status || "pass"
612
+ });
613
+ }
614
+ function updateSummary(report) {
615
+ 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;
616
+ report.summary = {
617
+ passed,
618
+ warnings,
619
+ failures
620
+ }, report.ok = failures === 0;
621
+ }
622
+ function statusBadge(status) {
623
+ let display = STATUS_DISPLAY[status];
624
+ return `${display.icon} [${display.label}]`;
625
+ }
626
+ function formatReport(report) {
627
+ let lines = ["Tracker Plugin Doctor", ""];
628
+ 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:");
629
+ for (let check of report.checks)
630
+ lines.push(` ${statusBadge(check.status)} ${check.title}: ${check.message}`), check.action && lines.push(` Action: ${check.action}`);
631
+ return lines.push(
632
+ "",
633
+ `Summary: \u2713 ${report.summary.passed} passed, \u26A0 ${report.summary.warnings} warning(s), \u2717 ${report.summary.failures} failure(s).`
634
+ ), lines.push(
635
+ 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."
636
+ ), `${lines.join(`
637
+ `)}
638
+ `;
639
+ }
640
+ function writeStdout(content) {
641
+ return new Promise((resolve2, reject) => {
642
+ process.stdout.write(content, (error2) => {
643
+ if (error2) {
644
+ reject(error2);
645
+ return;
646
+ }
647
+ resolve2();
648
+ });
649
+ });
445
650
  }
651
+ async function finishDoctor(report, options) {
652
+ updateSummary(report), await writeStdout(options.json ? `${JSON.stringify(report, null, 4)}
653
+ ` : formatReport(report)), report.ok || (process.exitCode = 1);
654
+ }
655
+ var STATUS_DISPLAY, init_report = __esm({
656
+ "src/core/doctor/report.ts"() {
657
+ "use strict";
658
+ STATUS_DISPLAY = {
659
+ pass: { icon: "\u2713", label: "PASS" },
660
+ warn: { icon: "\u26A0", label: "WARN" },
661
+ fail: { icon: "\u2717", label: "FAIL" }
662
+ };
663
+ }
664
+ });
665
+
666
+ // src/distributions/external/doctorChecks.ts
667
+ var doctorChecks_exports = {};
668
+ __export(doctorChecks_exports, {
669
+ checkDistribution: () => checkDistribution
670
+ });
446
671
  async function checkExternalAuth(report, {
447
672
  required,
448
673
  useNetwork
@@ -468,25 +693,29 @@ async function checkExternalAuth(report, {
468
693
  data: {
469
694
  storage: "system credential store"
470
695
  }
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
- });
486
- }
696
+ }), readConfig()?.api?.platformOrgId ? addCheck(report, {
697
+ id: "auth.organization",
698
+ title: "Organization ID",
699
+ message: "Organization ID is configured."
700
+ }) : addCheck(report, {
701
+ id: "auth.organization",
702
+ title: "Organization ID",
703
+ status: authStatus,
704
+ message: "Organization ID is not configured.",
705
+ action: "Run weavix login to set your Organization ID."
706
+ }), !useNetwork)
707
+ return;
708
+ let isValid = await verifyToken();
709
+ addCheck(report, {
710
+ id: "auth.platform.network",
711
+ title: "Platform auth network",
712
+ status: isValid ? "pass" : "fail",
713
+ message: isValid ? "Verified Platform auth successfully." : "Platform auth verification failed.",
714
+ ...isValid ? {} : { action: "Check network access, org access, and rerun weavix login." }
715
+ });
487
716
  }
488
717
  async function checkDistribution(report, _projectRoot, options, policy = createDoctorPolicy(options)) {
489
- report.distribution = DISTRIBUTION, checkCliConfig(report), checkHostResolution(report), await checkExternalAuth(report, {
718
+ report.distribution = DISTRIBUTION, await checkExternalAuth(report, {
490
719
  required: policy.authMissingStatus === "fail",
491
720
  useNetwork: !!options.network
492
721
  });
@@ -494,41 +723,40 @@ async function checkDistribution(report, _projectRoot, options, policy = createD
494
723
  var DISTRIBUTION, init_doctorChecks = __esm({
495
724
  "src/distributions/external/doctorChecks.ts"() {
496
725
  "use strict";
726
+ init_user();
497
727
  init_manager();
498
728
  init_policy();
499
729
  init_report();
500
730
  init_authManager();
501
- init_hosts();
502
- init_trackerApiRequest();
503
731
  DISTRIBUTION = "external";
504
732
  }
505
733
  });
506
734
 
507
735
  // src/distribution/doctorChecks.ts
508
- var impl2, checkDistribution2, init_doctorChecks2 = __esm({
736
+ var impl4, checkDistribution2, init_doctorChecks2 = __esm({
509
737
  "src/distribution/doctorChecks.ts"() {
510
738
  "use strict";
511
739
  init_flag();
512
- impl2 = (init_doctorChecks(), __toCommonJS(doctorChecks_exports)), { checkDistribution: checkDistribution2 } = impl2;
740
+ impl4 = (init_doctorChecks(), __toCommonJS(doctorChecks_exports)), { checkDistribution: checkDistribution2 } = impl4;
513
741
  }
514
742
  });
515
743
 
516
744
  // src/core/doctor/distChecks.ts
517
745
  function resolveDistEntrypoint(distDir, entrypoint) {
518
- if (import_path2.default.isAbsolute(entrypoint))
746
+ if (import_path3.default.isAbsolute(entrypoint))
519
747
  return {
520
748
  error: `${entrypoint} is absolute`
521
749
  };
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) ? {
750
+ let filePath = import_path3.default.resolve(distDir, import_path3.default.normalize(entrypoint)), relative = import_path3.default.relative(distDir, filePath);
751
+ return relative.startsWith("..") || import_path3.default.isAbsolute(relative) ? {
524
752
  error: `${entrypoint} escapes dist`
525
753
  } : {
526
754
  filePath
527
755
  };
528
756
  }
529
757
  async function checkDist(report, projectRoot, entries, policy) {
530
- let distDir = import_path2.default.join(projectRoot, "dist");
531
- if (!import_fs2.default.existsSync(distDir)) {
758
+ let distDir = import_path3.default.join(projectRoot, "dist");
759
+ if (!import_fs3.default.existsSync(distDir)) {
532
760
  addCheck(report, {
533
761
  id: "dist.exists",
534
762
  title: "dist directory",
@@ -538,7 +766,7 @@ async function checkDist(report, projectRoot, entries, policy) {
538
766
  });
539
767
  return;
540
768
  }
541
- if (!import_fs2.default.statSync(distDir).isDirectory()) {
769
+ if (!import_fs3.default.statSync(distDir).isDirectory()) {
542
770
  addCheck(report, {
543
771
  id: "dist.exists",
544
772
  title: "dist directory",
@@ -573,7 +801,7 @@ async function checkDist(report, projectRoot, entries, policy) {
573
801
  );
574
802
  continue;
575
803
  }
576
- (!import_fs2.default.existsSync(resolved.filePath) || !import_fs2.default.statSync(resolved.filePath).isFile()) && missingEntrypoints.push(entrypoint);
804
+ (!import_fs3.default.existsSync(resolved.filePath) || !import_fs3.default.statSync(resolved.filePath).isFile()) && missingEntrypoints.push(entrypoint);
577
805
  }
578
806
  invalidEntrypoints.length > 0 ? addCheck(report, {
579
807
  id: "dist.entrypoints.valid",
@@ -597,10 +825,10 @@ async function checkDist(report, projectRoot, entries, policy) {
597
825
  message: "All manifest entrypoints exist in dist."
598
826
  });
599
827
  }
600
- var import_fs2, import_path2, import_tinyglobby, init_distChecks = __esm({
828
+ var import_fs3, import_path3, import_tinyglobby, init_distChecks = __esm({
601
829
  "src/core/doctor/distChecks.ts"() {
602
830
  "use strict";
603
- import_fs2 = __toESM(require("fs")), import_path2 = __toESM(require("path")), import_tinyglobby = require("tinyglobby");
831
+ import_fs3 = __toESM(require("fs")), import_path3 = __toESM(require("path")), import_tinyglobby = require("tinyglobby");
604
832
  init_report();
605
833
  }
606
834
  });
@@ -611,6 +839,7 @@ var TRACKER_SLOTS, init_slots = __esm({
611
839
  "use strict";
612
840
  TRACKER_SLOTS = [
613
841
  "issue.action",
842
+ "drawer.issue.action",
614
843
  "issue.block",
615
844
  "issue.tab",
616
845
  "issue.comment.action",
@@ -647,7 +876,7 @@ var init_src = __esm({
647
876
  });
648
877
 
649
878
  // 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({
879
+ 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_constants2 = __esm({
651
880
  "src/core/manifest/constants.ts"() {
652
881
  "use strict";
653
882
  init_src();
@@ -752,7 +981,7 @@ var DATA_PERMISSIONS, TOP_DATA_PERMISSIONS, SERVICES, TEMPLATES, CLI_ONLY_TRACKE
752
981
  "user-card-calendar"
753
982
  ], 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
983
  default: [],
755
- "issue.action": ["issue.action"],
984
+ "issue.action": ["issue.action", "drawer.issue.action"],
756
985
  "issue.block": ["issue.block"],
757
986
  "issue.tab": ["issue.tab"],
758
987
  "issue.comment.action": ["issue.comment.action"],
@@ -821,11 +1050,11 @@ var permissionsSchemaExtensions, init_manifestPermissionsSchema = __esm({
821
1050
  });
822
1051
 
823
1052
  // src/distribution/manifestPermissionsSchema.ts
824
- var impl3, permissionsSchemaExtensions2, init_manifestPermissionsSchema2 = __esm({
1053
+ var impl5, permissionsSchemaExtensions2, init_manifestPermissionsSchema2 = __esm({
825
1054
  "src/distribution/manifestPermissionsSchema.ts"() {
826
1055
  "use strict";
827
1056
  init_flag();
828
- impl3 = (init_manifestPermissionsSchema(), __toCommonJS(manifestPermissionsSchema_exports)), { permissionsSchemaExtensions: permissionsSchemaExtensions2 } = impl3;
1057
+ impl5 = (init_manifestPermissionsSchema(), __toCommonJS(manifestPermissionsSchema_exports)), { permissionsSchemaExtensions: permissionsSchemaExtensions2 } = impl5;
829
1058
  }
830
1059
  });
831
1060
 
@@ -857,14 +1086,14 @@ var priorityOrder, errorMessages, getPriority, formatValidationErrors, init_form
857
1086
  }, formatValidationErrors = (errors) => {
858
1087
  let errorsByPath = {};
859
1088
  for (let error2 of errors) {
860
- let path24 = error2.instancePath || "root";
861
- errorsByPath[path24] || (errorsByPath[path24] = []), errorsByPath[path24].push(error2);
1089
+ let path26 = error2.instancePath || "root";
1090
+ errorsByPath[path26] || (errorsByPath[path26] = []), errorsByPath[path26].push(error2);
862
1091
  }
863
- return Object.entries(errorsByPath).map(([path24, pathErrors]) => {
1092
+ return Object.entries(errorsByPath).map(([path26, pathErrors]) => {
864
1093
  let error2 = [...pathErrors].sort(
865
1094
  (a, b) => getPriority(a.keyword) - getPriority(b.keyword)
866
1095
  )[0], formatter = errorMessages[error2.keyword], message = formatter ? formatter(error2.params) : error2.message;
867
- return ` - ${path24}: ${message}`;
1096
+ return ` - ${path26}: ${message}`;
868
1097
  }).join(`
869
1098
  `);
870
1099
  };
@@ -891,6 +1120,12 @@ var manifest_schema_default, init_manifest_schema = __esm({
891
1120
  $schema: {
892
1121
  type: "string"
893
1122
  },
1123
+ docsUrl: {
1124
+ type: "string",
1125
+ description: "URL to the documentation for the plugin",
1126
+ maxLength: 1e3,
1127
+ minLength: 1
1128
+ },
894
1129
  id: {
895
1130
  type: "string",
896
1131
  description: "Unique identifier for the plugin ()",
@@ -1003,6 +1238,16 @@ var manifest_schema_default, init_manifest_schema = __esm({
1003
1238
  },
1004
1239
  minItems: 1
1005
1240
  },
1241
+ categories: {
1242
+ type: "array",
1243
+ description: "Categories for plugin discovery in the marketplace",
1244
+ items: {
1245
+ type: "string",
1246
+ minLength: 1,
1247
+ maxLength: 50
1248
+ },
1249
+ uniqueItems: !0
1250
+ },
1006
1251
  homepage: {
1007
1252
  type: "string",
1008
1253
  description: "Homepage URL for the plugin (http or https)",
@@ -1177,6 +1422,14 @@ var manifest_schema_default, init_manifest_schema = __esm({
1177
1422
  $ref: "#/definitions/SlotConfig"
1178
1423
  }
1179
1424
  },
1425
+ "drawer.issue.action": {
1426
+ type: "array",
1427
+ description: "Drawer Issue Action slot configurations",
1428
+ minItems: 1,
1429
+ items: {
1430
+ $ref: "#/definitions/SlotConfig"
1431
+ }
1432
+ },
1180
1433
  "issue.block": {
1181
1434
  type: "array",
1182
1435
  description: "Issue Block slot configurations",
@@ -1578,10 +1831,10 @@ var manifest_schema_default, init_manifest_schema = __esm({
1578
1831
  });
1579
1832
 
1580
1833
  // src/core/manifest/manifestManager.ts
1581
- var import_fs3, import_promises, import_ajv, import_ajv_formats, validator, defaultManifestPath, parseManifest, loadRaw, load, validate, save, update, manifestManager, init_manifestManager = __esm({
1834
+ var import_fs4, import_promises, import_ajv, import_ajv_formats, validator, defaultManifestPath, parseManifest, loadRaw, load, validate, save, update, manifestManager, init_manifestManager = __esm({
1582
1835
  "src/core/manifest/manifestManager.ts"() {
1583
1836
  "use strict";
1584
- import_fs3 = require("fs"), import_promises = require("fs/promises"), import_ajv = __toESM(require("ajv")), import_ajv_formats = __toESM(require("ajv-formats"));
1837
+ import_fs4 = require("fs"), import_promises = require("fs/promises"), import_ajv = __toESM(require("ajv")), import_ajv_formats = __toESM(require("ajv-formats"));
1585
1838
  init_manifestPermissionsSchema2();
1586
1839
  init_formatValidationErrors();
1587
1840
  init_manifest_schema();
@@ -1609,7 +1862,7 @@ var import_fs3, import_promises, import_ajv, import_ajv_formats, validator, defa
1609
1862
  }
1610
1863
  return manifest;
1611
1864
  }, loadRaw = async (manifestPath = defaultManifestPath) => {
1612
- if (!(0, import_fs3.existsSync)(manifestPath))
1865
+ if (!(0, import_fs4.existsSync)(manifestPath))
1613
1866
  throw new Error(`File manifest.json not found at path: ${manifestPath}`);
1614
1867
  try {
1615
1868
  return await (0, import_promises.readFile)(manifestPath, "utf8");
@@ -1665,10 +1918,10 @@ function isNonEmptyString(value) {
1665
1918
  return typeof value == "string" && !!value.trim();
1666
1919
  }
1667
1920
  function isSafeRelativePath(value) {
1668
- if (import_path3.default.isAbsolute(value))
1921
+ if (import_path4.default.isAbsolute(value))
1669
1922
  return !1;
1670
- let normalized = import_path3.default.normalize(value);
1671
- return normalized !== ".." && !normalized.startsWith(`..${import_path3.default.sep}`);
1923
+ let normalized = import_path4.default.normalize(value);
1924
+ return normalized !== ".." && !normalized.startsWith(`..${import_path4.default.sep}`);
1672
1925
  }
1673
1926
  function getManifestEntries(manifest) {
1674
1927
  let result = [];
@@ -1799,11 +2052,11 @@ async function checkManifest(report, manifestPath, policy) {
1799
2052
  };
1800
2053
  }
1801
2054
  }
1802
- var import_path3, init_manifestChecks = __esm({
2055
+ var import_path4, init_manifestChecks = __esm({
1803
2056
  "src/core/doctor/manifestChecks.ts"() {
1804
2057
  "use strict";
1805
- import_path3 = __toESM(require("path"));
1806
- init_constants();
2058
+ import_path4 = __toESM(require("path"));
2059
+ init_constants2();
1807
2060
  init_manifestManager();
1808
2061
  init_helpers();
1809
2062
  init_report();
@@ -1816,8 +2069,8 @@ function getMissingOrInvalidStatus(requiredPath, policy) {
1816
2069
  }
1817
2070
  function checkMarketplaceAssets(report, projectRoot, policy) {
1818
2071
  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)) {
2072
+ let fullPath = import_path5.default.join(projectRoot, requiredPath.path), status = getMissingOrInvalidStatus(requiredPath, policy);
2073
+ if (!import_fs5.default.existsSync(fullPath)) {
1821
2074
  addCheck(report, {
1822
2075
  id: `marketplace.${requiredPath.path}`,
1823
2076
  title: requiredPath.title,
@@ -1827,7 +2080,7 @@ function checkMarketplaceAssets(report, projectRoot, policy) {
1827
2080
  });
1828
2081
  continue;
1829
2082
  }
1830
- let stat = import_fs4.default.statSync(fullPath), validKind = requiredPath.kind === "directory" ? stat.isDirectory() : stat.isFile();
2083
+ let stat = import_fs5.default.statSync(fullPath), validKind = requiredPath.kind === "directory" ? stat.isDirectory() : stat.isFile();
1831
2084
  addCheck(report, {
1832
2085
  id: `marketplace.${requiredPath.path}`,
1833
2086
  title: requiredPath.title,
@@ -1837,10 +2090,10 @@ function checkMarketplaceAssets(report, projectRoot, policy) {
1837
2090
  });
1838
2091
  }
1839
2092
  }
1840
- var import_fs4, import_path4, REQUIRED_PATHS, init_marketplaceChecks = __esm({
2093
+ var import_fs5, import_path5, REQUIRED_PATHS, init_marketplaceChecks = __esm({
1841
2094
  "src/core/doctor/marketplaceChecks.ts"() {
1842
2095
  "use strict";
1843
- import_fs4 = __toESM(require("fs")), import_path4 = __toESM(require("path"));
2096
+ import_fs5 = __toESM(require("fs")), import_path5 = __toESM(require("path"));
1844
2097
  init_report();
1845
2098
  REQUIRED_PATHS = [
1846
2099
  { path: "src", title: "Source directory", kind: "directory" },
@@ -1897,10 +2150,10 @@ function defaultCommandExists(command) {
1897
2150
  return !result.error && result.status === 0;
1898
2151
  }
1899
2152
  function detectFromPackageJson(projectRoot) {
1900
- let packageJsonPath = import_path5.default.join(projectRoot, "package.json");
1901
- if (import_fs5.default.existsSync(packageJsonPath))
2153
+ let packageJsonPath = import_path6.default.join(projectRoot, "package.json");
2154
+ if (import_fs6.default.existsSync(packageJsonPath))
1902
2155
  try {
1903
- let raw = import_fs5.default.readFileSync(packageJsonPath, "utf8"), packageManager = JSON.parse(raw).packageManager;
2156
+ let raw = import_fs6.default.readFileSync(packageJsonPath, "utf8"), packageManager = JSON.parse(raw).packageManager;
1904
2157
  if (typeof packageManager != "string")
1905
2158
  return;
1906
2159
  if (packageManager.startsWith("pnpm@"))
@@ -1912,7 +2165,7 @@ function detectFromPackageJson(projectRoot) {
1912
2165
  }
1913
2166
  }
1914
2167
  function detectPackageManager(projectRoot = process.cwd()) {
1915
- return import_fs5.default.existsSync(import_path5.default.join(projectRoot, "pnpm-lock.yaml")) ? "pnpm" : detectFromPackageJson(projectRoot) || "npm";
2168
+ return import_fs6.default.existsSync(import_path6.default.join(projectRoot, "pnpm-lock.yaml")) ? "pnpm" : detectFromPackageJson(projectRoot) || "npm";
1916
2169
  }
1917
2170
  function resolvePackageManagerExecutable(packageManager, options = {}) {
1918
2171
  let commandExists = options.commandExists || defaultCommandExists;
@@ -1981,10 +2234,10 @@ function runPackageManagerRuntimeCheck(projectRoot, packageManager, executable)
1981
2234
  output: output || null
1982
2235
  };
1983
2236
  }
1984
- var import_child_process, import_fs5, import_path5, PACKAGE_MANAGER_RUNTIME_TIMEOUT_MS, MAX_RUNTIME_OUTPUT_LENGTH, PackageManagerRuntimeError, init_packageManager = __esm({
2237
+ var import_child_process, import_fs6, import_path6, PACKAGE_MANAGER_RUNTIME_TIMEOUT_MS, MAX_RUNTIME_OUTPUT_LENGTH, PackageManagerRuntimeError, init_packageManager = __esm({
1985
2238
  "src/utils/packageManager.ts"() {
1986
2239
  "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 {
2240
+ import_child_process = require("child_process"), import_fs6 = __toESM(require("fs")), import_path6 = __toESM(require("path")), PACKAGE_MANAGER_RUNTIME_TIMEOUT_MS = 15e3, MAX_RUNTIME_OUTPUT_LENGTH = 1e3, PackageManagerRuntimeError = class extends Error {
1988
2241
  constructor(check) {
1989
2242
  super(check.message), this.name = "PackageManagerRuntimeError", this.action = check.action, this.check = check;
1990
2243
  }
@@ -1994,14 +2247,14 @@ var import_child_process, import_fs5, import_path5, PACKAGE_MANAGER_RUNTIME_TIME
1994
2247
 
1995
2248
  // src/core/doctor/packageChecks.ts
1996
2249
  function readPackageJson(projectRoot) {
1997
- let packageJsonPath = import_path6.default.join(projectRoot, "package.json");
1998
- if (!import_fs6.default.existsSync(packageJsonPath))
2250
+ let packageJsonPath = import_path7.default.join(projectRoot, "package.json");
2251
+ if (!import_fs7.default.existsSync(packageJsonPath))
1999
2252
  return {
2000
2253
  path: packageJsonPath,
2001
2254
  error: "package.json not found"
2002
2255
  };
2003
2256
  try {
2004
- let raw = import_fs6.default.readFileSync(packageJsonPath, "utf8");
2257
+ let raw = import_fs7.default.readFileSync(packageJsonPath, "utf8");
2005
2258
  return {
2006
2259
  path: packageJsonPath,
2007
2260
  packageJson: JSON.parse(raw)
@@ -2188,10 +2441,10 @@ function checkPackageManager(report, projectRoot) {
2188
2441
  });
2189
2442
  }
2190
2443
  }
2191
- var import_fs6, import_path6, CLI_PACKAGE_MANAGER, COMMON_SDK_PACKAGES, GENERIC_SDK_PACKAGES, init_packageChecks = __esm({
2444
+ var import_fs7, import_path7, CLI_PACKAGE_MANAGER, COMMON_SDK_PACKAGES, GENERIC_SDK_PACKAGES, init_packageChecks = __esm({
2192
2445
  "src/core/doctor/packageChecks.ts"() {
2193
2446
  "use strict";
2194
- import_fs6 = __toESM(require("fs")), import_path6 = __toESM(require("path"));
2447
+ import_fs7 = __toESM(require("fs")), import_path7 = __toESM(require("path"));
2195
2448
  init_packageManager();
2196
2449
  init_helpers();
2197
2450
  init_report();
@@ -2205,371 +2458,95 @@ var import_fs6, import_path6, CLI_PACKAGE_MANAGER, COMMON_SDK_PACKAGES, GENERIC_
2205
2458
  ], GENERIC_SDK_PACKAGES = ["@weavix/sdk-core", "@weavix/sdk-react"];
2206
2459
  }
2207
2460
  });
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
- };
2461
+
2462
+ // src/utils/project.ts
2463
+ function resolveProjectRoot(startDir = process.cwd()) {
2464
+ let current = import_path8.default.resolve(startDir);
2465
+ for (; ; ) {
2466
+ if (import_fs8.default.existsSync(import_path8.default.join(current, MANIFEST_FILE)))
2467
+ return current;
2468
+ let parent = import_path8.default.dirname(current);
2469
+ if (parent === current)
2470
+ throw new Error(
2471
+ `Could not find ${MANIFEST_FILE}. Run this command inside a plugin project.`
2472
+ );
2473
+ current = parent;
2491
2474
  }
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
2475
  }
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();
2476
+ function getManifestPath(projectRoot = process.cwd()) {
2477
+ return import_path8.default.join(resolveProjectRoot(projectRoot), MANIFEST_FILE);
2504
2478
  }
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}`);
2479
+ var import_fs8, import_path8, MANIFEST_FILE, init_project = __esm({
2480
+ "src/utils/project.ts"() {
2481
+ "use strict";
2482
+ import_fs8 = __toESM(require("fs")), import_path8 = __toESM(require("path")), MANIFEST_FILE = "manifest.json";
2527
2483
  }
2484
+ });
2485
+
2486
+ // src/core/doctor/projectChecks.ts
2487
+ function checkProjectRoot(report) {
2528
2488
  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);
2489
+ let projectRoot = resolveProjectRoot();
2490
+ return report.projectRoot = projectRoot, report.manifestPath = getManifestPath(projectRoot), addCheck(report, {
2491
+ id: "project-root.resolved",
2492
+ title: "Project root",
2493
+ message: `Found plugin project root at ${projectRoot}.`
2494
+ }), projectRoot;
2545
2495
  } 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);
2496
+ addCheck(report, {
2497
+ id: "project-root.resolved",
2498
+ title: "Project root",
2499
+ status: "fail",
2500
+ message: getErrorMessage(error2),
2501
+ action: "Run doctor inside a generated plugin project."
2502
+ });
2503
+ return;
2560
2504
  }
2561
2505
  }
2562
- var import_node_fetch2, PLATFORM_API_TIMEOUT_MS, init_platformApiRequest = __esm({
2563
- "src/api/platformApiRequest.ts"() {
2506
+ var init_projectChecks = __esm({
2507
+ "src/core/doctor/projectChecks.ts"() {
2564
2508
  "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);
2509
+ init_project();
2510
+ init_helpers();
2511
+ init_report();
2512
+ }
2513
+ });
2514
+
2515
+ // src/core/doctor/checks.ts
2516
+ async function runDoctorChecks(options) {
2517
+ let report = createDoctorReport(), policy = createDoctorPolicy(options);
2518
+ report.mode = policy.mode, checkNodeVersion(report);
2519
+ let projectRoot = checkProjectRoot(report);
2520
+ if (!projectRoot)
2521
+ return await checkDistribution2(report, void 0, options, policy), report;
2522
+ let { manifest, entries } = await checkManifest(report, report.manifestPath, policy);
2523
+ 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;
2524
+ }
2525
+ var init_checks = __esm({
2526
+ "src/core/doctor/checks.ts"() {
2527
+ "use strict";
2528
+ init_doctorChecks2();
2529
+ init_distChecks();
2530
+ init_manifestChecks();
2531
+ init_marketplaceChecks();
2532
+ init_nodeChecks();
2533
+ init_packageChecks();
2534
+ init_policy();
2535
+ init_projectChecks();
2536
+ init_report();
2537
+ }
2538
+ });
2539
+
2540
+ // src/commands/doctor/index.ts
2541
+ async function doctor(options = {}) {
2542
+ let report = await runDoctorChecks(options);
2543
+ await finishDoctor(report, options);
2544
+ }
2545
+ var init_doctor = __esm({
2546
+ "src/commands/doctor/index.ts"() {
2547
+ "use strict";
2548
+ init_checks();
2549
+ init_report();
2573
2550
  }
2574
2551
  });
2575
2552
 
@@ -2594,22 +2571,6 @@ async function updatePluginArchive(pluginId, archiveBuffer, archiveName) {
2594
2571
  formData
2595
2572
  });
2596
2573
  }
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
2574
  async function submitPlugin(pluginId, version) {
2614
2575
  return platformApiRequest(`/plugins/${pluginId}/submit`, {
2615
2576
  method: "POST",
@@ -2623,6 +2584,16 @@ async function getPluginInfo(pluginId) {
2623
2584
  method: "GET"
2624
2585
  });
2625
2586
  }
2587
+ async function getPluginVersions(pluginId) {
2588
+ return platformApiRequest(`/plugins/${pluginId}/versions`, {
2589
+ method: "GET"
2590
+ });
2591
+ }
2592
+ async function withdrawPluginVersion(pluginId, versionId) {
2593
+ return platformApiRequest(`/plugins/${pluginId}/versions/${versionId}/withdraw`, {
2594
+ method: "POST"
2595
+ });
2596
+ }
2626
2597
  async function getMyPlugins() {
2627
2598
  return platformApiRequest("/plugins/my", {
2628
2599
  method: "GET"
@@ -2633,10 +2604,14 @@ async function checkSlugAvailability(slug) {
2633
2604
  method: "GET"
2634
2605
  });
2635
2606
  }
2607
+ async function getPluginCategories() {
2608
+ return mockedCategories;
2609
+ }
2636
2610
  var import_form_data, init_platform = __esm({
2637
2611
  "src/api/platform.ts"() {
2638
2612
  "use strict";
2639
2613
  import_form_data = __toESM(require("form-data"));
2614
+ init_constants();
2640
2615
  init_platformApiRequest();
2641
2616
  }
2642
2617
  });
@@ -2661,13 +2636,6 @@ var init_getPluginId = __esm({
2661
2636
  }
2662
2637
  });
2663
2638
 
2664
- // src/api/utils.ts
2665
- var init_utils = __esm({
2666
- "src/api/utils.ts"() {
2667
- "use strict";
2668
- }
2669
- });
2670
-
2671
2639
  // src/utils/pluginDisplay.ts
2672
2640
  function showPluginInfo(data) {
2673
2641
  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);
@@ -2695,11 +2663,13 @@ function showPluginList(plugins) {
2695
2663
  function showPluginCreated(data) {
2696
2664
  printSuccessHeader("\u2705 Plugin Created"), logger_default.newLine(), printPluginId(data.id);
2697
2665
  }
2698
- var import_picocolors2, printHeader, printSuccessHeader, getStatusBadgeByLabel, formatDate, printField, printPluginId, printCreated, printUpdated, init_pluginDisplay = __esm({
2666
+ function showPluginWithdrawn(data) {
2667
+ printSuccessHeader("\u{1F6AB} Plugin Version Withdrawn"), logger_default.newLine(), printPluginId(data.pluginId), printVersionId(data.versionId), printField("Version", import_picocolors2.default.white(data.version));
2668
+ }
2669
+ var import_picocolors2, printHeader, printSuccessHeader, getStatusBadgeByLabel, formatDate, printField, printPluginId, printVersionId, printCreated, printUpdated, init_pluginDisplay = __esm({
2699
2670
  "src/utils/pluginDisplay.ts"() {
2700
2671
  "use strict";
2701
2672
  import_picocolors2 = __toESM(require("picocolors"));
2702
- init_utils();
2703
2673
  init_logger();
2704
2674
  printHeader = (title) => {
2705
2675
  console.info(import_picocolors2.default.bold(import_picocolors2.default.white(title)));
@@ -2718,6 +2688,8 @@ var import_picocolors2, printHeader, printSuccessHeader, getStatusBadgeByLabel,
2718
2688
  console.info(` ${import_picocolors2.default.dim(label.padEnd(minWidth))} ${value}`);
2719
2689
  }, printPluginId = (pluginId) => {
2720
2690
  printField("Plugin ID", import_picocolors2.default.cyan(pluginId));
2691
+ }, printVersionId = (versionId) => {
2692
+ printField("Version ID", import_picocolors2.default.cyan(versionId));
2721
2693
  }, printCreated = (createdAt) => {
2722
2694
  printField("Created", import_picocolors2.default.white(formatDate(createdAt)));
2723
2695
  }, printUpdated = (updatedAt) => {
@@ -2726,8 +2698,25 @@ var import_picocolors2, printHeader, printSuccessHeader, getStatusBadgeByLabel,
2726
2698
  }
2727
2699
  });
2728
2700
 
2701
+ // src/commands/platformAuth.ts
2702
+ function applyPlatformAuthOptions(options = {}) {
2703
+ setPlatformIamToken(options.iamToken);
2704
+ }
2705
+ var import_commander, iamTokenOption, init_platformAuth = __esm({
2706
+ "src/commands/platformAuth.ts"() {
2707
+ "use strict";
2708
+ import_commander = require("commander");
2709
+ init_platformApiRequest();
2710
+ iamTokenOption = new import_commander.Option(
2711
+ "--iam-token <token>",
2712
+ "use IAM token for Platform API requests instead of OAuth"
2713
+ );
2714
+ }
2715
+ });
2716
+
2729
2717
  // src/commands/info/platform.ts
2730
- async function infoPlatform(pluginId) {
2718
+ async function infoPlatform(pluginId, options = {}) {
2719
+ applyPlatformAuthOptions(options);
2731
2720
  let actualPluginId = await getPluginId(pluginId);
2732
2721
  logger_default.info(`\u23F3 Fetching plugin info for ID: ${actualPluginId}...`);
2733
2722
  try {
@@ -2744,12 +2733,13 @@ var init_platform2 = __esm({
2744
2733
  init_getPluginId();
2745
2734
  init_logger();
2746
2735
  init_pluginDisplay();
2736
+ init_platformAuth();
2747
2737
  }
2748
2738
  });
2749
2739
 
2750
2740
  // src/commands/list/platform.ts
2751
- async function listPlatform() {
2752
- logger_default.info("\u23F3 Fetching my plugins...");
2741
+ async function listPlatform(options = {}) {
2742
+ applyPlatformAuthOptions(options), logger_default.info("\u23F3 Fetching my plugins...");
2753
2743
  try {
2754
2744
  let plugins = await getMyPlugins();
2755
2745
  showPluginList(plugins);
@@ -2763,14 +2753,15 @@ var init_platform3 = __esm({
2763
2753
  init_platform();
2764
2754
  init_logger();
2765
2755
  init_pluginDisplay();
2756
+ init_platformAuth();
2766
2757
  }
2767
2758
  });
2768
2759
 
2769
2760
  // src/commands/submit/options.ts
2770
- var import_commander, skipChecksOption, init_options = __esm({
2761
+ var import_commander2, skipChecksOption, init_options = __esm({
2771
2762
  "src/commands/submit/options.ts"() {
2772
2763
  "use strict";
2773
- import_commander = require("commander"), skipChecksOption = new import_commander.Option(
2764
+ import_commander2 = require("commander"), skipChecksOption = new import_commander2.Option(
2774
2765
  "--skip-checks",
2775
2766
  "skip pre-submit validation (manifest, assets, lint, typecheck, tests, audit)"
2776
2767
  );
@@ -2778,6 +2769,22 @@ var import_commander, skipChecksOption, init_options = __esm({
2778
2769
  });
2779
2770
 
2780
2771
  // src/utils/marketplace.ts
2772
+ function validateDocs() {
2773
+ let docsDir = import_path9.default.resolve(DOCS_DIR), docsIndexPath = import_path9.default.join(docsDir, DOCS_INDEX_FILE);
2774
+ ensurePathExists(
2775
+ docsIndexPath,
2776
+ [
2777
+ `Documentation not found: /docs/${DOCS_INDEX_FILE}.`,
2778
+ `Add your docs to /docs/${DOCS_INDEX_FILE} before publishing, or remove the "docsUrl" field from manifest.json if you don't want to include documentation.`,
2779
+ `Learn more: ${DOCS_GUIDE_URL}`
2780
+ ].join(`
2781
+ `)
2782
+ );
2783
+ }
2784
+ function hasLocalDocs() {
2785
+ let docsIndexPath = import_path9.default.join(import_path9.default.resolve(DOCS_DIR), DOCS_INDEX_FILE);
2786
+ return import_fs9.default.existsSync(docsIndexPath);
2787
+ }
2781
2788
  function validateMarketplaceAssets() {
2782
2789
  let marketplaceDir = import_path9.default.resolve(MARKETPLACE_DIR);
2783
2790
  ensurePathExists(
@@ -2800,47 +2807,24 @@ function validateArchiveSources() {
2800
2807
  "Source folder not found. Add ./src before publishing."
2801
2808
  ), ensurePathExists(import_path9.default.resolve(MANIFEST_FILE2), "manifest.json not found in plugin root."), validateMarketplaceAssets();
2802
2809
  }
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({
2810
+ 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, DOCS_DIR, DOCS_INDEX_FILE, DOCS_GUIDE_URL, ensurePathExists, ensureManifestCatalogFields, validateManifestPublishingFields, marketplacePaths, init_marketplace = __esm({
2828
2811
  "src/utils/marketplace.ts"() {
2829
2812
  "use strict";
2830
2813
  import_fs9 = __toESM(require("fs")), import_path9 = __toESM(require("path"));
2831
2814
  init_manifestManager();
2832
2815
  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) => {
2816
+ 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", DOCS_DIR = "docs", DOCS_INDEX_FILE = "index.md", DOCS_GUIDE_URL = "https://diplodoc.com/docs/ru/", ensurePathExists = (targetPath, errorMessage) => {
2834
2817
  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) => {
2818
+ };
2819
+ ensureManifestCatalogFields = (manifest) => {
2839
2820
  (!manifest.name?.ru || !manifest.name?.en) && (logger_default.error(
2840
2821
  'Manifest field "name" is required for publishing. Add localized "name.ru" and "name.en" to ./manifest.json.'
2841
2822
  ), process.exit(1)), (!manifest.description?.ru || !manifest.description?.en) && (logger_default.error(
2842
2823
  'Manifest field "description" is required for publishing. Add localized "description.ru" and "description.en" to ./manifest.json.'
2843
2824
  ), process.exit(1));
2825
+ }, validateManifestPublishingFields = async () => {
2826
+ let manifest = await manifestManager.load();
2827
+ ensureManifestCatalogFields(manifest);
2844
2828
  };
2845
2829
  marketplacePaths = {
2846
2830
  distDir: DIST_DIR,
@@ -2864,9 +2848,11 @@ async function buildArchive() {
2864
2848
  logger_default.info(`[platform-api-debug] Saved archive copy to ${debugPath}`);
2865
2849
  }
2866
2850
  resolve2(buffer);
2867
- }), archive.on("error", reject), archive.glob("**/*", {
2851
+ }), archive.on("error", reject);
2852
+ let ignore = isInternal ? ["node_modules/**", "dist/**"] : ["node_modules/**", "dist/**", "src/**"];
2853
+ archive.glob("**/*", {
2868
2854
  cwd: process.cwd(),
2869
- ignore: ["node_modules/**", "dist/**"],
2855
+ ignore,
2870
2856
  dot: !1
2871
2857
  });
2872
2858
  for (let dotfile of [".npmrc", ".nvmrc"]) {
@@ -2883,15 +2869,25 @@ async function buildArchive() {
2883
2869
  ), archive.finalize();
2884
2870
  });
2885
2871
  }
2886
- var import_fs10, import_path10, import_archiver, init_buildArchive = __esm({
2872
+ var import_fs10, import_path10, import_archiver, isInternal, init_buildArchive = __esm({
2887
2873
  "src/utils/buildArchive.ts"() {
2888
2874
  "use strict";
2889
2875
  import_fs10 = __toESM(require("fs")), import_path10 = __toESM(require("path")), import_archiver = __toESM(require("archiver"));
2890
2876
  init_manifestManager();
2877
+ init_flag();
2891
2878
  init_meta2();
2892
2879
  init_logger();
2893
2880
  init_marketplace();
2894
2881
  init_verbose();
2882
+ isInternal = !1;
2883
+ }
2884
+ });
2885
+
2886
+ // src/utils/constants/docs.ts
2887
+ var localDocsUrl, init_docs = __esm({
2888
+ "src/utils/constants/docs.ts"() {
2889
+ "use strict";
2890
+ localDocsUrl = "/docs/index.html";
2895
2891
  }
2896
2892
  });
2897
2893
 
@@ -2961,18 +2957,65 @@ var build, init_build = __esm({
2961
2957
  }
2962
2958
  });
2963
2959
 
2960
+ // src/commands/utils/buildDocs.ts
2961
+ async function buildDocs(outputPath) {
2962
+ validateDocs();
2963
+ let pluginDir = resolveProjectRoot(), inputDir = import_path11.default.join(pluginDir, "docs"), outputDir = outputPath ? import_path11.default.join(pluginDir, outputPath) : import_path11.default.join(pluginDir, "dist", "docs"), originalCwd = process.cwd();
2964
+ process.chdir(inputDir);
2965
+ try {
2966
+ let report = await (0, import_cli.run)(["build", "--input", inputDir, "--output", outputDir]);
2967
+ if (report.code !== 0)
2968
+ throw new Error(`YFM build failed with exit code ${report.code}`);
2969
+ } finally {
2970
+ process.chdir(originalCwd);
2971
+ }
2972
+ }
2973
+ var import_path11, import_cli, init_buildDocs = __esm({
2974
+ "src/commands/utils/buildDocs.ts"() {
2975
+ "use strict";
2976
+ import_path11 = __toESM(require("path")), import_cli = require("@diplodoc/cli");
2977
+ init_marketplace();
2978
+ init_project();
2979
+ }
2980
+ });
2981
+
2982
+ // src/utils/urlGuards.ts
2983
+ var isLocalDocsUrl, isExternalDocsUrl, init_urlGuards = __esm({
2984
+ "src/utils/urlGuards.ts"() {
2985
+ "use strict";
2986
+ isLocalDocsUrl = (docsUrl) => docsUrl ? !/^https?:\/\//i.test(docsUrl) : !1, isExternalDocsUrl = (docsUrl) => docsUrl ? /^https?:\/\//i.test(docsUrl) : !1;
2987
+ }
2988
+ });
2989
+
2990
+ // src/commands/submit/utils/resolveBuildDocsDecision.ts
2991
+ function resolveBuildDocsDecision(docsUrl) {
2992
+ if (isExternalDocsUrl(docsUrl))
2993
+ return { shouldBuild: !1, autoDetected: !1 };
2994
+ if (isLocalDocsUrl(docsUrl))
2995
+ return { shouldBuild: !0, autoDetected: !1 };
2996
+ let detected = hasLocalDocs();
2997
+ return { shouldBuild: detected, autoDetected: detected };
2998
+ }
2999
+ var init_resolveBuildDocsDecision = __esm({
3000
+ "src/commands/submit/utils/resolveBuildDocsDecision.ts"() {
3001
+ "use strict";
3002
+ init_marketplace();
3003
+ init_urlGuards();
3004
+ }
3005
+ });
3006
+
2964
3007
  // src/utils/pluginPackageScripts.ts
2965
3008
  function readPluginPackageScripts(cwd = process.cwd()) {
2966
- let packageJsonPath = import_path11.default.join(cwd, "package.json");
3009
+ let packageJsonPath = import_path12.default.join(cwd, "package.json");
2967
3010
  return import_fs11.default.existsSync(packageJsonPath) ? JSON.parse(import_fs11.default.readFileSync(packageJsonPath, "utf-8")).scripts ?? {} : null;
2968
3011
  }
2969
3012
  function hasPluginScript(name, cwd = process.cwd()) {
2970
3013
  return !!readPluginPackageScripts(cwd)?.[name];
2971
3014
  }
2972
- var import_fs11, import_path11, init_pluginPackageScripts = __esm({
3015
+ var import_fs11, import_path12, init_pluginPackageScripts = __esm({
2973
3016
  "src/utils/pluginPackageScripts.ts"() {
2974
3017
  "use strict";
2975
- import_fs11 = __toESM(require("fs")), import_path11 = __toESM(require("path"));
3018
+ import_fs11 = __toESM(require("fs")), import_path12 = __toESM(require("path"));
2976
3019
  }
2977
3020
  });
2978
3021
 
@@ -3004,8 +3047,8 @@ var import_picocolors3, stepStart, stepDone, runStep, runShellStep, init_runSubm
3004
3047
  console.info(`${import_picocolors3.default.cyan("\u25B8")} ${label}`);
3005
3048
  }, stepDone = (label) => {
3006
3049
  console.info(`${import_picocolors3.default.green("\u2713")} ${label}`), console.info("");
3007
- }, runStep = async (label, run) => {
3008
- stepStart(label), await run(), stepDone(label);
3050
+ }, runStep = async (label, run2) => {
3051
+ stepStart(label), await run2(), stepDone(label);
3009
3052
  }, runShellStep = async (label, command) => {
3010
3053
  stepStart(label), console.info(import_picocolors3.default.dim(` $ ${command}`)), await execCommand(command), stepDone(label);
3011
3054
  };
@@ -3047,9 +3090,9 @@ var readline, init_validateSlug = __esm({
3047
3090
 
3048
3091
  // src/commands/submit/platform.ts
3049
3092
  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...");
3093
+ applyPlatformAuthOptions(options), await runSubmitPrechecks({ skip: options.skipChecks });
3094
+ let manifest = await manifestManager.load(), { docsUrl } = manifest, { shouldBuild, autoDetected } = resolveBuildDocsDecision(docsUrl);
3095
+ shouldBuild && validateDocs(), logger_default.info("\u{1F4E6} Building plugin..."), await build(), shouldBuild && (logger_default.info("\u{1F4E6} Building docs..."), await buildDocs(), autoDetected && (logger_default.info(`\u{1F4DD} Writing docsUrl: "${localDocsUrl}" to manifest.json...`), await manifestManager.update({ docsUrl: localDocsUrl }))), logger_default.info("\u{1F4E6} Creating archive...");
3053
3096
  let archiveBuffer = await buildArchive(), archiveName = `${manifest.slug}-${manifest.version}.zip`, pluginId;
3054
3097
  if (manifest.id)
3055
3098
  pluginId = manifest.id, logger_default.info("\u{1F4E4} Updating plugin archive..."), await updatePluginArchive(pluginId, archiveBuffer, archiveName);
@@ -3059,10 +3102,7 @@ async function submitPlatform(options = {}) {
3059
3102
  let createdPlugin = await createPlugin(archiveBuffer, archiveName);
3060
3103
  showPluginCreated(createdPlugin), pluginId = createdPlugin.id, await manifestManager.update({ id: pluginId });
3061
3104
  }
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();
3105
+ await submitPlugin(pluginId, manifest.version), logger_default.success("Plugin submitted for review!"), logger_default.info(` Version : ${manifest.version}`), logger_default.newLine();
3066
3106
  }
3067
3107
  var init_platform4 = __esm({
3068
3108
  "src/commands/submit/platform.ts"() {
@@ -3070,75 +3110,72 @@ var init_platform4 = __esm({
3070
3110
  init_platform();
3071
3111
  init_manifestManager();
3072
3112
  init_buildArchive();
3113
+ init_docs();
3073
3114
  init_logger();
3074
3115
  init_marketplace();
3075
3116
  init_pluginDisplay();
3076
3117
  init_build();
3118
+ init_platformAuth();
3119
+ init_buildDocs();
3120
+ init_resolveBuildDocsDecision();
3077
3121
  init_runSubmitPrechecks();
3078
3122
  init_validateSlug();
3079
3123
  }
3080
3124
  });
3081
3125
 
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
+ // src/commands/withdraw/index.ts
3127
+ async function getVersionArg(version) {
3128
+ if (version)
3129
+ return version;
3130
+ try {
3131
+ return (await manifestManager.load()).version;
3132
+ } catch {
3133
+ throw new Error("Version must be provided as argument or present in manifest.json");
3126
3134
  }
3127
- logger_default.info(`Configuration at ${getConfigPath()}:`), logger_default.info(JSON.stringify(cfg, null, 2));
3128
- }
3129
- function runConfigClear() {
3130
- clearConfig(), logger_default.success(`Configuration removed (${getConfigPath()})`);
3131
3135
  }
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);
3136
+ async function withdraw(pluginId, version) {
3137
+ let actualPluginId = await getPluginId(pluginId), actualVersion = await getVersionArg(version);
3138
+ logger_default.info(`\u23F3 Fetching versions for plugin ID: ${actualPluginId}...`);
3139
+ let pluginVersions;
3140
+ try {
3141
+ pluginVersions = await getPluginVersions(actualPluginId);
3142
+ } catch (error2) {
3143
+ throw error2 instanceof PlatformApiError && error2.status === 404 && (logger_default.error(`Plugin not found: ${actualPluginId}`), process.exit(1)), error2;
3144
+ }
3145
+ let target = pluginVersions.find((candidate) => candidate.version === actualVersion);
3146
+ target || (logger_default.error(`Version ${actualVersion} not found for plugin ${actualPluginId}.`), process.exit(1)), logger_default.info(`\u{1F6AB} Withdrawing version ${target.version} (current status: ${target.status})...`);
3147
+ try {
3148
+ await withdrawPluginVersion(actualPluginId, target.versionId);
3149
+ } catch (error2) {
3150
+ if (error2 instanceof PlatformApiError && error2.status === 400) {
3151
+ let hints = [
3152
+ `Version ${target.version} cannot be withdrawn: current status is ${target.status}.`,
3153
+ "Developer withdraw is only available while a version is IN_REVIEW."
3154
+ ];
3155
+ target.status.toUpperCase() === "CHECKING" && hints.push(
3156
+ "A version stuck in CHECKING cannot be withdrawn manually \u2014 it will move to CHECK_FAILED automatically via the recovery job."
3157
+ ), logger_default.error(hints.join(`
3158
+ `)), process.exit(1);
3159
+ }
3160
+ throw error2 instanceof PlatformApiError && error2.status === 404 && (logger_default.error(`Plugin or version not found: ${actualPluginId} / ${target.versionId}`), process.exit(1)), error2;
3161
+ }
3162
+ showPluginWithdrawn({
3163
+ pluginId: actualPluginId,
3164
+ versionId: target.versionId,
3165
+ version: target.version
3166
+ }), logger_default.info(
3167
+ "Closing the related Startrek ticket (if any) is handled by the backend on a best-effort basis."
3168
+ );
3135
3169
  }
3136
- var import_prompts, init_registerCommand = __esm({
3137
- "src/core/cliConfig/registerCommand.ts"() {
3170
+ var init_withdraw = __esm({
3171
+ "src/commands/withdraw/index.ts"() {
3138
3172
  "use strict";
3139
- import_prompts = require("@inquirer/prompts");
3173
+ init_platform();
3174
+ init_platformApiRequest();
3175
+ init_manifestManager();
3176
+ init_getPluginId();
3140
3177
  init_logger();
3141
- init_manager();
3178
+ init_pluginDisplay();
3142
3179
  }
3143
3180
  });
3144
3181
 
@@ -3184,10 +3221,10 @@ async function loginExternal() {
3184
3221
  console.info(
3185
3222
  import_picocolors4.default.dim("Get your OAuth token at: ") + import_picocolors4.default.cyan(`${ESC}]8;;${tokenUrl}${BEL}${tokenUrl}${ESC}]8;;${BEL}`)
3186
3223
  ), console.info("");
3187
- let token = await (0, import_prompts2.input)({
3224
+ let token = await (0, import_prompts.input)({
3188
3225
  message: "Enter your OAuth token:",
3189
3226
  required: !0
3190
- }), orgId = await (0, import_prompts2.input)({
3227
+ }), orgId = await (0, import_prompts.input)({
3191
3228
  message: "Enter your Organization ID (X-Org-ID):",
3192
3229
  required: !0
3193
3230
  });
@@ -3208,10 +3245,10 @@ function logoutExternal() {
3208
3245
  }
3209
3246
  logger_default.success("Successfully logged out.");
3210
3247
  }
3211
- var import_prompts2, import_picocolors4, ESC, BEL, init_login = __esm({
3248
+ var import_prompts, import_picocolors4, ESC, BEL, init_login = __esm({
3212
3249
  "src/distributions/external/login.ts"() {
3213
3250
  "use strict";
3214
- import_prompts2 = require("@inquirer/prompts"), import_picocolors4 = __toESM(require("picocolors"));
3251
+ import_prompts = require("@inquirer/prompts"), import_picocolors4 = __toESM(require("picocolors"));
3215
3252
  init_manager();
3216
3253
  init_logger();
3217
3254
  init_authManager();
@@ -3226,11 +3263,13 @@ __export(registerCommands_exports, {
3226
3263
  registerDistributionCommands: () => registerDistributionCommands
3227
3264
  });
3228
3265
  function registerDistributionCommands(program) {
3229
- registerConfigCommand(program, CLI_NAME), program.command("login").description("save your Yandex Tracker OAuth token (request it via Tracker support)").action(withErrorHandling(loginExternal)), program.command("logout").description("remove saved OAuth token").action(
3266
+ program.command("login").description("save your Yandex Tracker OAuth token (request it via Tracker support)").action(withErrorHandling(loginExternal)), program.command("logout").description("remove saved OAuth token").action(
3230
3267
  withErrorHandling(async () => {
3231
3268
  logoutExternal();
3232
3269
  })
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));
3270
+ ), program.command("submit").description("build plugin and submit it to the platform for review").addOption(skipChecksOption).addOption(iamTokenOption).action(withErrorHandling(submitPlatform)), program.command("doctor").description("validate local plugin project and auth").option("--network", "verify OAuth token against the Platform API", !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").addOption(iamTokenOption).action(withErrorHandling(listPlatform)), program.command("info [plugin-id]").description("show plugin status (uses plugin id from manifest if not provided)").addOption(iamTokenOption).action(withErrorHandling(infoPlatform)), program.command("withdraw [plugin-id] [version]").description(
3271
+ "withdraw a submitted version from review (uses manifest.id/version if not provided)"
3272
+ ).action(withErrorHandling(withdraw));
3234
3273
  }
3235
3274
  var init_registerCommands = __esm({
3236
3275
  "src/distributions/external/registerCommands.ts"() {
@@ -3238,17 +3277,17 @@ var init_registerCommands = __esm({
3238
3277
  init_doctor();
3239
3278
  init_platform2();
3240
3279
  init_platform3();
3280
+ init_platformAuth();
3241
3281
  init_options();
3242
3282
  init_platform4();
3243
- init_registerCommand();
3283
+ init_withdraw();
3244
3284
  init_withErrorHandling();
3245
3285
  init_login();
3246
- init_meta();
3247
3286
  }
3248
3287
  });
3249
3288
 
3250
3289
  // src/index.ts
3251
- var import_commander2 = require("commander");
3290
+ var import_commander3 = require("commander");
3252
3291
  init_meta2();
3253
3292
 
3254
3293
  // src/distribution/registerCommands.ts
@@ -3256,7 +3295,7 @@ init_flag();
3256
3295
  var impl6 = (init_registerCommands(), __toCommonJS(registerCommands_exports)), { registerDistributionCommands: registerDistributionCommands2 } = impl6;
3257
3296
 
3258
3297
  // src/utils/checkUpdate.ts
3259
- var import_node_fetch3 = __toESM(require("node-fetch"));
3298
+ var import_node_fetch2 = __toESM(require("node-fetch"));
3260
3299
  init_hosts2();
3261
3300
  init_logger();
3262
3301
  var SEMVER_RE = /^(\d+)\.(\d+)\.(\d+)$/, DIAGNOSTIC_FLAGS = /* @__PURE__ */ new Set(["--version", "-V", "--help", "-h", "help"]), parse = (v) => {
@@ -3272,7 +3311,7 @@ var SEMVER_RE = /^(\d+)\.(\d+)\.(\d+)$/, DIAGNOSTIC_FLAGS = /* @__PURE__ */ new
3272
3311
  let current = parse(version);
3273
3312
  if (current)
3274
3313
  try {
3275
- let response = await (0, import_node_fetch3.default)(`${info2.registryUrl}/${info2.packageName}/latest`);
3314
+ let response = await (0, import_node_fetch2.default)(`${info2.registryUrl}/${info2.packageName}/latest`);
3276
3315
  if (!response.ok) return;
3277
3316
  let json = await response.json(), latest = parse(json.version);
3278
3317
  if (!latest) return;
@@ -3300,14 +3339,22 @@ function shouldRunUpdateCheck(argv) {
3300
3339
  // src/index.ts
3301
3340
  init_build();
3302
3341
 
3342
+ // src/commands/build-docs.ts
3343
+ init_logger();
3344
+ init_buildDocs();
3345
+ var buildDocs2 = async () => {
3346
+ logger_default.info("\u{1F4E6} Building docs..."), await buildDocs("docs-build"), logger_default.info("You can see your docs by opening ./docs-build/index.html in your browser");
3347
+ };
3348
+
3303
3349
  // src/commands/create/index.ts
3304
- var path18 = __toESM(require("path")), import_prompts3 = require("@inquirer/prompts");
3305
- init_constants();
3350
+ var path20 = __toESM(require("path")), import_prompts2 = require("@inquirer/prompts");
3351
+ init_platform();
3352
+ init_constants2();
3306
3353
  init_meta2();
3307
3354
  init_logger();
3308
3355
 
3309
3356
  // src/commands/create/templateChoices.ts
3310
- init_constants();
3357
+ init_constants2();
3311
3358
  var DEFERRED_TEMPLATE_REASON = "will be added later", DEFERRED_TEMPLATES = /* @__PURE__ */ new Set(["user-card-info", "user-card-calendar"]);
3312
3359
  function getTemplateChoices(service) {
3313
3360
  return TEMPLATES.filter((templateName) => TEMPLATE_SERVICE[templateName] === service).map(
@@ -3329,10 +3376,10 @@ ${import_picocolors5.default.dim("Press")} ${import_picocolors5.default.yellow("
3329
3376
  `;
3330
3377
 
3331
3378
  // src/commands/create/utils/initManifest.ts
3332
- var fs11 = __toESM(require("fs")), path13 = __toESM(require("path"));
3379
+ var fs12 = __toESM(require("fs")), path16 = __toESM(require("path"));
3333
3380
 
3334
3381
  // src/commands/create/utils/generateManifest.ts
3335
- init_constants();
3382
+ init_constants2();
3336
3383
  var FULL_CONTEXT_TEMPLATES = /* @__PURE__ */ new Set(["user-card-info", "user-card-calendar"]);
3337
3384
  function buildSlots(template, slotTitle) {
3338
3385
  let slotNames = TEMPLATE_SLOTS[template];
@@ -3360,30 +3407,57 @@ var generateManifest = (answers) => ({
3360
3407
  ru: answers.pluginDescription,
3361
3408
  en: answers.pluginDescription
3362
3409
  },
3410
+ categories: answers.categories,
3363
3411
  permissions: answers.permissions,
3364
3412
  support: [{ type: "email", value: answers.supportEmail }],
3365
3413
  slots: buildSlots(answers.template, answers.slotTitle)
3366
3414
  });
3367
3415
 
3416
+ // src/commands/create/utils/generateManifestSchema.ts
3417
+ var fs11 = __toESM(require("fs")), path15 = __toESM(require("path"));
3418
+
3419
+ // src/utils/getProjectPath.ts
3420
+ 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);
3421
+
3422
+ // src/commands/create/utils/generateManifestSchema.ts
3423
+ function generateManifestSchema(categories, targetDir) {
3424
+ let baseSchemaPath = path15.join(getTemplatesBaseDir(), "_shared", "manifest.schema.json"), baseSchema = JSON.parse(fs11.readFileSync(baseSchemaPath, "utf-8")), categoriesProperty = {
3425
+ type: "array",
3426
+ description: "Categories this plugin belongs to",
3427
+ items: {
3428
+ type: "string",
3429
+ enum: categories.items.map((c) => c.slug)
3430
+ },
3431
+ uniqueItems: !0
3432
+ }, patchedSchema = {
3433
+ ...baseSchema,
3434
+ properties: {
3435
+ ...baseSchema.properties,
3436
+ categories: categoriesProperty
3437
+ }
3438
+ }, schemaPath = path15.join(targetDir, "manifest.schema.json");
3439
+ fs11.writeFileSync(schemaPath, JSON.stringify(patchedSchema, null, 2), "utf-8");
3440
+ }
3441
+
3368
3442
  // src/commands/create/utils/initManifest.ts
3369
- var initManifest = ({ answers, targetDir }) => {
3370
- let generatedManifest = generateManifest(answers), manifestPath = path13.join(targetDir, "manifest.json");
3371
- fs11.writeFileSync(manifestPath, JSON.stringify(generatedManifest, null, 2), "utf-8");
3443
+ var initManifest = ({ answers, targetDir, categories }) => {
3444
+ let generatedManifest = generateManifest(answers), manifestPath = path16.join(targetDir, "manifest.json");
3445
+ fs12.writeFileSync(manifestPath, JSON.stringify(generatedManifest, null, 2), "utf-8"), generateManifestSchema(categories, targetDir);
3372
3446
  };
3373
3447
 
3374
3448
  // src/commands/create/utils/initTemplate.ts
3375
- var fs14 = __toESM(require("fs")), path17 = __toESM(require("path"));
3449
+ var fs15 = __toESM(require("fs")), path19 = __toESM(require("path"));
3376
3450
 
3377
3451
  // src/distribution/templateSubstitution.ts
3378
3452
  init_flag();
3379
- var isInternal = !1, templateDeps = [
3453
+ var isInternal2 = !1, templateDeps = [
3380
3454
  "@weavix/tracker-plugin-sdk",
3381
3455
  "@weavix/tracker-plugin-sdk-react",
3382
3456
  "@weavix/tracker-api-types"
3383
- ], overlayDirName = isInternal ? "_internal" : "_external";
3457
+ ], overlayDirName = isInternal2 ? "_internal" : "_external";
3384
3458
 
3385
3459
  // src/utils/copyDirectory.ts
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) => {
3460
+ var fs13 = __toESM(require("fs")), import_path14 = __toESM(require("path")), import_tinyglobby2 = require("tinyglobby"), resolveTargetFileName = (file) => file.endsWith(".template") ? "." + file.replace(".template", "") : file, copyDirectory = async (sourceDir, targetDir) => {
3387
3461
  let files = await (0, import_tinyglobby2.glob)(["**/*"], {
3388
3462
  cwd: sourceDir,
3389
3463
  onlyFiles: !0,
@@ -3391,34 +3465,31 @@ var fs12 = __toESM(require("fs")), import_path12 = __toESM(require("path")), imp
3391
3465
  });
3392
3466
  await Promise.all(
3393
3467
  files.map(async (file) => {
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);
3468
+ let sourcePath = import_path14.default.join(sourceDir, file), targetFile = resolveTargetFileName(file), targetPath = import_path14.default.join(targetDir, targetFile);
3469
+ await fs13.promises.mkdir(import_path14.default.dirname(targetPath), { recursive: !0 });
3470
+ let content = await fs13.promises.readFile(sourcePath);
3471
+ await fs13.promises.writeFile(targetPath, content);
3398
3472
  })
3399
3473
  );
3400
3474
  };
3401
3475
 
3402
- // src/utils/getProjectPath.ts
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);
3404
-
3405
3476
  // src/commands/create/utils/initTemplate.ts
3406
3477
  init_logger();
3407
3478
 
3408
3479
  // src/commands/create/utils/updatePackageJson.ts
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) + `
3480
+ var fs14 = __toESM(require("fs")), path18 = __toESM(require("path")), updatePackageJson = (targetDir, packageSlug) => {
3481
+ let packageJsonPath = path18.join(targetDir, "package.json");
3482
+ if (fs14.existsSync(packageJsonPath)) {
3483
+ let packageJson = JSON.parse(fs14.readFileSync(packageJsonPath, "utf-8"));
3484
+ packageJson.name = packageSlug, fs14.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 4) + `
3414
3485
  `);
3415
3486
  }
3416
3487
  };
3417
3488
 
3418
3489
  // src/commands/create/utils/initTemplate.ts
3419
3490
  var initTemplate = async ({ answers, targetDir }) => {
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);
3491
+ fs15.existsSync(targetDir) || fs15.mkdirSync(targetDir, { recursive: !0 });
3492
+ let templatesBaseDir = getTemplatesBaseDir(), templatesDir = path19.join(templatesBaseDir, answers.template), sharedDir = path19.join(templatesBaseDir, "_shared"), overlayDir = path19.join(templatesBaseDir, overlayDirName);
3422
3493
  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(
3423
3494
  "Before publishing, add ./marketplace/index.md, ./marketplace/header-image.jpg (784:325), and ./public/logo.svg (square)."
3424
3495
  );
@@ -3428,20 +3499,20 @@ var initTemplate = async ({ answers, targetDir }) => {
3428
3499
  var DEFAULT_VERSION = "0.0.1";
3429
3500
  async function create() {
3430
3501
  logger_default.info(getWelcomeMessage(process.cwd()));
3431
- let packageSlug = await (0, import_prompts3.input)({
3502
+ let packageSlug = await (0, import_prompts2.input)({
3432
3503
  message: "Enter app slug (e.g., my-tracker-plugin):",
3433
3504
  required: !0
3434
- }), pluginName = await (0, import_prompts3.input)({
3505
+ }), pluginName = await (0, import_prompts2.input)({
3435
3506
  message: "Enter plugin name:",
3436
3507
  required: !0
3437
- }), pluginDescription = await (0, import_prompts3.input)({
3508
+ }), pluginDescription = await (0, import_prompts2.input)({
3438
3509
  message: "Enter plugin description:",
3439
3510
  required: !0
3440
- }), supportEmail = await (0, import_prompts3.input)({
3511
+ }), supportEmail = await (0, import_prompts2.input)({
3441
3512
  message: "Enter support email:",
3442
3513
  required: !0,
3443
3514
  validate: (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) || "Please enter a valid email address"
3444
- }), service = CREATE_SERVICES2.length === 1 ? CREATE_SERVICES2[0] : await (0, import_prompts3.select)({
3515
+ }), service = CREATE_SERVICES2.length === 1 ? CREATE_SERVICES2[0] : await (0, import_prompts2.select)({
3445
3516
  message: "Select a service:",
3446
3517
  choices: CREATE_SERVICES2.map((serviceName) => ({
3447
3518
  name: serviceName,
@@ -3455,10 +3526,16 @@ async function create() {
3455
3526
  );
3456
3527
  return;
3457
3528
  }
3458
- let template = await (0, import_prompts3.select)({
3529
+ let template = await (0, import_prompts2.select)({
3459
3530
  message: "Select a template:",
3460
3531
  choices: templateChoices
3461
- }), dataPermissions = await (0, import_prompts3.checkbox)({
3532
+ }), categoriesResponse = await getPluginCategories(), chosenCategories = await (0, import_prompts2.checkbox)({
3533
+ message: "Select a category:",
3534
+ choices: categoriesResponse.items.map((category) => ({
3535
+ name: category.name.en,
3536
+ value: category.slug
3537
+ }))
3538
+ }), dataPermissions = await (0, import_prompts2.checkbox)({
3462
3539
  message: "Select data permissions (some popular options):",
3463
3540
  choices: TOP_DATA_PERMISSIONS.map((permission) => ({
3464
3541
  name: permission,
@@ -3471,25 +3548,27 @@ async function create() {
3471
3548
  pluginDescription,
3472
3549
  supportEmail,
3473
3550
  service,
3551
+ categories: chosenCategories,
3474
3552
  template,
3475
3553
  permissions: {
3476
3554
  data: dataPermissions
3477
3555
  },
3478
3556
  version: DEFAULT_VERSION
3479
- }, targetDir = path18.join(process.cwd(), answers.packageSlug);
3557
+ }, targetDir = path20.join(process.cwd(), answers.packageSlug);
3480
3558
  await initTemplate({
3481
3559
  answers,
3482
3560
  targetDir
3483
3561
  }), initManifest({
3484
3562
  answers,
3485
- targetDir
3563
+ targetDir,
3564
+ categories: categoriesResponse
3486
3565
  }), 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
3566
  "\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
3567
  );
3489
3568
  }
3490
3569
 
3491
3570
  // src/commands/debug/index.ts
3492
- var import_fs15 = __toESM(require("fs")), import_path17 = __toESM(require("path"));
3571
+ var import_fs15 = __toESM(require("fs")), import_path18 = __toESM(require("path"));
3493
3572
  init_manifestManager();
3494
3573
 
3495
3574
  // src/core/s3config/constants.ts
@@ -3513,7 +3592,7 @@ var registerCleanup = (cleanup) => {
3513
3592
  init_templateCommands();
3514
3593
 
3515
3594
  // src/commands/debug/utils/createDebugConfig.ts
3516
- var import_fs12 = __toESM(require("fs")), import_path14 = __toESM(require("path"));
3595
+ var import_fs12 = __toESM(require("fs")), import_path15 = __toESM(require("path"));
3517
3596
  init_manifestManager();
3518
3597
 
3519
3598
  // src/utils/convertManifestToConfig.ts
@@ -3561,12 +3640,12 @@ var convertManifestToConfig = (manifest, environment) => {
3561
3640
 
3562
3641
  // src/commands/debug/utils/createDebugConfig.ts
3563
3642
  var createDebugConfig = async () => {
3564
- let manifest = await manifestManager.load(), config = convertManifestToConfig(manifest, "debug"), configPath = import_path14.default.join(process.cwd(), CONFIG_FILE_NAME);
3643
+ let manifest = await manifestManager.load(), config = convertManifestToConfig(manifest, "debug"), configPath = import_path15.default.join(process.cwd(), CONFIG_FILE_NAME);
3565
3644
  import_fs12.default.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
3566
3645
  };
3567
3646
 
3568
3647
  // src/commands/debug/utils/lockFile.ts
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 = () => {
3648
+ var import_fs13 = __toESM(require("fs")), import_path16 = __toESM(require("path")), LOCK_FILE_NAME = ".yaweavix-debug.lock", getLockFilePath = () => import_path16.default.join(process.cwd(), LOCK_FILE_NAME), getRunningDebugPid = () => {
3570
3649
  let lockPath = getLockFilePath();
3571
3650
  if (!import_fs13.default.existsSync(lockPath))
3572
3651
  return null;
@@ -3591,11 +3670,11 @@ var import_fs13 = __toESM(require("fs")), import_path15 = __toESM(require("path"
3591
3670
  };
3592
3671
 
3593
3672
  // src/commands/debug/utils/watchManifest.ts
3594
- var import_fs14 = __toESM(require("fs")), import_path16 = __toESM(require("path"));
3673
+ var import_fs14 = __toESM(require("fs")), import_path17 = __toESM(require("path"));
3595
3674
  init_manifestManager();
3596
3675
  init_logger();
3597
3676
  var watchManifest = () => {
3598
- let manifestPath = import_path16.default.join(process.cwd(), "manifest.json"), debounceTimer = null, watcher = import_fs14.default.watch(manifestPath, async (eventType) => {
3677
+ let manifestPath = import_path17.default.join(process.cwd(), "manifest.json"), debounceTimer = null, watcher = import_fs14.default.watch(manifestPath, async (eventType) => {
3599
3678
  eventType === "change" && (debounceTimer && clearTimeout(debounceTimer), debounceTimer = setTimeout(async () => {
3600
3679
  try {
3601
3680
  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");
@@ -3619,7 +3698,7 @@ Please stop the existing instance before starting a new one.
3619
3698
  If you lost the terminal tab, you can kill the process with:
3620
3699
  kill ${runningPid}`
3621
3700
  ), process.exit(1));
3622
- let configPath = import_path17.default.join(process.cwd(), CONFIG_FILE_NAME);
3701
+ let configPath = import_path18.default.join(process.cwd(), CONFIG_FILE_NAME);
3623
3702
  options.lint && await manifestManager.validate(), await createDebugConfig();
3624
3703
  let watcher = watchManifest(), cleanup = () => {
3625
3704
  watcher.close(), import_fs15.default.existsSync(configPath) && import_fs15.default.unlinkSync(configPath), removeLockFile();
@@ -3638,15 +3717,16 @@ async function lint() {
3638
3717
 
3639
3718
  // src/commands/up/index.ts
3640
3719
  var import_fs18 = require("fs"), import_promises4 = require("fs/promises");
3720
+ init_platform();
3641
3721
  init_execCommand();
3642
3722
 
3643
3723
  // src/commands/up/utils/copyTemplateFiles.ts
3644
- var import_fs16 = require("fs"), import_promises2 = require("fs/promises"), import_path18 = __toESM(require("path"));
3724
+ var import_fs16 = require("fs"), import_promises2 = require("fs/promises"), import_path19 = __toESM(require("path"));
3645
3725
  var copyTemplateFiles = async (files) => {
3646
3726
  await Promise.all(
3647
3727
  files.map(async (file) => {
3648
3728
  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));
3729
+ 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_path19.default.dirname(targetPath), { recursive: !0 }), await (0, import_promises2.copyFile)(templatePath, targetPath));
3650
3730
  })
3651
3731
  );
3652
3732
  }, overlayFileCopy = (overlayDir, sourceFilename, targetFilename) => ({
@@ -3709,16 +3789,42 @@ async function up() {
3709
3789
  await copyTemplateFiles([
3710
3790
  ...sharedFiles,
3711
3791
  { ...overlayFileCopy(overlayDirName, npmrcTemplateFilename, ".npmrc"), force: !0 }
3712
- ]), await updateManifestCompatibility(), await updatePackageDependencies(templateDeps), shouldCleanNpmCache && await execCommand("npm cache clean --force"), await execCommand("npm i");
3792
+ ]), await updateManifestCompatibility();
3793
+ let categoriesResponse = await getPluginCategories();
3794
+ generateManifestSchema(categoriesResponse, process.cwd()), await updatePackageDependencies(templateDeps), shouldCleanNpmCache && await execCommand("npm cache clean --force"), await execCommand("npm i");
3795
+ }
3796
+
3797
+ // src/core/legalAgreement/ensureLegalAgreementAccepted.ts
3798
+ var import_prompts3 = require("@inquirer/prompts");
3799
+ init_manager();
3800
+ init_logger();
3801
+
3802
+ // src/core/legalAgreement/legalAgreementText.ts
3803
+ var LEGAL_NOTICE_RU = "\u0418\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u044F \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043E\u0442\u043A\u0438 \u0434\u043B\u044F \u0446\u0435\u043B\u0435\u0439 \u0440\u0430\u0437\u043C\u0435\u0449\u0435\u043D\u0438\u044F \u041F\u043B\u0430\u0433\u0438\u043D\u0430 \u0432 \u041A\u0430\u0442\u0430\u043B\u043E\u0433\u0435 \u041F\u043B\u0430\u0433\u0438\u043D\u043E\u0432 \u0432\u044B \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u0435\u0442\u0435, \u0447\u0442\u043E \u043E\u0437\u043D\u0430\u043A\u043E\u043C\u043B\u0435\u043D\u044B \u0438 \u0441\u043E\u0433\u043B\u0430\u0441\u043D\u044B \u0441\u043E \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u043C\u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\u043C\u0438: \u0423\u0441\u043B\u043E\u0432\u0438\u044F \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u044F \u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0430 \u043F\u043B\u0430\u0433\u0438\u043D\u043E\u0432 \u0434\u043B\u044F \u0421\u0435\u0440\u0432\u0438\u0441\u043E\u0432 \u042F\u043D\u0434\u0435\u043A\u0441 360 (https://yandex.ru/legal/360_plugin_termsofuse), \u0421\u043E\u0433\u043B\u0430\u0448\u0435\u043D\u0438\u0435 \u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043E\u0442\u0447\u0438\u043A\u043E\u043C \u043F\u043B\u0430\u0433\u0438\u043D\u043E\u0432 (\u043F\u0430\u0431\u043B\u0438\u0448\u0435\u0440\u043E\u043C) \u0434\u043B\u044F \u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0430 \u043F\u043B\u0430\u0433\u0438\u043D\u043E\u0432 \u0421\u0435\u0440\u0432\u0438\u0441\u043E\u0432 \u042F\u043D\u0434\u0435\u043A\u0441 360 (https://yandex.ru/legal/360_plugin_dev_agreement).", LEGAL_NOTICE_EN = "By using the development tool for the purpose of placement of the Plugin in the Plugin Catalog, you acknowledge that you have read and agree to the following documents: Terms of Use of the Plugin Catalog for Yandex 360 Services ( https://yandex.ru/legal/360_plugin_termsofuse ), Plugin Developer (Publisher) Agreement for the Plugin Catalog of Yandex 360 Services ( https://yandex.ru/legal/360_plugin_dev_agreement ).";
3804
+
3805
+ // src/core/legalAgreement/ensureLegalAgreementAccepted.ts
3806
+ async function ensureLegalAgreementAccepted() {
3807
+ if (readConfig()?.legal?.acceptedAt)
3808
+ return;
3809
+ if (logger_default.separator(), logger_default.info("Legal notice / \u042E\u0440\u0438\u0434\u0438\u0447\u0435\u0441\u043A\u043E\u0435 \u0443\u0432\u0435\u0434\u043E\u043C\u043B\u0435\u043D\u0438\u0435"), logger_default.info(LEGAL_NOTICE_RU), logger_default.info(LEGAL_NOTICE_EN), logger_default.separator(), !await (0, import_prompts3.confirm)({
3810
+ message: "\u0412\u044B \u0441\u043E\u0433\u043B\u0430\u0441\u043D\u044B \u0441 \u0443\u0441\u043B\u043E\u0432\u0438\u044F\u043C\u0438 \u0432\u044B\u0448\u0435? / Do you agree to the terms above?",
3811
+ default: !1
3812
+ })) {
3813
+ logger_default.error(
3814
+ "\u0420\u0430\u0431\u043E\u0442\u0430 \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u0430: \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435 \u0441 \u0443\u0441\u043B\u043E\u0432\u0438\u044F\u043C\u0438 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u044F. / Stopped: you must accept the terms to continue."
3815
+ ), process.exit(1);
3816
+ return;
3817
+ }
3818
+ writeConfig({ ...readConfig() ?? {}, legal: { acceptedAt: (/* @__PURE__ */ new Date()).toISOString() } });
3713
3819
  }
3714
3820
 
3715
3821
  // src/utils/getVersion.ts
3716
- var import_fs19 = require("fs"), import_path19 = require("path"), UNKNOWN_VERSION = "unknown", CANDIDATES = ["..", "../.."], findVersionInPackageJson = (startDir) => {
3822
+ var import_fs19 = require("fs"), import_path20 = require("path"), UNKNOWN_VERSION = "unknown", CANDIDATES = ["..", "../.."], findVersionInPackageJson = (startDir) => {
3717
3823
  for (let rel of CANDIDATES) {
3718
- let path24 = (0, import_path19.resolve)(startDir, rel, "package.json");
3719
- if ((0, import_fs19.existsSync)(path24))
3824
+ let path26 = (0, import_path20.resolve)(startDir, rel, "package.json");
3825
+ if ((0, import_fs19.existsSync)(path26))
3720
3826
  try {
3721
- let pkg = JSON.parse((0, import_fs19.readFileSync)(path24, "utf-8"));
3827
+ let pkg = JSON.parse((0, import_fs19.readFileSync)(path26, "utf-8"));
3722
3828
  if (typeof pkg.version == "string") return pkg.version;
3723
3829
  } catch {
3724
3830
  }
@@ -3730,10 +3836,13 @@ var import_fs19 = require("fs"), import_path19 = require("path"), UNKNOWN_VERSIO
3730
3836
  init_verbose();
3731
3837
  init_withErrorHandling();
3732
3838
  async function main() {
3733
- let program = new import_commander2.Command(), version = getVersion();
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) => {
3735
- setVerboseEnabled(!!thisCommand.opts().verbose);
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(
3839
+ let program = new import_commander3.Command(), version = getVersion();
3840
+ 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(
3841
+ "preAction",
3842
+ withErrorHandling(async (thisCommand) => {
3843
+ setVerboseEnabled(!!thisCommand.opts().verbose), await ensureLegalAgreementAccepted();
3844
+ })
3845
+ ), 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("build-docs").description("build diplodoc docs").action(withErrorHandling(buildDocs2)), program.command("debug").description(
3737
3846
  "start a tunnel to connect your local code with the app running in the development environment"
3738
3847
  ).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);
3739
3848
  }