slicejs-cli 3.5.1 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +34 -15
  2. package/client.js +67 -20
  3. package/commands/doctor/doctor.js +69 -3
  4. package/commands/getComponent/getComponent.js +33 -25
  5. package/commands/init/init.js +106 -28
  6. package/commands/utils/PackageManager.js +148 -0
  7. package/commands/utils/VersionChecker.js +6 -4
  8. package/commands/utils/sliceScripts.js +21 -0
  9. package/commands/utils/updateManager.js +54 -35
  10. package/package.json +12 -1
  11. package/post.js +8 -16
  12. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -29
  13. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -25
  14. package/.github/pull_request_template.md +0 -22
  15. package/.github/workflows/ci.yml +0 -43
  16. package/AGENTS.md +0 -247
  17. package/CODE_OF_CONDUCT.md +0 -126
  18. package/ECOSYSTEM.md +0 -9
  19. package/docs/superpowers/specs/2026-05-10-pwa-generate-design.md +0 -182
  20. package/playwright.config.js +0 -51
  21. package/tests/build-command-integration.test.js +0 -87
  22. package/tests/build-production-e2e.test.js +0 -140
  23. package/tests/builder-edge-cases.test.js +0 -322
  24. package/tests/bundle-generate-e2e.test.js +0 -115
  25. package/tests/bundle-generator.test.js +0 -691
  26. package/tests/bundle-v2-register-output.test.js +0 -470
  27. package/tests/bundling-dependency-edges.test.js +0 -127
  28. package/tests/bundling-imports-unit.test.js +0 -267
  29. package/tests/client-launcher-contract.test.js +0 -211
  30. package/tests/client-update-flow-contract.test.js +0 -272
  31. package/tests/commands-component-crud.test.js +0 -102
  32. package/tests/commands-doctor.test.js +0 -80
  33. package/tests/commands-version-checker.test.js +0 -37
  34. package/tests/component-registry-parse.test.js +0 -34
  35. package/tests/dependency-analyzer.test.js +0 -24
  36. package/tests/e2e/bundles.spec.js +0 -91
  37. package/tests/e2e/dependency-scenarios.spec.js +0 -56
  38. package/tests/e2e/fixtures/components/Service/FetchManager/FetchManager.js +0 -136
  39. package/tests/e2e/fixtures/components/Service/IndexedDbManager/IndexedDbManager.js +0 -149
  40. package/tests/e2e/fixtures/components/Service/LocalStorageManager/LocalStorageManager.js +0 -45
  41. package/tests/e2e/fixtures/components/Visual/Button/Button.css +0 -106
  42. package/tests/e2e/fixtures/components/Visual/Button/Button.html +0 -5
  43. package/tests/e2e/fixtures/components/Visual/Button/Button.js +0 -158
  44. package/tests/e2e/fixtures/components/Visual/Link/Link.js +0 -33
  45. package/tests/e2e/fixtures/components/Visual/Loading/Loading.css +0 -56
  46. package/tests/e2e/fixtures/components/Visual/Loading/Loading.html +0 -83
  47. package/tests/e2e/fixtures/components/Visual/Loading/Loading.js +0 -164
  48. package/tests/e2e/fixtures/components/Visual/MultiRoute/MultiRoute.js +0 -167
  49. package/tests/e2e/fixtures/components/Visual/Navbar/Navbar.css +0 -116
  50. package/tests/e2e/fixtures/components/Visual/Navbar/Navbar.html +0 -44
  51. package/tests/e2e/fixtures/components/Visual/Navbar/Navbar.js +0 -180
  52. package/tests/e2e/fixtures/components/Visual/NotFound/NotFound.js +0 -20
  53. package/tests/e2e/fixtures/components/Visual/Route/Route.js +0 -181
  54. package/tests/e2e/fixtures/components/registry.json +0 -12
  55. package/tests/e2e/fixtures/vendor-components.mjs +0 -65
  56. package/tests/e2e/navigation.spec.js +0 -44
  57. package/tests/e2e/render.spec.js +0 -34
  58. package/tests/e2e/serve.mjs +0 -264
  59. package/tests/e2e/shared-deps.spec.js +0 -61
  60. package/tests/e2e/unminified.spec.js +0 -33
  61. package/tests/e2e-serve.test.js +0 -148
  62. package/tests/fixtures/components.js +0 -8
  63. package/tests/fixtures/sliceConfig.json +0 -74
  64. package/tests/getcomponent.test.js +0 -407
  65. package/tests/helpers/setup.js +0 -102
  66. package/tests/init-command-contract.test.js +0 -46
  67. package/tests/local-cli-delegation.test.js +0 -81
  68. package/tests/path-helper.test.js +0 -206
  69. package/tests/perf-budget.test.js +0 -86
  70. package/tests/postinstall-command.test.js +0 -72
  71. package/tests/types-breakage.test.js +0 -491
  72. package/tests/types-generator-errors.test.js +0 -361
  73. package/tests/types-generator.test.js +0 -346
  74. package/tests/update-manager-notifications.test.js +0 -88
@@ -0,0 +1,148 @@
1
+ // commands/utils/PackageManager.js
2
+ //
3
+ // Package manager detection and command building (npm / pnpm / yarn).
4
+ // Resolution priority for an existing project:
5
+ // 1. "packageManager" field in the project package.json (corepack convention)
6
+ // 2. Lockfile present at the project root
7
+ // 3. npm_config_user_agent (set when the CLI runs via `npx` / `pnpm dlx` / a PM script)
8
+ // 4. The only PM binary available on PATH (if exactly one)
9
+ // When everything is ambiguous, detectPackageManager() returns null so callers
10
+ // can prompt the user (interactive init) or fall back to npm (non-interactive).
11
+
12
+ import fs from 'fs-extra'
13
+ import path from 'path'
14
+ import { spawnSync } from 'node:child_process'
15
+
16
+ export const SUPPORTED_PACKAGE_MANAGERS = ['npm', 'pnpm', 'yarn']
17
+
18
+ const LOCKFILES = {
19
+ 'pnpm-lock.yaml': 'pnpm',
20
+ 'package-lock.json': 'npm',
21
+ 'yarn.lock': 'yarn'
22
+ }
23
+
24
+ export function parseUserAgent(userAgent = process.env.npm_config_user_agent) {
25
+ if (!userAgent) return null
26
+ const match = userAgent.match(/^(npm|pnpm|yarn)\/(\S+)/)
27
+ if (!match) return null
28
+ return { name: match[1], version: match[2], source: 'user-agent' }
29
+ }
30
+
31
+ export function fromPackageManagerField(projectRoot) {
32
+ try {
33
+ const pkgPath = path.join(projectRoot, 'package.json')
34
+ if (!fs.pathExistsSync(pkgPath)) return null
35
+ const pkg = fs.readJsonSync(pkgPath)
36
+ if (typeof pkg.packageManager !== 'string') return null
37
+ const match = pkg.packageManager.match(/^(npm|pnpm|yarn)@(\S+)/)
38
+ if (!match) return null
39
+ return { name: match[1], version: match[2], source: 'package-manager-field' }
40
+ } catch {
41
+ return null
42
+ }
43
+ }
44
+
45
+ export function fromLockfile(projectRoot) {
46
+ for (const [lockfile, name] of Object.entries(LOCKFILES)) {
47
+ if (fs.pathExistsSync(path.join(projectRoot, lockfile))) {
48
+ return { name, version: null, source: `lockfile (${lockfile})` }
49
+ }
50
+ }
51
+ return null
52
+ }
53
+
54
+ function runPmBinary(name, args) {
55
+ // On Windows the PM entry points are .cmd shims, which require shell resolution.
56
+ const isWindows = process.platform === 'win32'
57
+ return spawnSync(name, args, {
58
+ stdio: ['ignore', 'pipe', 'ignore'],
59
+ shell: isWindows,
60
+ encoding: 'utf-8'
61
+ })
62
+ }
63
+
64
+ export function isPackageManagerAvailable(name) {
65
+ try {
66
+ const result = runPmBinary(name, ['--version'])
67
+ return result.status === 0
68
+ } catch {
69
+ return false
70
+ }
71
+ }
72
+
73
+ export function getPackageManagerVersion(name) {
74
+ try {
75
+ const result = runPmBinary(name, ['--version'])
76
+ if (result.status !== 0) return null
77
+ return (result.stdout || '').toString().trim() || null
78
+ } catch {
79
+ return null
80
+ }
81
+ }
82
+
83
+ export function getAvailablePackageManagers() {
84
+ return SUPPORTED_PACKAGE_MANAGERS.filter(isPackageManagerAvailable)
85
+ }
86
+
87
+ /**
88
+ * Detect the package manager for a project.
89
+ * Returns { name, version, source } or null when genuinely ambiguous.
90
+ */
91
+ export function detectPackageManager(projectRoot, { userAgent = process.env.npm_config_user_agent } = {}) {
92
+ if (projectRoot) {
93
+ const fromField = fromPackageManagerField(projectRoot)
94
+ if (fromField) return fromField
95
+
96
+ const fromLock = fromLockfile(projectRoot)
97
+ if (fromLock) return fromLock
98
+ }
99
+
100
+ const fromUa = parseUserAgent(userAgent)
101
+ if (fromUa) return fromUa
102
+
103
+ const available = getAvailablePackageManagers()
104
+ if (available.length === 1) {
105
+ return { name: available[0], version: null, source: 'only available binary' }
106
+ }
107
+
108
+ return null
109
+ }
110
+
111
+ /**
112
+ * Non-interactive resolution: detection first, then npm if available,
113
+ * then whatever binary exists. Never returns null so update/doctor flows
114
+ * always have a usable PM name (commands fail later with a clear error
115
+ * if no PM is actually installed).
116
+ */
117
+ export function resolvePackageManager(projectRoot, options = {}) {
118
+ const detected = detectPackageManager(projectRoot, options)
119
+ if (detected) return detected
120
+
121
+ const available = getAvailablePackageManagers()
122
+ if (available.includes('npm')) return { name: 'npm', version: null, source: 'fallback' }
123
+ if (available.length > 0) return { name: available[0], version: null, source: 'fallback' }
124
+ return { name: 'npm', version: null, source: 'fallback (none detected)' }
125
+ }
126
+
127
+ export function installCommand(pmName, packages, { dev = false, global: isGlobal = false } = {}) {
128
+ const pkgs = Array.isArray(packages) ? packages.join(' ') : packages
129
+ const flags = [isGlobal ? '-g' : '', dev ? '-D' : ''].filter(Boolean).join(' ')
130
+ const flagSuffix = flags ? ` ${flags}` : ''
131
+ if (pmName === 'pnpm' || pmName === 'yarn') {
132
+ return `${pmName} add${flagSuffix} ${pkgs}`
133
+ }
134
+ return `npm install${flagSuffix} ${pkgs}`
135
+ }
136
+
137
+ export function uninstallCommand(pmName, packages, { global: isGlobal = false } = {}) {
138
+ const pkgs = Array.isArray(packages) ? packages.join(' ') : packages
139
+ const flagSuffix = isGlobal ? ' -g' : ''
140
+ if (pmName === 'pnpm' || pmName === 'yarn') {
141
+ return `${pmName} remove${flagSuffix} ${pkgs}`
142
+ }
143
+ return `npm uninstall${flagSuffix} ${pkgs}`
144
+ }
145
+
146
+ export function runScriptCommand(pmName, script) {
147
+ return `${pmName} run ${script}`
148
+ }
@@ -5,6 +5,7 @@ import path from "path";
5
5
  import { fileURLToPath } from "url";
6
6
  import Print from "../Print.js";
7
7
  import { getProjectRoot, getPath } from "../utils/PathHelper.js";
8
+ import { resolvePackageManager } from "../utils/PackageManager.js";
8
9
 
9
10
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
11
 
@@ -110,17 +111,18 @@ class VersionChecker {
110
111
  const frameworkStatus = this.compareVersions(current.framework, latest.framework);
111
112
 
112
113
  if (!silent && (cliStatus === 'outdated' || frameworkStatus === 'outdated')) {
114
+ const pm = resolvePackageManager(getProjectRoot(import.meta.url)).name;
113
115
  console.log(''); // Line break
114
116
  Print.warning('📦 Available Updates:');
115
-
117
+
116
118
  if (cliStatus === 'outdated') {
117
119
  console.log(` 🔧 CLI: ${current.cli} → ${latest.cli}`);
118
- console.log(` npm update slicejs-cli`);
120
+ console.log(` ${pm} update slicejs-cli`);
119
121
  }
120
-
122
+
121
123
  if (frameworkStatus === 'outdated') {
122
124
  console.log(` ⚡ Framework: ${current.framework} → ${latest.framework}`);
123
- console.log(` npm update slicejs-web-framework`);
125
+ console.log(` ${pm} update slicejs-web-framework`);
124
126
  }
125
127
 
126
128
  console.log(' 📚 Changelog: https://github.com/VKneider/slice.js/releases');
@@ -0,0 +1,21 @@
1
+ // commands/utils/sliceScripts.js
2
+ //
3
+ // Single source of truth for the slice:* package scripts configured by the CLI.
4
+ // Used by post.js (the postinstall hook), the `slice postinstall` command in
5
+ // client.js, and `slice init` — so the three can never drift apart (they did:
6
+ // client.js was missing slice:types, and none of them had slice:build).
7
+ export const SLICE_SCRIPTS = {
8
+ 'slice:init': 'slice init',
9
+ 'slice:dev': 'slice dev',
10
+ 'slice:build': 'slice build',
11
+ 'slice:start': 'slice start',
12
+ 'slice:create': 'slice component create',
13
+ 'slice:list': 'slice component list',
14
+ 'slice:delete': 'slice component delete',
15
+ 'slice:get': 'slice get',
16
+ 'slice:browse': 'slice browse',
17
+ 'slice:sync': 'slice sync',
18
+ 'slice:version': 'slice version',
19
+ 'slice:update': 'slice update',
20
+ 'slice:types': 'slice types generate',
21
+ };
@@ -7,6 +7,7 @@ import ora from "ora";
7
7
  import Print from "../Print.js";
8
8
  import versionChecker from "./VersionChecker.js";
9
9
  import { getProjectRoot, getApiPath, getPath } from "../utils/PathHelper.js";
10
+ import { resolvePackageManager, installCommand } from "../utils/PackageManager.js";
10
11
  import path from "path";
11
12
  import { fileURLToPath } from "url";
12
13
  import fs from "fs-extra";
@@ -18,28 +19,45 @@ export class UpdateManager {
18
19
  this.packagesToUpdate = [];
19
20
  }
20
21
 
22
+ getPackageManager() {
23
+ if (!this._packageManager) {
24
+ this._packageManager = resolvePackageManager(getProjectRoot(import.meta.url)).name;
25
+ }
26
+ return this._packageManager;
27
+ }
28
+
21
29
  async detectCliInstall() {
22
30
  try {
23
31
  const moduleDir = path.dirname(fileURLToPath(import.meta.url));
24
32
  const cliRoot = path.join(moduleDir, '../../');
25
33
  const projectRoot = getProjectRoot(import.meta.url);
34
+ const packageManager = this.getPackageManager();
35
+ const localNodeModules = path.join(projectRoot, 'node_modules');
36
+
37
+ if (cliRoot.startsWith(localNodeModules)) {
38
+ return { type: 'local', cliRoot, projectRoot, packageManager };
39
+ }
40
+
41
+ // Global pnpm installs live under PNPM_HOME — `npm config get prefix`
42
+ // knows nothing about them (and npm may not even exist on the machine).
43
+ const pnpmHome = process.env.PNPM_HOME;
44
+ if (pnpmHome && cliRoot.startsWith(pnpmHome)) {
45
+ return { type: 'global', cliRoot, projectRoot, packageManager: 'pnpm' };
46
+ }
47
+
26
48
  let globalPrefix = '';
27
49
  try {
28
50
  const { stdout } = await execAsync('npm config get prefix');
29
51
  globalPrefix = stdout.toString().trim();
30
52
  } catch {}
31
- const localNodeModules = path.join(projectRoot, 'node_modules');
32
53
  const globalNodeModules = globalPrefix ? path.join(globalPrefix, 'node_modules') : '';
33
-
34
- if (cliRoot.startsWith(localNodeModules)) {
35
- return { type: 'local', cliRoot, projectRoot, globalPrefix };
36
- }
37
54
  if (globalNodeModules && cliRoot.startsWith(globalNodeModules)) {
38
- return { type: 'global', cliRoot, projectRoot, globalPrefix };
55
+ return { type: 'global', cliRoot, projectRoot, packageManager: 'npm' };
39
56
  }
40
- return { type: 'unknown', cliRoot, projectRoot, globalPrefix };
57
+
58
+ return { type: 'unknown', cliRoot, projectRoot, packageManager };
41
59
  } catch (error) {
42
- return { type: 'unknown' };
60
+ return { type: 'unknown', packageManager: this.getPackageManager() };
43
61
  }
44
62
  }
45
63
 
@@ -180,17 +198,12 @@ export class UpdateManager {
180
198
  async buildUpdatePlan(packages) {
181
199
  const plan = [];
182
200
  const info = await this.detectCliInstall();
201
+ const pm = info.packageManager || this.getPackageManager();
183
202
  for (const pkg of packages) {
184
- if (pkg === 'slicejs-cli') {
185
- if (info.type === 'global') {
186
- plan.push({ package: pkg, target: 'global', command: 'npm install -g slicejs-cli@latest' });
187
- } else {
188
- plan.push({ package: pkg, target: 'project', command: 'npm install slicejs-cli@latest' });
189
- }
190
- } else if (pkg === 'slicejs-web-framework') {
191
- plan.push({ package: pkg, target: 'project', command: 'npm install slicejs-web-framework@latest' });
203
+ if (pkg === 'slicejs-cli' && info.type === 'global') {
204
+ plan.push({ package: pkg, target: 'global', command: installCommand(pm, 'slicejs-cli@latest', { global: true }) });
192
205
  } else {
193
- plan.push({ package: pkg, target: 'project', command: `npm install ${pkg}@latest` });
206
+ plan.push({ package: pkg, target: 'project', command: installCommand(pm, `${pkg}@latest`) });
194
207
  }
195
208
  }
196
209
  return plan;
@@ -201,15 +214,15 @@ export class UpdateManager {
201
214
  */
202
215
  async updatePackage(packageName) {
203
216
  try {
204
- let installCmd = `npm install ${packageName}@latest`;
205
- let uninstallCmd = `npm uninstall ${packageName}`;
217
+ const pm = this.getPackageManager();
218
+ let installCmd = installCommand(pm, `${packageName}@latest`);
206
219
  let options = {};
207
220
 
208
221
  if (packageName === 'slicejs-cli') {
209
222
  const info = await this.detectCliInstall();
210
223
  if (info.type === 'global') {
211
- installCmd = `npm install -g slicejs-cli@latest`;
212
- uninstallCmd = `npm uninstall -g slicejs-cli`;
224
+ const globalPm = info.packageManager || pm;
225
+ installCmd = installCommand(globalPm, 'slicejs-cli@latest', { global: true });
213
226
  } else {
214
227
  options.cwd = info.projectRoot || getProjectRoot(import.meta.url);
215
228
  }
@@ -217,11 +230,9 @@ export class UpdateManager {
217
230
  options.cwd = getProjectRoot(import.meta.url);
218
231
  }
219
232
 
220
- // Try uninstall first (ignore failure)
221
- try {
222
- await execAsync(uninstallCmd, options);
223
- } catch {}
224
-
233
+ // Install directly npm/pnpm upgrade in place. (We used to uninstall
234
+ // first, which left the project without the package whenever the
235
+ // subsequent install failed, e.g. offline or under a release-age policy.)
225
236
  const { stdout, stderr } = await execAsync(installCmd, options);
226
237
 
227
238
  return {
@@ -284,13 +295,12 @@ export class UpdateManager {
284
295
  return false;
285
296
  }
286
297
 
287
- if (updateInfo.allCurrent) {
288
- Print.success('✅ All components are up to date!');
289
- return true;
290
- }
291
-
292
- if (!updateInfo.hasUpdates) {
298
+ if (updateInfo.allCurrent || !updateInfo.hasUpdates) {
293
299
  Print.success('✅ All components are up to date!');
300
+ // --update-api works even when no package update runs.
301
+ if (options.updateApi) {
302
+ await this.updateApiIndexIfNeeded(options);
303
+ }
294
304
  return true;
295
305
  }
296
306
 
@@ -341,7 +351,7 @@ export class UpdateManager {
341
351
  }
342
352
  } else {
343
353
  Print.warning('Global CLI detected. It is recommended to update slicejs-cli globally to keep aligned with the framework.');
344
- console.log(' Suggestion: npm install -g slicejs-cli@latest');
354
+ console.log(` Suggestion: ${installCommand(cliInfo.packageManager || this.getPackageManager(), 'slicejs-cli@latest', { global: true })}`);
345
355
  console.log('');
346
356
  }
347
357
  }
@@ -386,7 +396,7 @@ export class UpdateManager {
386
396
  }
387
397
 
388
398
  const frameworkUpdated = results.find(r => r.packageName === 'slicejs-web-framework' && r.success);
389
- if (frameworkUpdated) {
399
+ if (frameworkUpdated || options.updateApi) {
390
400
  await this.updateApiIndexIfNeeded(options);
391
401
  }
392
402
 
@@ -417,7 +427,16 @@ export class UpdateManager {
417
427
 
418
428
  Print.warning('⚠️ Detected changes in framework api/index.js.');
419
429
 
420
- let confirmUpdate = options.yes === true;
430
+ // Overwriting api/index.js is opt-in: `--update-api` is the only way
431
+ // to auto-confirm. `-y/--yes` deliberately does NOT imply it — the
432
+ // project file may carry local changes, so a blanket "yes to updates"
433
+ // must not silently replace it.
434
+ let confirmUpdate = options.updateApi === true;
435
+ if (!confirmUpdate && options.yes === true) {
436
+ Print.info('Skipping api/index.js update (not updated by default).');
437
+ Print.info('Run "slice update --update-api" to update it (a .bak backup is created).');
438
+ return;
439
+ }
421
440
  if (!confirmUpdate) {
422
441
  const answers = await inquirer.prompt([
423
442
  {
package/package.json CHANGED
@@ -1,11 +1,20 @@
1
1
  {
2
2
  "name": "slicejs-cli",
3
- "version": "3.5.1",
3
+ "version": "3.6.0",
4
4
  "description": "Command client for developing web applications with Slice.js framework",
5
5
  "main": "client.js",
6
6
  "bin": {
7
7
  "slice": "./client.js"
8
8
  },
9
+ "engines": {
10
+ "node": ">=20.0.0"
11
+ },
12
+ "files": [
13
+ "client.js",
14
+ "post.js",
15
+ "commands",
16
+ "assets"
17
+ ],
9
18
  "repository": {
10
19
  "type": "git",
11
20
  "url": "https://github.com/vkneider/slicejs-cli.git"
@@ -14,6 +23,7 @@
14
23
  "test": "node --test",
15
24
  "postinstall": "node post.js",
16
25
  "slice:dev": "slice dev",
26
+ "slice:build": "slice build",
17
27
  "slice:start": "slice start",
18
28
  "slice:create": "slice component create",
19
29
  "slice:list": "slice component list",
@@ -38,6 +48,7 @@
38
48
  ],
39
49
  "author": "vkneider",
40
50
  "type": "module",
51
+ "packageManager": "pnpm@11.1.1",
41
52
  "preferGlobal": false,
42
53
  "license": "ISC",
43
54
  "dependencies": {
package/post.js CHANGED
@@ -2,35 +2,27 @@ import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { fileURLToPath } from 'url';
4
4
  import { getProjectRoot, getPath } from './commands/utils/PathHelper.js';
5
+ import { SLICE_SCRIPTS } from './commands/utils/sliceScripts.js';
5
6
 
6
7
  const __filename = fileURLToPath(import.meta.url);
7
8
 
8
- const isGlobal = process.env.npm_config_global === 'true';
9
+ // npm sets npm_config_global; pnpm does not — for pnpm a global install lives
10
+ // under PNPM_HOME, so detect it by where this script is running from.
11
+ const pnpmHome = process.env.PNPM_HOME;
12
+ const isGlobal = process.env.npm_config_global === 'true'
13
+ || (pnpmHome && __filename.startsWith(pnpmHome));
9
14
 
10
15
  if (isGlobal) {
11
16
  console.log('⚠️ Global installation of slicejs-cli detected.');
12
17
  console.log(' We strongly recommend using a local installation to avoid version mismatches.');
13
- console.log(' Uninstall global: npm uninstall -g slicejs-cli');
18
+ console.log(` Uninstall global: ${pnpmHome ? 'pnpm remove -g slicejs-cli' : 'npm uninstall -g slicejs-cli'}`);
14
19
  process.exit(0);
15
20
  }
16
21
 
17
22
  const projectRoot = getProjectRoot(import.meta.url);
18
23
  const pkgPath = getPath(import.meta.url, 'package.json');
19
24
 
20
- const sliceScripts = {
21
- 'slice:dev': 'slice dev',
22
- 'slice:start': 'slice start',
23
- 'slice:create': 'slice component create',
24
- 'slice:list': 'slice component list',
25
- 'slice:delete': 'slice component delete',
26
- 'slice:init': 'slice init',
27
- 'slice:get': 'slice get',
28
- 'slice:browse': 'slice browse',
29
- 'slice:sync': 'slice sync',
30
- 'slice:version': 'slice version',
31
- 'slice:update': 'slice update',
32
- 'slice:types': 'slice types generate',
33
- };
25
+ const sliceScripts = SLICE_SCRIPTS;
34
26
 
35
27
  try {
36
28
  let pkg = {};
@@ -1,29 +0,0 @@
1
- ---
2
- name: Bug Report
3
- about: Report a bug in a component or the parser
4
- title: ''
5
- labels: bug
6
- assignees: ''
7
- ---
8
-
9
- ## Description
10
- A clear description of the bug.
11
-
12
- ## Reproduction
13
- Steps to reproduce:
14
- 1. Go to '...'
15
- 2. Click on '...'
16
- 3. Error: '...'
17
-
18
- ## Expected behavior
19
- What should have happened.
20
-
21
- ## Environment
22
- - Browser/Node version:
23
- - OS:
24
- - slice.js_visual_library version:
25
-
26
- ## Screenshots / Console output
27
- If applicable.
28
-
29
- ## Additional context
@@ -1,25 +0,0 @@
1
- ---
2
- name: Feature Request
3
- about: Suggest a new component or improvement
4
- title: ''
5
- labels: enhancement
6
- assignees: ''
7
- ---
8
-
9
- ## Problem
10
- What problem does this solve? (e.g. "I need a component that...")
11
-
12
- ## Proposed solution
13
- How should it work? Include props, behavior, and visual details if applicable.
14
-
15
- ## Alternatives considered
16
- What other approaches have you considered?
17
-
18
- ## Example usage
19
- ```javascript
20
- const component = await slice.build('ComponentName', {
21
- // props here
22
- });
23
- ```
24
-
25
- ## Additional context
@@ -1,22 +0,0 @@
1
- ## Summary
2
- -
3
-
4
- ## Docs Scope
5
- - [ ] Visual library docs pages (`src/markdown/` and generated outputs)
6
- - [ ] Parser logic (`parser/`)
7
- - [ ] Routes/index sync (`documentationRoutes.generated.js`, `docsIndex.js`, `components.js`)
8
-
9
- ## Verification
10
- - [ ] `npm run docs:lint-md`
11
- - [ ] `npm run docs:generate`
12
- - [ ] `node --test parser/tests/index.test.js`
13
-
14
- ## Screenshots / UI Notes
15
- -
16
-
17
- ## Breaking Changes
18
- - [ ] None
19
- - [ ] Yes (describe below)
20
-
21
- ## Additional Context
22
- -
@@ -1,43 +0,0 @@
1
- name: CI
2
-
3
- on:
4
- push:
5
- branches: [master, main]
6
- pull_request:
7
-
8
- jobs:
9
- test:
10
- runs-on: ubuntu-latest
11
- timeout-minutes: 20
12
- steps:
13
- - uses: actions/checkout@v4
14
-
15
- - uses: pnpm/action-setup@v4
16
- with:
17
- version: 11
18
-
19
- - uses: actions/setup-node@v4
20
- with:
21
- node-version: 22
22
- cache: pnpm
23
-
24
- - name: Install dependencies
25
- run: pnpm install --frozen-lockfile
26
-
27
- - name: Install Playwright browser
28
- run: pnpm exec playwright install --with-deps chromium
29
-
30
- # Serialized to avoid resource contention between the build-heavy
31
- # integration tests under parallel runners.
32
- - name: Unit & integration tests
33
- run: node --test --test-concurrency=1
34
-
35
- - name: Browser E2E tests
36
- run: pnpm exec playwright test
37
-
38
- - uses: actions/upload-artifact@v4
39
- if: ${{ !cancelled() }}
40
- with:
41
- name: playwright-report
42
- path: playwright-report/
43
- retention-days: 7