@nimblebrain/mpak 0.1.0 → 0.3.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/README.md +50 -383
- package/dist/index.d.ts +0 -2
- package/dist/index.js +2117 -4
- package/dist/index.js.map +1 -1
- package/package.json +26 -23
- package/.claude/settings.local.json +0 -19
- package/.env.example +0 -13
- package/.github/workflows/ci.yml +0 -27
- package/CLAUDE.md +0 -283
- package/LICENSE +0 -201
- package/dist/commands/config.d.ts +0 -31
- package/dist/commands/config.d.ts.map +0 -1
- package/dist/commands/config.js +0 -129
- package/dist/commands/config.js.map +0 -1
- package/dist/commands/packages/pull.d.ts +0 -11
- package/dist/commands/packages/pull.d.ts.map +0 -1
- package/dist/commands/packages/pull.js +0 -72
- package/dist/commands/packages/pull.js.map +0 -1
- package/dist/commands/packages/run.d.ts +0 -47
- package/dist/commands/packages/run.d.ts.map +0 -1
- package/dist/commands/packages/run.js +0 -419
- package/dist/commands/packages/run.js.map +0 -1
- package/dist/commands/packages/search.d.ts +0 -12
- package/dist/commands/packages/search.d.ts.map +0 -1
- package/dist/commands/packages/search.js +0 -63
- package/dist/commands/packages/search.js.map +0 -1
- package/dist/commands/packages/show.d.ts +0 -8
- package/dist/commands/packages/show.d.ts.map +0 -1
- package/dist/commands/packages/show.js +0 -109
- package/dist/commands/packages/show.js.map +0 -1
- package/dist/commands/search.d.ts +0 -12
- package/dist/commands/search.d.ts.map +0 -1
- package/dist/commands/search.js +0 -144
- package/dist/commands/search.js.map +0 -1
- package/dist/commands/skills/index.d.ts +0 -8
- package/dist/commands/skills/index.d.ts.map +0 -1
- package/dist/commands/skills/index.js +0 -8
- package/dist/commands/skills/index.js.map +0 -1
- package/dist/commands/skills/install.d.ts +0 -9
- package/dist/commands/skills/install.d.ts.map +0 -1
- package/dist/commands/skills/install.js +0 -110
- package/dist/commands/skills/install.js.map +0 -1
- package/dist/commands/skills/list.d.ts +0 -8
- package/dist/commands/skills/list.d.ts.map +0 -1
- package/dist/commands/skills/list.js +0 -89
- package/dist/commands/skills/list.js.map +0 -1
- package/dist/commands/skills/pack.d.ts +0 -22
- package/dist/commands/skills/pack.d.ts.map +0 -1
- package/dist/commands/skills/pack.js +0 -116
- package/dist/commands/skills/pack.js.map +0 -1
- package/dist/commands/skills/pull.d.ts +0 -9
- package/dist/commands/skills/pull.d.ts.map +0 -1
- package/dist/commands/skills/pull.js +0 -68
- package/dist/commands/skills/pull.js.map +0 -1
- package/dist/commands/skills/search.d.ts +0 -14
- package/dist/commands/skills/search.d.ts.map +0 -1
- package/dist/commands/skills/search.js +0 -53
- package/dist/commands/skills/search.js.map +0 -1
- package/dist/commands/skills/show.d.ts +0 -8
- package/dist/commands/skills/show.d.ts.map +0 -1
- package/dist/commands/skills/show.js +0 -64
- package/dist/commands/skills/show.js.map +0 -1
- package/dist/commands/skills/validate.d.ts +0 -25
- package/dist/commands/skills/validate.d.ts.map +0 -1
- package/dist/commands/skills/validate.js +0 -191
- package/dist/commands/skills/validate.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/lib/api/registry-client.d.ts +0 -63
- package/dist/lib/api/registry-client.d.ts.map +0 -1
- package/dist/lib/api/registry-client.js +0 -167
- package/dist/lib/api/registry-client.js.map +0 -1
- package/dist/lib/api/skills-client.d.ts +0 -30
- package/dist/lib/api/skills-client.d.ts.map +0 -1
- package/dist/lib/api/skills-client.js +0 -110
- package/dist/lib/api/skills-client.js.map +0 -1
- package/dist/program.d.ts +0 -12
- package/dist/program.d.ts.map +0 -1
- package/dist/program.js +0 -186
- package/dist/program.js.map +0 -1
- package/dist/schemas/generated/api-responses.d.ts +0 -541
- package/dist/schemas/generated/api-responses.d.ts.map +0 -1
- package/dist/schemas/generated/api-responses.js +0 -313
- package/dist/schemas/generated/api-responses.js.map +0 -1
- package/dist/schemas/generated/auth.d.ts +0 -18
- package/dist/schemas/generated/auth.d.ts.map +0 -1
- package/dist/schemas/generated/auth.js +0 -18
- package/dist/schemas/generated/auth.js.map +0 -1
- package/dist/schemas/generated/index.d.ts +0 -5
- package/dist/schemas/generated/index.d.ts.map +0 -1
- package/dist/schemas/generated/index.js +0 -6
- package/dist/schemas/generated/index.js.map +0 -1
- package/dist/schemas/generated/package.d.ts +0 -43
- package/dist/schemas/generated/package.d.ts.map +0 -1
- package/dist/schemas/generated/package.js +0 -20
- package/dist/schemas/generated/package.js.map +0 -1
- package/dist/schemas/generated/skill.d.ts +0 -381
- package/dist/schemas/generated/skill.d.ts.map +0 -1
- package/dist/schemas/generated/skill.js +0 -216
- package/dist/schemas/generated/skill.js.map +0 -1
- package/dist/utils/config-manager.d.ts +0 -66
- package/dist/utils/config-manager.d.ts.map +0 -1
- package/dist/utils/config-manager.js +0 -193
- package/dist/utils/config-manager.js.map +0 -1
- package/dist/utils/errors.d.ts +0 -12
- package/dist/utils/errors.d.ts.map +0 -1
- package/dist/utils/errors.js +0 -27
- package/dist/utils/errors.js.map +0 -1
- package/dist/utils/version.d.ts +0 -5
- package/dist/utils/version.d.ts.map +0 -1
- package/dist/utils/version.js +0 -19
- package/dist/utils/version.js.map +0 -1
- package/eslint.config.js +0 -63
- package/src/commands/config.ts +0 -162
- package/src/commands/packages/pull.ts +0 -96
- package/src/commands/packages/run.test.ts +0 -261
- package/src/commands/packages/run.ts +0 -536
- package/src/commands/packages/search.ts +0 -83
- package/src/commands/packages/show.ts +0 -128
- package/src/commands/search.ts +0 -191
- package/src/commands/skills/index.ts +0 -7
- package/src/commands/skills/install.ts +0 -129
- package/src/commands/skills/list.ts +0 -116
- package/src/commands/skills/pack.test.ts +0 -260
- package/src/commands/skills/pack.ts +0 -145
- package/src/commands/skills/pull.ts +0 -88
- package/src/commands/skills/search.ts +0 -73
- package/src/commands/skills/show.ts +0 -72
- package/src/commands/skills/validate.test.ts +0 -466
- package/src/commands/skills/validate.ts +0 -227
- package/src/index.ts +0 -11
- package/src/lib/api/registry-client.ts +0 -223
- package/src/lib/api/schema.d.ts +0 -520
- package/src/lib/api/skills-client.ts +0 -148
- package/src/program.test.ts +0 -22
- package/src/program.ts +0 -226
- package/src/schemas/config.v1.schema.json +0 -37
- package/src/schemas/generated/api-responses.ts +0 -386
- package/src/schemas/generated/auth.ts +0 -21
- package/src/schemas/generated/index.ts +0 -5
- package/src/schemas/generated/package.ts +0 -29
- package/src/schemas/generated/skill.ts +0 -271
- package/src/utils/config-manager.test.ts +0 -330
- package/src/utils/config-manager.ts +0 -272
- package/src/utils/errors.test.ts +0 -25
- package/src/utils/errors.ts +0 -33
- package/src/utils/version.test.ts +0 -16
- package/src/utils/version.ts +0 -18
- package/test/integration/registry-client.test.ts +0 -180
- package/tsconfig.check.json +0 -9
- package/tsconfig.json +0 -25
- package/vitest.config.ts +0 -14
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { homedir } from 'os';
|
|
3
|
-
import { join } from 'path';
|
|
4
|
-
import { parsePackageSpec, getCacheDir, resolveArgs, substituteUserConfig, substituteEnvVars, getLocalCacheDir, localBundleNeedsExtract } from './run.js';
|
|
5
|
-
|
|
6
|
-
describe('parsePackageSpec', () => {
|
|
7
|
-
describe('scoped packages', () => {
|
|
8
|
-
it('parses @scope/name without version', () => {
|
|
9
|
-
expect(parsePackageSpec('@scope/name')).toEqual({
|
|
10
|
-
name: '@scope/name',
|
|
11
|
-
});
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it('parses @scope/name@1.0.0', () => {
|
|
15
|
-
expect(parsePackageSpec('@scope/name@1.0.0')).toEqual({
|
|
16
|
-
name: '@scope/name',
|
|
17
|
-
version: '1.0.0',
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('parses prerelease versions @scope/name@1.0.0-beta.1', () => {
|
|
22
|
-
expect(parsePackageSpec('@scope/name@1.0.0-beta.1')).toEqual({
|
|
23
|
-
name: '@scope/name',
|
|
24
|
-
version: '1.0.0-beta.1',
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('parses version with build metadata @scope/name@1.0.0+build.123', () => {
|
|
29
|
-
expect(parsePackageSpec('@scope/name@1.0.0+build.123')).toEqual({
|
|
30
|
-
name: '@scope/name',
|
|
31
|
-
version: '1.0.0+build.123',
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
describe('edge cases', () => {
|
|
37
|
-
it('handles package name with multiple slashes @org/sub/name', () => {
|
|
38
|
-
// This is technically invalid per npm spec, but we should handle gracefully
|
|
39
|
-
const result = parsePackageSpec('@org/sub/name');
|
|
40
|
-
expect(result.name).toBe('@org/sub/name');
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('handles unscoped package name', () => {
|
|
44
|
-
expect(parsePackageSpec('simple-name')).toEqual({
|
|
45
|
-
name: 'simple-name',
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('treats unscoped@version as invalid (mpak requires scoped packages)', () => {
|
|
50
|
-
// mpak only supports scoped packages (@scope/name)
|
|
51
|
-
// An unscoped name with @ is treated as the full name, not name@version
|
|
52
|
-
expect(parsePackageSpec('unscoped@1.0.0')).toEqual({
|
|
53
|
-
name: 'unscoped@1.0.0',
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('handles empty string', () => {
|
|
58
|
-
expect(parsePackageSpec('')).toEqual({ name: '' });
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('handles @ only', () => {
|
|
62
|
-
expect(parsePackageSpec('@')).toEqual({ name: '@' });
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
describe('getCacheDir', () => {
|
|
68
|
-
const expectedBase = join(homedir(), '.mpak', 'cache');
|
|
69
|
-
|
|
70
|
-
it('converts @scope/name to scope-name', () => {
|
|
71
|
-
expect(getCacheDir('@nimblebraininc/echo')).toBe(
|
|
72
|
-
join(expectedBase, 'nimblebraininc-echo')
|
|
73
|
-
);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('handles simple scoped names', () => {
|
|
77
|
-
expect(getCacheDir('@foo/bar')).toBe(join(expectedBase, 'foo-bar'));
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it('handles unscoped names', () => {
|
|
81
|
-
expect(getCacheDir('simple')).toBe(join(expectedBase, 'simple'));
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
describe('resolveArgs', () => {
|
|
86
|
-
const cacheDir = '/Users/test/.mpak/cache/scope-name';
|
|
87
|
-
|
|
88
|
-
it('resolves ${__dirname} placeholder', () => {
|
|
89
|
-
expect(resolveArgs(['${__dirname}/dist/index.js'], cacheDir)).toEqual([
|
|
90
|
-
`${cacheDir}/dist/index.js`,
|
|
91
|
-
]);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it('resolves multiple ${__dirname} in single arg', () => {
|
|
95
|
-
expect(
|
|
96
|
-
resolveArgs(['--config=${__dirname}/config.json'], cacheDir)
|
|
97
|
-
).toEqual([`--config=${cacheDir}/config.json`]);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('resolves ${__dirname} in multiple args', () => {
|
|
101
|
-
expect(
|
|
102
|
-
resolveArgs(
|
|
103
|
-
['${__dirname}/index.js', '--config', '${__dirname}/config.json'],
|
|
104
|
-
cacheDir
|
|
105
|
-
)
|
|
106
|
-
).toEqual([
|
|
107
|
-
`${cacheDir}/index.js`,
|
|
108
|
-
'--config',
|
|
109
|
-
`${cacheDir}/config.json`,
|
|
110
|
-
]);
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it('leaves args without placeholders unchanged', () => {
|
|
114
|
-
expect(resolveArgs(['-m', 'mcp_echo.server'], cacheDir)).toEqual([
|
|
115
|
-
'-m',
|
|
116
|
-
'mcp_echo.server',
|
|
117
|
-
]);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it('handles empty args array', () => {
|
|
121
|
-
expect(resolveArgs([], cacheDir)).toEqual([]);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it('handles Windows-style paths in cacheDir', () => {
|
|
125
|
-
const winPath = 'C:\\Users\\test\\.mpak\\cache\\scope-name';
|
|
126
|
-
expect(resolveArgs(['${__dirname}\\dist\\index.js'], winPath)).toEqual([
|
|
127
|
-
`${winPath}\\dist\\index.js`,
|
|
128
|
-
]);
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
describe('substituteUserConfig', () => {
|
|
133
|
-
it('substitutes single user_config variable', () => {
|
|
134
|
-
expect(
|
|
135
|
-
substituteUserConfig('${user_config.api_key}', { api_key: 'secret123' })
|
|
136
|
-
).toBe('secret123');
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it('substitutes multiple user_config variables', () => {
|
|
140
|
-
expect(
|
|
141
|
-
substituteUserConfig('key=${user_config.key}&secret=${user_config.secret}', {
|
|
142
|
-
key: 'mykey',
|
|
143
|
-
secret: 'mysecret',
|
|
144
|
-
})
|
|
145
|
-
).toBe('key=mykey&secret=mysecret');
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it('leaves unmatched variables unchanged', () => {
|
|
149
|
-
expect(
|
|
150
|
-
substituteUserConfig('${user_config.missing}', { other: 'value' })
|
|
151
|
-
).toBe('${user_config.missing}');
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
it('handles mixed matched and unmatched variables', () => {
|
|
155
|
-
expect(
|
|
156
|
-
substituteUserConfig('${user_config.found}-${user_config.missing}', {
|
|
157
|
-
found: 'yes',
|
|
158
|
-
})
|
|
159
|
-
).toBe('yes-${user_config.missing}');
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it('handles empty config values', () => {
|
|
163
|
-
expect(
|
|
164
|
-
substituteUserConfig('${user_config.empty}', { empty: '' })
|
|
165
|
-
).toBe('');
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
it('handles values with special characters', () => {
|
|
169
|
-
expect(
|
|
170
|
-
substituteUserConfig('${user_config.key}', { key: 'abc$def{ghi}' })
|
|
171
|
-
).toBe('abc$def{ghi}');
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
it('leaves non-user_config placeholders unchanged', () => {
|
|
175
|
-
expect(
|
|
176
|
-
substituteUserConfig('${__dirname}/path', { dirname: '/cache' })
|
|
177
|
-
).toBe('${__dirname}/path');
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
describe('substituteEnvVars', () => {
|
|
182
|
-
it('substitutes user_config in all env vars', () => {
|
|
183
|
-
const env = {
|
|
184
|
-
API_KEY: '${user_config.api_key}',
|
|
185
|
-
DEBUG: 'true',
|
|
186
|
-
TOKEN: '${user_config.token}',
|
|
187
|
-
};
|
|
188
|
-
const values = { api_key: 'key123', token: 'tok456' };
|
|
189
|
-
|
|
190
|
-
expect(substituteEnvVars(env, values)).toEqual({
|
|
191
|
-
API_KEY: 'key123',
|
|
192
|
-
DEBUG: 'true',
|
|
193
|
-
TOKEN: 'tok456',
|
|
194
|
-
});
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
it('handles undefined env', () => {
|
|
198
|
-
expect(substituteEnvVars(undefined, { key: 'value' })).toEqual({});
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
it('handles empty env', () => {
|
|
202
|
-
expect(substituteEnvVars({}, { key: 'value' })).toEqual({});
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
it('preserves env vars without placeholders', () => {
|
|
206
|
-
const env = { PATH: '/usr/bin', HOME: '/home/user' };
|
|
207
|
-
expect(substituteEnvVars(env, {})).toEqual(env);
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
it('leaves unsubstituted placeholders as-is', () => {
|
|
211
|
-
const env = {
|
|
212
|
-
API_KEY: '${user_config.api_key}',
|
|
213
|
-
DEBUG: 'true',
|
|
214
|
-
};
|
|
215
|
-
// api_key not provided, so placeholder remains
|
|
216
|
-
// (process.env will override this at merge time)
|
|
217
|
-
expect(substituteEnvVars(env, {})).toEqual({
|
|
218
|
-
API_KEY: '${user_config.api_key}',
|
|
219
|
-
DEBUG: 'true',
|
|
220
|
-
});
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
describe('getLocalCacheDir', () => {
|
|
225
|
-
const expectedBase = join(homedir(), '.mpak', 'cache', '_local');
|
|
226
|
-
|
|
227
|
-
it('returns consistent hash for same path', () => {
|
|
228
|
-
const dir1 = getLocalCacheDir('/path/to/bundle.mcpb');
|
|
229
|
-
const dir2 = getLocalCacheDir('/path/to/bundle.mcpb');
|
|
230
|
-
expect(dir1).toBe(dir2);
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
it('returns different hash for different paths', () => {
|
|
234
|
-
const dir1 = getLocalCacheDir('/path/to/bundle1.mcpb');
|
|
235
|
-
const dir2 = getLocalCacheDir('/path/to/bundle2.mcpb');
|
|
236
|
-
expect(dir1).not.toBe(dir2);
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
it('includes _local in path', () => {
|
|
240
|
-
const dir = getLocalCacheDir('/path/to/bundle.mcpb');
|
|
241
|
-
expect(dir).toContain('_local');
|
|
242
|
-
expect(dir.startsWith(expectedBase)).toBe(true);
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
it('produces a 12-character hash suffix', () => {
|
|
246
|
-
const dir = getLocalCacheDir('/path/to/bundle.mcpb');
|
|
247
|
-
const hashPart = dir.split('/').pop();
|
|
248
|
-
expect(hashPart).toHaveLength(12);
|
|
249
|
-
});
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
describe('localBundleNeedsExtract', () => {
|
|
253
|
-
it('returns true when cache directory does not exist', () => {
|
|
254
|
-
expect(localBundleNeedsExtract('/any/path.mcpb', '/nonexistent/cache')).toBe(true);
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
it('returns true when meta file does not exist in cache dir', () => {
|
|
258
|
-
// Using a directory that exists but has no .mpak-meta.json
|
|
259
|
-
expect(localBundleNeedsExtract('/any/path.mcpb', '/tmp')).toBe(true);
|
|
260
|
-
});
|
|
261
|
-
});
|