@meltstudio/meltctl 4.34.0 → 4.36.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/dist/commands/audit.js +66 -111
- package/dist/commands/audit.test.js +118 -209
- package/dist/commands/coins.js +30 -28
- package/dist/commands/coins.test.js +23 -43
- package/dist/commands/feedback.js +8 -17
- package/dist/commands/feedback.test.js +38 -103
- package/dist/commands/login.js +15 -20
- package/dist/commands/plan.js +21 -51
- package/dist/commands/plan.test.js +95 -132
- package/dist/commands/standup.js +10 -14
- package/dist/commands/standup.test.js +66 -100
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.js +74 -0
- package/dist/commands/update.test.d.ts +1 -0
- package/dist/commands/update.test.js +93 -0
- package/dist/index.js +7 -0
- package/dist/utils/analytics.js +9 -19
- package/dist/utils/api.d.ts +2 -1
- package/dist/utils/api.js +4 -12
- package/dist/utils/api.test.js +25 -45
- package/dist/utils/templates.d.ts +2 -4
- package/dist/utils/templates.js +3 -7
- package/dist/utils/templates.test.js +14 -26
- package/dist/utils/version-check.js +17 -15
- package/dist/utils/version-check.test.js +20 -2
- package/package.json +3 -2
package/dist/utils/templates.js
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getClient } from './api.js';
|
|
2
2
|
export async function fetchTemplates() {
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
throw new Error(`Failed to fetch templates: ${response.statusText}`);
|
|
6
|
-
}
|
|
7
|
-
const data = (await response.json());
|
|
8
|
-
return data.files;
|
|
3
|
+
const client = await getClient();
|
|
4
|
+
return client.templates.fetch();
|
|
9
5
|
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
vi.
|
|
3
|
-
|
|
2
|
+
const mockClient = vi.hoisted(() => ({
|
|
3
|
+
templates: {
|
|
4
|
+
fetch: vi.fn(),
|
|
5
|
+
},
|
|
6
|
+
}));
|
|
7
|
+
vi.mock('./api.js', () => ({
|
|
8
|
+
getClient: vi.fn().mockResolvedValue(mockClient),
|
|
4
9
|
}));
|
|
5
|
-
import { authenticatedFetch } from './auth.js';
|
|
6
10
|
import { fetchTemplates } from './templates.js';
|
|
7
11
|
beforeEach(() => {
|
|
8
12
|
vi.clearAllMocks();
|
|
@@ -13,38 +17,22 @@ describe('fetchTemplates', () => {
|
|
|
13
17
|
'AGENTS.md': '# Agents content',
|
|
14
18
|
'.claude/skills/setup.md': '# Setup skill',
|
|
15
19
|
};
|
|
16
|
-
|
|
17
|
-
ok: true,
|
|
18
|
-
json: vi.fn().mockResolvedValue({ files: mockFiles }),
|
|
19
|
-
});
|
|
20
|
+
mockClient.templates.fetch.mockResolvedValue(mockFiles);
|
|
20
21
|
const result = await fetchTemplates();
|
|
21
|
-
expect(
|
|
22
|
+
expect(mockClient.templates.fetch).toHaveBeenCalled();
|
|
22
23
|
expect(result).toEqual(mockFiles);
|
|
23
24
|
});
|
|
24
25
|
it('throws error when API returns failure', async () => {
|
|
25
|
-
;
|
|
26
|
-
authenticatedFetch.mockResolvedValue({
|
|
27
|
-
ok: false,
|
|
28
|
-
statusText: 'Unauthorized',
|
|
29
|
-
});
|
|
26
|
+
mockClient.templates.fetch.mockRejectedValue(new Error('Failed to fetch templates: Unauthorized'));
|
|
30
27
|
await expect(fetchTemplates()).rejects.toThrow('Failed to fetch templates: Unauthorized');
|
|
31
28
|
});
|
|
32
29
|
it('throws error when API returns 500', async () => {
|
|
33
|
-
;
|
|
34
|
-
authenticatedFetch.mockResolvedValue({
|
|
35
|
-
ok: false,
|
|
36
|
-
statusText: 'Internal Server Error',
|
|
37
|
-
});
|
|
30
|
+
mockClient.templates.fetch.mockRejectedValue(new Error('Failed to fetch templates: Internal Server Error'));
|
|
38
31
|
await expect(fetchTemplates()).rejects.toThrow('Failed to fetch templates: Internal Server Error');
|
|
39
32
|
});
|
|
40
|
-
it('calls
|
|
41
|
-
;
|
|
42
|
-
authenticatedFetch.mockResolvedValue({
|
|
43
|
-
ok: true,
|
|
44
|
-
json: vi.fn().mockResolvedValue({ files: {} }),
|
|
45
|
-
});
|
|
33
|
+
it('calls client.templates.fetch', async () => {
|
|
34
|
+
mockClient.templates.fetch.mockResolvedValue({});
|
|
46
35
|
await fetchTemplates();
|
|
47
|
-
expect(
|
|
48
|
-
expect(authenticatedFetch).toHaveBeenCalledWith('/templates');
|
|
36
|
+
expect(mockClient.templates.fetch).toHaveBeenCalledTimes(1);
|
|
49
37
|
});
|
|
50
38
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
+
import { confirm } from '@inquirer/prompts';
|
|
2
3
|
import { execSync } from 'child_process';
|
|
3
4
|
import fs from 'fs-extra';
|
|
4
5
|
import path from 'path';
|
|
@@ -101,29 +102,30 @@ export async function checkAndEnforceUpdate() {
|
|
|
101
102
|
if (severity === 'none') {
|
|
102
103
|
return;
|
|
103
104
|
}
|
|
104
|
-
const updateCmd = 'npm install -g @meltstudio/meltctl@latest';
|
|
105
105
|
if (severity === 'patch') {
|
|
106
106
|
// Patch updates: warn but allow continuing
|
|
107
107
|
console.log();
|
|
108
|
-
console.log(chalk.yellow(` Update available: ${currentVersion} → ${latestVersion} (run:
|
|
108
|
+
console.log(chalk.yellow(` Update available: ${currentVersion} → ${latestVersion} (run: meltctl update)`));
|
|
109
109
|
console.log();
|
|
110
110
|
return;
|
|
111
111
|
}
|
|
112
|
-
// Minor/major updates: block
|
|
112
|
+
// Minor/major updates: offer to update, block if declined
|
|
113
113
|
console.log();
|
|
114
|
-
console.log(chalk.
|
|
115
|
-
console.log(chalk.red.bold(' ⚠️ Update Required'));
|
|
116
|
-
console.log(chalk.red('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
114
|
+
console.log(chalk.yellow(` Update required: ${currentVersion} → ${latestVersion}`));
|
|
117
115
|
console.log();
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
116
|
+
const shouldUpdate = await confirm({
|
|
117
|
+
message: 'Update now?',
|
|
118
|
+
default: true,
|
|
119
|
+
});
|
|
120
|
+
if (shouldUpdate) {
|
|
121
|
+
const { updateCommand } = await import('../commands/update.js');
|
|
122
|
+
await updateCommand();
|
|
123
|
+
// Re-run the original command after update
|
|
124
|
+
console.log();
|
|
125
|
+
console.log(chalk.dim(' Please re-run your command.'));
|
|
126
|
+
console.log();
|
|
127
|
+
process.exit(0);
|
|
128
|
+
}
|
|
127
129
|
console.log();
|
|
128
130
|
console.log(chalk.gray('To skip this check (CI/CD), set MELTCTL_SKIP_UPDATE_CHECK=1'));
|
|
129
131
|
console.log();
|
|
@@ -7,8 +7,15 @@ vi.mock('fs-extra', () => ({
|
|
|
7
7
|
readJson: vi.fn(),
|
|
8
8
|
},
|
|
9
9
|
}));
|
|
10
|
+
vi.mock('@inquirer/prompts', () => ({
|
|
11
|
+
confirm: vi.fn(),
|
|
12
|
+
}));
|
|
13
|
+
vi.mock('../commands/update.js', () => ({
|
|
14
|
+
updateCommand: vi.fn().mockResolvedValue(undefined),
|
|
15
|
+
}));
|
|
10
16
|
import { execSync } from 'child_process';
|
|
11
17
|
import fs from 'fs-extra';
|
|
18
|
+
import { confirm } from '@inquirer/prompts';
|
|
12
19
|
import { getCurrentCliVersion, getLatestCliVersion, compareVersions, getUpdateSeverity, isCI, checkAndEnforceUpdate, } from './version-check.js';
|
|
13
20
|
beforeEach(() => {
|
|
14
21
|
vi.clearAllMocks();
|
|
@@ -139,17 +146,28 @@ describe('checkAndEnforceUpdate', () => {
|
|
|
139
146
|
await checkAndEnforceUpdate();
|
|
140
147
|
// Should not throw or exit
|
|
141
148
|
});
|
|
142
|
-
it('
|
|
149
|
+
it('exits when user declines update on minor bump', async () => {
|
|
143
150
|
const exitSpy = vi.spyOn(process, 'exit').mockImplementation(() => undefined);
|
|
144
151
|
fs.readJson.mockResolvedValue({ version: '4.25.0' });
|
|
145
152
|
execSync.mockReturnValue('"4.26.0"\n');
|
|
153
|
+
vi.mocked(confirm).mockResolvedValue(false);
|
|
146
154
|
await checkAndEnforceUpdate();
|
|
155
|
+
expect(confirm).toHaveBeenCalled();
|
|
147
156
|
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
148
157
|
});
|
|
149
|
-
it('
|
|
158
|
+
it('runs update when user accepts on minor bump', async () => {
|
|
159
|
+
const exitSpy = vi.spyOn(process, 'exit').mockImplementation(() => undefined);
|
|
160
|
+
fs.readJson.mockResolvedValue({ version: '4.25.0' });
|
|
161
|
+
execSync.mockReturnValue('"4.26.0"\n');
|
|
162
|
+
vi.mocked(confirm).mockResolvedValue(true);
|
|
163
|
+
await checkAndEnforceUpdate();
|
|
164
|
+
expect(exitSpy).toHaveBeenCalledWith(0);
|
|
165
|
+
});
|
|
166
|
+
it('exits when user declines update on major bump', async () => {
|
|
150
167
|
const exitSpy = vi.spyOn(process, 'exit').mockImplementation(() => undefined);
|
|
151
168
|
fs.readJson.mockResolvedValue({ version: '4.33.0' });
|
|
152
169
|
execSync.mockReturnValue('"5.0.0"\n');
|
|
170
|
+
vi.mocked(confirm).mockResolvedValue(false);
|
|
153
171
|
await checkAndEnforceUpdate();
|
|
154
172
|
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
155
173
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meltstudio/meltctl",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.36.0",
|
|
4
4
|
"description": "AI-first development tools for teams - set up AGENTS.md, Claude Code, Cursor, and OpenCode standards",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"author": "Melt Studio",
|
|
48
48
|
"license": "UNLICENSED",
|
|
49
49
|
"dependencies": {
|
|
50
|
+
"@meltstudio/meltctl-sdk": "*",
|
|
50
51
|
"@commander-js/extra-typings": "^12.1.0",
|
|
51
52
|
"@inquirer/prompts": "^8.2.1",
|
|
52
53
|
"chalk": "^5.4.1",
|
|
@@ -60,7 +61,7 @@
|
|
|
60
61
|
"@typescript-eslint/eslint-plugin": "^8.19.0",
|
|
61
62
|
"@typescript-eslint/parser": "^8.19.0",
|
|
62
63
|
"eslint": "^9.17.0",
|
|
63
|
-
"eslint-config-prettier": "^
|
|
64
|
+
"eslint-config-prettier": "^10.1.8",
|
|
64
65
|
"eslint-plugin-prettier": "^5.2.1",
|
|
65
66
|
"prettier": "^3.4.2",
|
|
66
67
|
"tsx": "^4.19.5",
|