climaybe 3.0.1 → 3.0.3
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/README.md +11 -5
- package/bin/version.txt +1 -1
- package/package.json +5 -5
- package/src/commands/update-workflows.js +31 -4
- package/src/index.js +5 -4
- package/src/lib/theme-dev-kit.js +23 -29
- package/src/lib/update-notifier.js +43 -5
package/README.md
CHANGED
|
@@ -115,15 +115,21 @@ npx climaybe ensure-branches
|
|
|
115
115
|
git push origin --all
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
-
### `climaybe update
|
|
118
|
+
### `climaybe update` / `climaybe theme update`
|
|
119
119
|
|
|
120
|
-
Refresh
|
|
120
|
+
Refresh all climaybe-managed project files from your installed CLI version:
|
|
121
|
+
- GitHub workflows
|
|
122
|
+
- root dev-kit files (`.theme-check.yml`, `.shopifyignore`, `.prettierrc`, `.lighthouserc.js`, `.gitignore`)
|
|
123
|
+
- `package.json` managed deps (`climaybe`, `tailwindcss`)
|
|
124
|
+
- optional `.vscode/tasks.json` (if enabled)
|
|
125
|
+
- optional commitlint + Husky files (if enabled)
|
|
126
|
+
- optional Cursor bundle files (if enabled)
|
|
121
127
|
|
|
122
128
|
```bash
|
|
123
|
-
npx climaybe update
|
|
129
|
+
npx climaybe update
|
|
124
130
|
```
|
|
125
131
|
|
|
126
|
-
|
|
132
|
+
`update-workflows` still works as a backward-compatible alias.
|
|
127
133
|
|
|
128
134
|
### `climaybe setup-commitlint`
|
|
129
135
|
|
|
@@ -141,7 +147,7 @@ Install Electric Maybe **Cursor rules, skills, and subagents** into `.cursor/rul
|
|
|
141
147
|
npx climaybe add-cursor
|
|
142
148
|
```
|
|
143
149
|
|
|
144
|
-
The previous command name `add-cursor-skill` still works as an alias. Re-running replaces the bundled rules, skills, and subagent files with the copies shipped by your installed climaybe version (same idea as `update
|
|
150
|
+
The previous command name `add-cursor-skill` still works as an alias. Re-running replaces the bundled rules, skills, and subagent files with the copies shipped by your installed climaybe version (same idea as `update`).
|
|
145
151
|
|
|
146
152
|
## Configuration
|
|
147
153
|
|
package/bin/version.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.0.
|
|
1
|
+
3.0.3
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "climaybe",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.3",
|
|
4
4
|
"description": "Shopify CLI by Electric Maybe for theme CI/CD workflows, branch orchestration, app setup, and dev tooling",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -81,14 +81,14 @@
|
|
|
81
81
|
"@shopify/prettier-plugin-liquid": "^1.6.3",
|
|
82
82
|
"@tailwindcss/cli": "^4.1.17",
|
|
83
83
|
"@tailwindcss/typography": "^0.5.16",
|
|
84
|
+
"commander": "^14.0.3",
|
|
84
85
|
"eslint": "^9.11.0",
|
|
86
|
+
"picocolors": "^1.1.1",
|
|
85
87
|
"prettier": "^3.4.2",
|
|
88
|
+
"prompts": "^2.4.2",
|
|
86
89
|
"stylelint": "^16.9.0",
|
|
87
90
|
"stylelint-config-standard": "^36.0.1",
|
|
88
|
-
"tailwindcss": "^4.1.18"
|
|
89
|
-
"commander": "^14.0.3",
|
|
90
|
-
"picocolors": "^1.1.1",
|
|
91
|
-
"prompts": "^2.4.2"
|
|
91
|
+
"tailwindcss": "^4.1.18"
|
|
92
92
|
},
|
|
93
93
|
"devDependencies": {
|
|
94
94
|
"@commitlint/cli": "^20.4.4",
|
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
import pc from 'picocolors';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
getMode,
|
|
4
|
+
isBuildWorkflowsEnabled,
|
|
5
|
+
isCommitlintEnabled,
|
|
6
|
+
isCursorSkillsEnabled,
|
|
7
|
+
isPreviewWorkflowsEnabled,
|
|
8
|
+
readConfig,
|
|
9
|
+
} from '../lib/config.js';
|
|
3
10
|
import { scaffoldWorkflows } from '../lib/workflows.js';
|
|
4
11
|
import { requireThemeProject } from '../lib/theme-guard.js';
|
|
12
|
+
import { scaffoldThemeDevKit } from '../lib/theme-dev-kit.js';
|
|
13
|
+
import { scaffoldCommitlint } from '../lib/commit-tooling.js';
|
|
14
|
+
import { scaffoldCursorBundle } from '../lib/cursor-bundle.js';
|
|
5
15
|
|
|
6
|
-
export async function
|
|
7
|
-
console.log(pc.bold('\n climaybe — Update
|
|
16
|
+
export async function updateCommand() {
|
|
17
|
+
console.log(pc.bold('\n climaybe — Update\n'));
|
|
8
18
|
|
|
9
19
|
if (!requireThemeProject()) return;
|
|
10
20
|
|
|
@@ -17,7 +27,24 @@ export async function updateWorkflowsCommand() {
|
|
|
17
27
|
const mode = getMode();
|
|
18
28
|
const includePreview = isPreviewWorkflowsEnabled();
|
|
19
29
|
const includeBuild = isBuildWorkflowsEnabled();
|
|
30
|
+
|
|
31
|
+
// Keep theme project files in sync (root files, package.json, .gitignore, VS Code tasks).
|
|
32
|
+
scaffoldThemeDevKit({
|
|
33
|
+
includeVSCodeTasks: !!config.vscode_tasks,
|
|
34
|
+
defaultStoreDomain: config.default_store || '',
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if (isCommitlintEnabled()) {
|
|
38
|
+
scaffoldCommitlint(process.cwd(), { skipInstall: true });
|
|
39
|
+
}
|
|
40
|
+
if (isCursorSkillsEnabled()) {
|
|
41
|
+
scaffoldCursorBundle();
|
|
42
|
+
}
|
|
43
|
+
|
|
20
44
|
scaffoldWorkflows(mode, { includePreview, includeBuild });
|
|
21
45
|
|
|
22
|
-
console.log(pc.bold(pc.green('\n
|
|
46
|
+
console.log(pc.bold(pc.green('\n Project files updated!\n')));
|
|
23
47
|
}
|
|
48
|
+
|
|
49
|
+
// Backward-compatible export for old command name.
|
|
50
|
+
export const updateWorkflowsCommand = updateCommand;
|
package/src/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { initCommand, reinitCommand } from './commands/init.js';
|
|
|
3
3
|
import { addStoreCommand } from './commands/add-store.js';
|
|
4
4
|
import { switchCommand } from './commands/switch.js';
|
|
5
5
|
import { syncCommand } from './commands/sync.js';
|
|
6
|
-
import {
|
|
6
|
+
import { updateCommand } from './commands/update-workflows.js';
|
|
7
7
|
import { ensureBranchesCommand } from './commands/ensure-branches.js';
|
|
8
8
|
import { setupCommitlintCommand } from './commands/setup-commitlint.js';
|
|
9
9
|
import { addCursorSkillCommand } from './commands/add-cursor-skill.js';
|
|
@@ -81,9 +81,10 @@ function registerThemeCommands(cmd) {
|
|
|
81
81
|
.action(createEntrypointsCommand);
|
|
82
82
|
|
|
83
83
|
cmd
|
|
84
|
-
.command('update
|
|
85
|
-
.
|
|
86
|
-
.
|
|
84
|
+
.command('update')
|
|
85
|
+
.alias('update-workflows')
|
|
86
|
+
.description('Refresh workflows and all climaybe-managed project files')
|
|
87
|
+
.action(updateCommand);
|
|
87
88
|
|
|
88
89
|
cmd
|
|
89
90
|
.command('ensure-branches')
|
package/src/lib/theme-dev-kit.js
CHANGED
|
@@ -66,43 +66,20 @@ const VSCODE_TASKS_CONTENT = `{
|
|
|
66
66
|
"version": "2.0.0",
|
|
67
67
|
"tasks": [
|
|
68
68
|
{
|
|
69
|
-
"label": "
|
|
69
|
+
"label": "Climaybe Serve",
|
|
70
70
|
"type": "shell",
|
|
71
|
-
"command": "climaybe serve
|
|
71
|
+
"command": "climaybe serve",
|
|
72
72
|
"isBackground": true,
|
|
73
73
|
"presentation": {
|
|
74
74
|
"echo": true,
|
|
75
75
|
"reveal": "always",
|
|
76
76
|
"focus": true,
|
|
77
|
-
"panel": "
|
|
77
|
+
"panel": "shared",
|
|
78
78
|
"group": "develop",
|
|
79
79
|
"showReuseMessage": false,
|
|
80
80
|
"clear": true
|
|
81
81
|
},
|
|
82
82
|
"problemMatcher": []
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
"label": "Tailwind",
|
|
86
|
-
"type": "shell",
|
|
87
|
-
"command": "climaybe serve:assets",
|
|
88
|
-
"isBackground": true,
|
|
89
|
-
"presentation": {
|
|
90
|
-
"echo": true,
|
|
91
|
-
"reveal": "always",
|
|
92
|
-
"focus": false,
|
|
93
|
-
"panel": "new",
|
|
94
|
-
"group": "develop",
|
|
95
|
-
"showReuseMessage": false,
|
|
96
|
-
"clear": true
|
|
97
|
-
},
|
|
98
|
-
"problemMatcher": []
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
"label": "Run Both Consoles",
|
|
102
|
-
"dependsOn": ["Shopify", "Tailwind"],
|
|
103
|
-
"runOptions": {
|
|
104
|
-
"runOn": "folderOpen"
|
|
105
|
-
}
|
|
106
83
|
}
|
|
107
84
|
]
|
|
108
85
|
}
|
|
@@ -111,6 +88,8 @@ const VSCODE_TASKS_CONTENT = `{
|
|
|
111
88
|
const GITIGNORE_BLOCK = `# climaybe: theme dev kit (managed)
|
|
112
89
|
.vscode
|
|
113
90
|
node_modules/
|
|
91
|
+
.DS_Store
|
|
92
|
+
**/.DS_Store
|
|
114
93
|
assets/style.css
|
|
115
94
|
assets/index.js
|
|
116
95
|
.shopify
|
|
@@ -128,8 +107,21 @@ function mergeGitignore(cwd = process.cwd()) {
|
|
|
128
107
|
return;
|
|
129
108
|
}
|
|
130
109
|
const current = readFileSync(path, 'utf-8');
|
|
131
|
-
|
|
132
|
-
|
|
110
|
+
const marker = '# climaybe: theme dev kit (managed)';
|
|
111
|
+
if (current.includes(marker)) {
|
|
112
|
+
const lines = current.split('\n');
|
|
113
|
+
const start = lines.findIndex((line) => line.trim() === marker);
|
|
114
|
+
if (start >= 0) {
|
|
115
|
+
let end = start + 1;
|
|
116
|
+
while (end < lines.length && lines[end].trim() !== '') end += 1;
|
|
117
|
+
const before = lines.slice(0, start).join('\n').trimEnd();
|
|
118
|
+
const after = lines.slice(end).join('\n').trim();
|
|
119
|
+
const segments = [before, GITIGNORE_BLOCK.trimEnd(), after].filter(Boolean);
|
|
120
|
+
writeFileSync(path, `${segments.join('\n\n')}\n`, 'utf-8');
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const next = `${current.trimEnd()}\n\n${GITIGNORE_BLOCK.trimEnd()}`;
|
|
133
125
|
writeFileSync(path, `${next}\n`, 'utf-8');
|
|
134
126
|
}
|
|
135
127
|
|
|
@@ -151,12 +143,14 @@ function mergePackageJson({ packageName = 'shopify-theme', cwd = process.cwd() }
|
|
|
151
143
|
if (!pkg.author) {
|
|
152
144
|
pkg.author = 'Electric Maybe <hello@electricmaybe.com>';
|
|
153
145
|
}
|
|
146
|
+
pkg.dependencies = { ...(pkg.dependencies || {}) };
|
|
154
147
|
pkg.devDependencies = { ...(pkg.devDependencies || {}) };
|
|
155
148
|
|
|
156
149
|
// Ensure teammates can run climaybe + Tailwind after plain npm install.
|
|
157
150
|
const cliVersion = process.env.CLIMAYBE_PACKAGE_VERSION;
|
|
158
151
|
const climaybeRange = /^\d+\.\d+\.\d+/.test(String(cliVersion || '')) ? `^${cliVersion}` : 'latest';
|
|
159
|
-
if (!pkg.
|
|
152
|
+
if (!pkg.dependencies.climaybe) pkg.dependencies.climaybe = climaybeRange;
|
|
153
|
+
if (pkg.devDependencies.climaybe) delete pkg.devDependencies.climaybe;
|
|
160
154
|
if (!pkg.devDependencies.tailwindcss) pkg.devDependencies.tailwindcss = 'latest';
|
|
161
155
|
|
|
162
156
|
writePkg(pkg, cwd);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { execSync } from 'node:child_process';
|
|
2
2
|
import { stdin as input, stdout as output } from 'node:process';
|
|
3
3
|
import { createInterface } from 'node:readline/promises';
|
|
4
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
5
|
+
import { join, resolve } from 'node:path';
|
|
4
6
|
import pc from 'picocolors';
|
|
5
7
|
|
|
6
8
|
const NPM_REGISTRY_BASE = 'https://registry.npmjs.org';
|
|
@@ -43,8 +45,42 @@ function canPromptForUpdate() {
|
|
|
43
45
|
return Boolean(input.isTTY && output.isTTY && process.env.CI !== 'true');
|
|
44
46
|
}
|
|
45
47
|
|
|
46
|
-
function
|
|
47
|
-
|
|
48
|
+
export function resolveInstallScope({ packageDir, cwd = process.cwd() } = {}) {
|
|
49
|
+
try {
|
|
50
|
+
const globalRoot = execSync('npm root -g', { encoding: 'utf-8', stdio: 'pipe' }).trim();
|
|
51
|
+
if (packageDir && resolve(packageDir).startsWith(resolve(globalRoot))) return 'global';
|
|
52
|
+
} catch {
|
|
53
|
+
// ignore and fallback to local checks
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (existsSync(join(cwd, 'package.json'))) return 'local';
|
|
57
|
+
return 'global';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function getLocalInstallFlag({ packageName, cwd = process.cwd() } = {}) {
|
|
61
|
+
// Always keep climaybe in runtime dependencies for theme repos.
|
|
62
|
+
if (packageName === 'climaybe') return '--save';
|
|
63
|
+
try {
|
|
64
|
+
const pkgPath = join(cwd, 'package.json');
|
|
65
|
+
if (!existsSync(pkgPath)) return '--save-dev';
|
|
66
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
67
|
+
if (pkg?.dependencies?.[packageName]) return '--save';
|
|
68
|
+
if (pkg?.devDependencies?.[packageName]) return '--save-dev';
|
|
69
|
+
return '--save-dev';
|
|
70
|
+
} catch {
|
|
71
|
+
return '--save-dev';
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function runUpdate(packageName, { packageDir, cwd = process.cwd() } = {}) {
|
|
76
|
+
const scope = resolveInstallScope({ packageDir, cwd });
|
|
77
|
+
if (scope === 'global') {
|
|
78
|
+
execSync(`npm install -g ${packageName}@latest`, { stdio: 'inherit' });
|
|
79
|
+
return 'global';
|
|
80
|
+
}
|
|
81
|
+
const flag = getLocalInstallFlag({ packageName, cwd });
|
|
82
|
+
execSync(`npm install ${packageName}@latest ${flag}`, { cwd, stdio: 'inherit' });
|
|
83
|
+
return 'local';
|
|
48
84
|
}
|
|
49
85
|
|
|
50
86
|
export async function maybeOfferCliUpdate({
|
|
@@ -54,6 +90,7 @@ export async function maybeOfferCliUpdate({
|
|
|
54
90
|
timeoutMs = DEFAULT_TIMEOUT_MS,
|
|
55
91
|
} = {}) {
|
|
56
92
|
if (!packageName || !currentVersion || !canPromptForUpdate()) return;
|
|
93
|
+
const invocationCwd = process.cwd();
|
|
57
94
|
|
|
58
95
|
const latestVersion = await fetchLatestVersion(packageName, timeoutMs);
|
|
59
96
|
if (!latestVersion || !isVersionGreater(latestVersion, currentVersion)) return;
|
|
@@ -68,9 +105,10 @@ export async function maybeOfferCliUpdate({
|
|
|
68
105
|
if (!shouldUpdate) return;
|
|
69
106
|
|
|
70
107
|
try {
|
|
71
|
-
|
|
72
|
-
console.log(pc.green(`Updated ${packageName} to latest. Restarting command...`));
|
|
73
|
-
|
|
108
|
+
const updatedScope = runUpdate(packageName, { packageDir, cwd: process.cwd() });
|
|
109
|
+
console.log(pc.green(`Updated ${packageName} (${updatedScope}) to latest. Restarting command...`));
|
|
110
|
+
// Continue in the repo where the user invoked the command.
|
|
111
|
+
process.chdir(invocationCwd);
|
|
74
112
|
} catch (err) {
|
|
75
113
|
console.log(pc.red('Update failed. Continuing with current version.'));
|
|
76
114
|
if (err?.message) console.log(pc.dim(err.message));
|