@mearl/setup 3.0.0 → 3.0.2

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.
@@ -1,6 +1,6 @@
1
1
  import { type CommandRunner } from '@mearl/daemon-core';
2
2
  import { readTrackedSkillSources, type SourceOptions, type SkillSourceScope, type TrackedSkillSource } from './skillSourceReceipts.js';
3
- export { isPublicSkillSource, matchesTrackedSkillSource, readTrackedSkillSources } from './skillSourceReceipts.js';
3
+ export { isPublicSkillSource, matchesTrackedSkillSource, readTrackedSkillSources, } from './skillSourceReceipts.js';
4
4
  export type { SkillSourceScope, TrackedSkillSource } from './skillSourceReceipts.js';
5
5
  /** Matches the public Skills folder hash without writing to the installed Skill. */
6
6
  export declare function hashSkillDirectory(directory: string, ignoreRuntimeFiles?: boolean): Promise<string>;
@@ -6,12 +6,15 @@ import { homedir, tmpdir } from 'node:os';
6
6
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
7
7
  import { runCommand } from '@mearl/daemon-core';
8
8
  import { satisfies, valid } from 'semver';
9
- import { DISABLED_SKILL_MANIFEST, getSkillEnabled, findPluginDirectoryEntry, findPluginRegistration, listPluginNames, OFFICIAL_PLUGIN_MANAGER, pluginRegistrationNeedsRefresh, readInstalledSkillMetadata } from '@mearl/client/plugin';
9
+ import { DISABLED_SKILL_MANIFEST, getSkillEnabled, findPluginDirectoryEntry, findPluginRegistration, listPluginNames, OFFICIAL_PLUGIN_MANAGER, pluginRegistrationNeedsRefresh, readInstalledSkillMetadata, } from '@mearl/client/plugin';
10
10
  import { existsSync } from 'node:fs';
11
- import { gitSource, isPublicSkillSource, matchesTrackedSkillSource, readTrackedSkillSources } from './skillSourceReceipts.js';
12
- export { isPublicSkillSource, matchesTrackedSkillSource, readTrackedSkillSources } from './skillSourceReceipts.js';
11
+ import { gitSource, isPublicSkillSource, matchesTrackedSkillSource, readTrackedSkillSources, } from './skillSourceReceipts.js';
12
+ export { isPublicSkillSource, matchesTrackedSkillSource, readTrackedSkillSources, } from './skillSourceReceipts.js';
13
13
  function skillName(text) {
14
- return text.match(/^---\r?\n([\s\S]*?)\r?\n---/)?.[1].match(/^name:\s*["']?([^"'\r\n]+?)["']?\s*$/m)?.[1]?.trim();
14
+ return text
15
+ .match(/^---\r?\n([\s\S]*?)\r?\n---/)?.[1]
16
+ .match(/^name:\s*["']?([^"'\r\n]+?)["']?\s*$/m)?.[1]
17
+ ?.trim();
15
18
  }
16
19
  async function findSkillDirectory(root, name, skillPath) {
17
20
  if (skillPath) {
@@ -47,7 +50,8 @@ export async function hashSkillDirectory(directory, ignoreRuntimeFiles = false)
47
50
  let total = 0;
48
51
  const visit = async (current) => {
49
52
  for (const entry of await readdir(current, { withFileTypes: true })) {
50
- if (['.git', 'node_modules'].includes(entry.name) || (ignoreRuntimeFiles && ['__pycache__', '.DS_Store'].includes(entry.name)))
53
+ if (['.git', 'node_modules'].includes(entry.name) ||
54
+ (ignoreRuntimeFiles && ['__pycache__', '.DS_Store'].includes(entry.name)))
51
55
  continue;
52
56
  const file = join(current, entry.name);
53
57
  if (entry.isDirectory())
@@ -57,7 +61,13 @@ export async function hashSkillDirectory(directory, ignoreRuntimeFiles = false)
57
61
  total += info.size;
58
62
  if (total > 64 * 1024 * 1024 || files.length >= 10_000)
59
63
  throw new Error('Skill source exceeds the comparison limit');
60
- files.push({ path: relative(directory, file).split(sep).join('/').replace(ignoreRuntimeFiles ? /^SKILL\.md\.mearl-disabled$/ : /$^/, 'SKILL.md'), bytes: await readFile(file) });
64
+ files.push({
65
+ path: relative(directory, file)
66
+ .split(sep)
67
+ .join('/')
68
+ .replace(ignoreRuntimeFiles ? /^SKILL\.md\.mearl-disabled$/ : /$^/, 'SKILL.md'),
69
+ bytes: await readFile(file),
70
+ });
61
71
  }
62
72
  }
63
73
  };
@@ -71,7 +81,10 @@ export async function hashSkillDirectory(directory, ignoreRuntimeFiles = false)
71
81
  }
72
82
  /** Checks source content in a temporary checkout; never invokes the mutating Skills `check` alias. */
73
83
  export async function checkTrackedSkillUpdates(options = {}) {
74
- const sources = [...readTrackedSkillSources('global', undefined, options), ...(options.cwd ? readTrackedSkillSources('project', options.cwd, options) : [])];
84
+ const sources = [
85
+ ...readTrackedSkillSources('global', undefined, options),
86
+ ...(options.cwd ? readTrackedSkillSources('project', options.cwd, options) : []),
87
+ ];
75
88
  if (sources.some(source => !isPublicSkillSource(source)))
76
89
  throw new Error('Installed Skills require an external manager. Enable its preset.');
77
90
  if (sources.length > 500)
@@ -88,12 +101,27 @@ export async function checkTrackedSkillUpdates(options = {}) {
88
101
  let checkout = checkouts.get(key);
89
102
  if (!checkout) {
90
103
  const target = join(temporary, String(checkouts.size));
91
- checkout = local ? Promise.resolve(local) : (async () => {
92
- const result = await runner('git', ['clone', '--depth', '1', '--filter=blob:none', ...(location.ref ? ['--branch', location.ref] : []), '--', location.repository, target], { capture: true, env: { ...(options.env ?? process.env), GIT_TERMINAL_PROMPT: '0' }, timeoutMs: 120_000 });
93
- if (result.code !== 0)
94
- throw new Error(`Unable to inspect Skill source: ${source.name}`);
95
- return target;
96
- })();
104
+ checkout = local
105
+ ? Promise.resolve(local)
106
+ : (async () => {
107
+ const result = await runner('git', [
108
+ 'clone',
109
+ '--depth',
110
+ '1',
111
+ '--filter=blob:none',
112
+ ...(location.ref ? ['--branch', location.ref] : []),
113
+ '--',
114
+ location.repository,
115
+ target,
116
+ ], {
117
+ capture: true,
118
+ env: { ...(options.env ?? process.env), GIT_TERMINAL_PROMPT: '0' },
119
+ timeoutMs: 120_000,
120
+ });
121
+ if (result.code !== 0)
122
+ throw new Error(`Unable to inspect Skill source: ${source.name}`);
123
+ return target;
124
+ })();
97
125
  checkouts.set(key, checkout);
98
126
  }
99
127
  const root = await realpath(await checkout);
@@ -107,10 +135,12 @@ export async function checkTrackedSkillUpdates(options = {}) {
107
135
  changed = result.stdout.trim() !== source.expectedHash;
108
136
  }
109
137
  else if (source.expectedHash && source.hashKind === 'folder')
110
- changed = await hashSkillDirectory(directory) !== source.expectedHash;
138
+ changed = (await hashSkillDirectory(directory)) !== source.expectedHash;
111
139
  else {
112
- const installed = join(source.scope === 'global' ? options.homeDirectory ?? homedir() : options.cwd, '.agents', 'skills', source.name);
113
- changed = await hashSkillDirectory(directory, true) !== await hashSkillDirectory(installed, true);
140
+ const installed = join(source.scope === 'global' ? (options.homeDirectory ?? homedir()) : options.cwd, '.agents', 'skills', source.name);
141
+ changed =
142
+ (await hashSkillDirectory(directory, true)) !==
143
+ (await hashSkillDirectory(installed, true));
114
144
  }
115
145
  if (changed)
116
146
  updates.push({ name: source.name, source: source.source, scope: source.scope });
@@ -128,7 +158,10 @@ export function readLinkedSkillSource(directory, name) {
128
158
  return undefined;
129
159
  const actual = realpathSync(directory);
130
160
  const git = (...args) => execFileSync('git', ['--no-optional-locks', '-c', 'core.fsmonitor=false', '-C', actual, ...args], {
131
- encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], timeout: 2_000, maxBuffer: 16_384,
161
+ encoding: 'utf8',
162
+ stdio: ['ignore', 'pipe', 'ignore'],
163
+ timeout: 2_000,
164
+ maxBuffer: 16_384,
132
165
  }).trim();
133
166
  const root = git('rev-parse', '--show-toplevel');
134
167
  const folder = relative(root, actual);
@@ -169,29 +202,44 @@ function canonicalPath(path) {
169
202
  return parent === absolute ? absolute : join(canonicalPath(parent), basename(absolute));
170
203
  }
171
204
  }
172
- function hasOnlySetupRegistrations(directory) {
205
+ function hasOnlySetupRegistrations(directory, allowUnregistered = false) {
173
206
  const contains = (root, entry) => {
174
207
  const path = relative(root, entry);
175
208
  return path !== '' && path !== '..' && !path.startsWith('..' + sep) && !isAbsolute(path);
176
209
  };
177
- const registrations = listPluginNames().flatMap(name => findPluginRegistration(name) ?? []).filter(registration => contains(resolve(directory), resolve(registration.entry)) || contains(canonicalPath(directory), canonicalPath(registration.entry)));
178
- return registrations.length > 0 && registrations.every(registration => registration.managedBy === OFFICIAL_PLUGIN_MANAGER);
210
+ const registrations = listPluginNames()
211
+ .flatMap(name => findPluginRegistration(name) ?? [])
212
+ .filter(registration => contains(resolve(directory), resolve(registration.entry)) ||
213
+ contains(canonicalPath(directory), canonicalPath(registration.entry)));
214
+ return ((allowUnregistered || registrations.length > 0) &&
215
+ registrations.every(registration => registration.managedBy === OFFICIAL_PLUGIN_MANAGER));
179
216
  }
180
217
  /** CLI and Agent readiness use the same source, manifest and registration evidence. */
181
218
  export function inspectGlobalSkill(source, name, version, options = {}) {
182
219
  if (!source.trim() || !name || name === '.' || name === '..' || /[\\/\0\r\n]/.test(name))
183
220
  throw new Error('Invalid Skill identity');
184
221
  const directory = join(options.homeDirectory ?? homedir(), '.agents', 'skills', name);
185
- if (existsSync(join(directory, 'SKILL.md')) && existsSync(join(directory, DISABLED_SKILL_MANIFEST)))
222
+ if (existsSync(join(directory, 'SKILL.md')) &&
223
+ existsSync(join(directory, DISABLED_SKILL_MANIFEST)))
186
224
  return { state: 'conflict', reason: 'SKILL_MANIFEST_CONFLICT' };
187
- const receipt = (options.readSources ?? readTrackedSkillSources)('global', undefined, { homeDirectory: options.homeDirectory }).find(entry => entry.name === name);
188
- const tracked = receipt
189
- ?? (!/(?:#|\/(?:tree|blob)\/)/.test(source) ? readLinkedSkillSource(directory, name) : undefined);
190
- if (tracked && ((!options.externalManager && !isPublicSkillSource(tracked)) || !matchesTrackedSkillSource(source, tracked, options.normalizeSource))) {
225
+ const receipt = (options.readSources ?? readTrackedSkillSources)('global', undefined, {
226
+ homeDirectory: options.homeDirectory,
227
+ }).find(entry => entry.name === name);
228
+ const tracked = receipt ??
229
+ (!/(?:#|\/(?:tree|blob)\/)/.test(source) ? readLinkedSkillSource(directory, name) : undefined);
230
+ if (tracked &&
231
+ ((!options.externalManager && !isPublicSkillSource(tracked)) ||
232
+ !matchesTrackedSkillSource(source, tracked, options.normalizeSource))) {
191
233
  const metadata = readInstalledSkillMetadata(directory);
192
- if (receipt && (options.externalManager || isPublicSkillSource(receipt)) && metadata?.name === name &&
193
- options.migrateFrom?.some(previous => matchesTrackedSkillSource(previous, receipt, options.normalizeSource)) && hasOnlySetupRegistrations(directory)) {
194
- return { state: 'migration', reason: 'SKILL_SOURCE_MIGRATION_REQUIRED' };
234
+ if (receipt &&
235
+ (options.externalManager || isPublicSkillSource(receipt)) &&
236
+ metadata?.name === name) {
237
+ // A missing ref requires installing the requested ref before the Skill can be ready.
238
+ const missingRef = matchesTrackedSkillSource(source, receipt, options.normalizeSource, 'missing');
239
+ const declaredMigration = options.migrateFrom?.some(previous => matchesTrackedSkillSource(previous, receipt, options.normalizeSource));
240
+ if ((missingRef || declaredMigration) && hasOnlySetupRegistrations(directory, missingRef)) {
241
+ return { state: 'migration', reason: 'SKILL_SOURCE_MIGRATION_REQUIRED' };
242
+ }
195
243
  }
196
244
  return { state: 'conflict', reason: 'SKILL_SOURCE_CONFLICT' };
197
245
  }
@@ -202,7 +250,8 @@ export function inspectGlobalSkill(source, name, version, options = {}) {
202
250
  return { state: 'conflict', reason: 'SKILL_SOURCE_UNKNOWN' };
203
251
  if (metadata.name !== name)
204
252
  return { state: 'conflict', reason: 'SKILL_MANIFEST_IDENTITY' };
205
- if (version && (!metadata.version || !valid(metadata.version) || !satisfies(metadata.version, version)))
253
+ if (version &&
254
+ (!metadata.version || !valid(metadata.version) || !satisfies(metadata.version, version)))
206
255
  return { state: 'version', reason: 'SKILL_VERSION_REQUIRED' };
207
256
  const entry = findPluginDirectoryEntry(directory);
208
257
  const names = listPluginNames().filter(name => {
@@ -212,10 +261,13 @@ export function inspectGlobalSkill(source, name, version, options = {}) {
212
261
  const managedNames = names.filter(name => findPluginRegistration(name)?.managedBy === OFFICIAL_PLUGIN_MANAGER);
213
262
  // User aliases may share a managed Skill without participating in its readiness or cleanup.
214
263
  const requiredNames = managedNames.length ? managedNames : names;
215
- if (entry && (requiredNames.length !== 1 || !requiredNames.some(name => {
216
- const registration = findPluginRegistration(name);
217
- return resolve(registration.entry) === resolve(entry) && !pluginRegistrationNeedsRefresh(registration, true);
218
- })))
264
+ if (entry &&
265
+ (requiredNames.length !== 1 ||
266
+ !requiredNames.some(name => {
267
+ const registration = findPluginRegistration(name);
268
+ return (resolve(registration.entry) === resolve(entry) &&
269
+ !pluginRegistrationNeedsRefresh(registration, true));
270
+ })))
219
271
  return { state: 'registration', reason: 'SKILL_PLUGIN_REGISTRATION_REQUIRED' };
220
272
  if (!entry && names.length)
221
273
  return { state: 'registration', reason: 'SKILL_PLUGIN_REGISTRATION_REQUIRED' };
package/dist/skills.d.ts CHANGED
@@ -2,7 +2,7 @@ import { inspectGlobalSkill } from './skillSources.js';
2
2
  import type { PluginCatalogSelection } from '@mearl/client/plugin';
3
3
  import type { ResolvedComponent } from '@mearl/preset';
4
4
  import { type CommandRunner, type CommandResult, type RunCommandOptions } from '@mearl/daemon-core';
5
- export declare const SKILLS_CLI_PACKAGE = "skills@1.5.0";
5
+ export declare const SKILLS_CLI_PACKAGE = "skills";
6
6
  export declare const MEARL_SKILL_SOURCE: string;
7
7
  export interface ResolveSkillsOptions {
8
8
  env?: NodeJS.ProcessEnv;
package/dist/skills.js CHANGED
@@ -5,7 +5,7 @@ import { NodeCapabilityRegistry } from '@mearl/daemon-core/capabilities';
5
5
  import { inspectGlobalSkill, readTrackedSkillSources } from './skillSources.js';
6
6
  import { PresetInstallationStore } from './presetStore.js';
7
7
  import { findExecutable, isExecutable, npmExecEnvironment, prependCommandPath, prependNodePath, runCommand, } from '@mearl/daemon-core';
8
- export const SKILLS_CLI_PACKAGE = 'skills@1.5.0';
8
+ export const SKILLS_CLI_PACKAGE = 'skills';
9
9
  export const MEARL_SKILL_SOURCE = SETUP_VERSION.includes('-beta.')
10
10
  ? `https://github.com/mearlhq/mearl/tree/v${SETUP_VERSION}`
11
11
  : 'https://github.com/mearlhq/mearl';
@@ -40,7 +40,7 @@ export function resolveSkillsInvocation(options = {}) {
40
40
  return null;
41
41
  return {
42
42
  command: npx,
43
- argsPrefix: ['-y', SKILLS_CLI_PACKAGE],
43
+ argsPrefix: ['-y', `--package=${SKILLS_CLI_PACKAGE}`, '--', 'skills'],
44
44
  env: npmExecEnvironment(prependNodePath(prependCommandPath(npx, env), processExecPath)),
45
45
  };
46
46
  }
@@ -49,37 +49,81 @@ export async function captureSkillsCli(options = {}) {
49
49
  const env = options.env ?? process.env;
50
50
  const runner = options.runCommand ?? runCommand;
51
51
  const directory = env.MEARL_CAPABILITY_DIR || path.join(homedir(), '.mearl', 'capabilities');
52
- const current = await new PresetInstallationStore({ directory }).current({ verifyResources: false });
52
+ const current = await new PresetInstallationStore({ directory }).current({
53
+ verifyResources: false,
54
+ });
53
55
  const registry = new NodeCapabilityRegistry({ env: Object.freeze({ ...env }), runCommand: runner }, directory, { hooks: ['skills.manager'] });
54
56
  await registry.refresh();
55
- if (current.activation?.revision !== registry.revision || current.activation?.installationRevision !== registry.installationRevision)
57
+ if (current.activation?.revision !== registry.revision ||
58
+ current.activation?.installationRevision !== registry.installationRevision)
56
59
  throw new Error('SKILL_MANAGER_CHANGED');
57
60
  const readSources = (scope, cwd) => readTrackedSkillSources(scope, cwd, { env });
58
- const selection = current.rawHash ? { path: path.resolve(directory, 'active-node.json'), sha256: current.rawHash } : undefined;
61
+ const selection = current.rawHash
62
+ ? { path: path.resolve(directory, 'active-node.json'), sha256: current.rawHash }
63
+ : undefined;
59
64
  const managedSkills = Object.fromEntries(Object.entries(current.preset?.skills ?? {}).filter(([, entry]) => entry.enabled !== false));
60
65
  const backend = registry.get('skills.manager')?.();
61
66
  if (backend !== undefined) {
62
67
  if (backend?.readSources !== undefined && typeof backend.readSources !== 'function')
63
68
  throw new Error('Invalid Skill source reader');
64
- if (!backend || typeof backend.id !== 'string' || !/^[a-z][a-z0-9-]{0,63}$/.test(backend.id) || typeof backend.cli !== 'function')
69
+ if (!backend ||
70
+ typeof backend.id !== 'string' ||
71
+ !/^[a-z][a-z0-9-]{0,63}$/.test(backend.id) ||
72
+ typeof backend.cli !== 'function')
65
73
  throw new Error('The selected Skill manager requires a preset update for CLI operations');
66
- return { id: backend.id, managedSkills, selection, inspectGlobal: (source, name, version, inspection) => inspectGlobalSkill(source, name, version, { migrateFrom: inspection?.migrateFrom, externalManager: true, normalizeSource: backend.normalizeSource, readSources: backend.readSources ?? readSources }), run: async (args, settings) => {
74
+ return {
75
+ id: backend.id,
76
+ managedSkills,
77
+ selection,
78
+ inspectGlobal: (source, name, version, inspection) => inspectGlobalSkill(source, name, version, {
79
+ migrateFrom: inspection?.migrateFrom,
80
+ externalManager: true,
81
+ normalizeSource: backend.normalizeSource,
82
+ readSources: backend.readSources ?? readSources,
83
+ }),
84
+ run: async (args, settings) => {
67
85
  const result = await backend.cli([...args], settings);
68
- if (!result || !Number.isInteger(result.code) || typeof result.stdout !== 'string' || typeof result.stderr !== 'string')
86
+ if (!result ||
87
+ !Number.isInteger(result.code) ||
88
+ typeof result.stdout !== 'string' ||
89
+ typeof result.stderr !== 'string')
69
90
  throw new Error('Invalid Skill manager CLI result');
70
91
  return result;
71
- } };
92
+ },
93
+ };
72
94
  }
73
95
  const invocation = resolveSkillsInvocation(options);
74
96
  if (!invocation)
75
97
  return undefined;
76
- return { id: 'skills', managedSkills, selection, inspectGlobal: (source, name, version, inspection) => inspectGlobalSkill(source, name, version, { migrateFrom: inspection?.migrateFrom, readSources }), run: (args, settings) => runner(invocation.command, [...invocation.argsPrefix, ...args], { ...settings, env: invocation.env }) };
98
+ return {
99
+ id: 'skills',
100
+ managedSkills,
101
+ selection,
102
+ inspectGlobal: (source, name, version, inspection) => inspectGlobalSkill(source, name, version, {
103
+ migrateFrom: inspection?.migrateFrom,
104
+ readSources,
105
+ }),
106
+ run: (args, settings) => runner(invocation.command, [...invocation.argsPrefix, ...args], {
107
+ ...settings,
108
+ env: invocation.env,
109
+ }),
110
+ };
77
111
  }
78
112
  export function parseInstalledSkills(output) {
79
113
  const value = JSON.parse(stripAnsi(output).trim());
80
- if (!Array.isArray(value) || value.some(item => !item || typeof item.name !== 'string' || typeof item.path !== 'string' || !['global', 'project'].includes(item.scope)))
114
+ if (!Array.isArray(value))
81
115
  throw new Error('Skills returned an invalid skill list');
82
- return value;
116
+ const installed = [];
117
+ for (const item of value) {
118
+ if (!item || typeof item.name !== 'string' || !['global', 'project'].includes(item.scope))
119
+ throw new Error('Skills returned an invalid skill list');
120
+ if (item.status === 'missing' && item.path === null)
121
+ continue;
122
+ if (typeof item.path !== 'string')
123
+ throw new Error('Skills returned an invalid skill list');
124
+ installed.push(item);
125
+ }
126
+ return installed;
83
127
  }
84
128
  export function parseGlobalMearlSkillPaths(output) {
85
129
  const parsed = parseInstalledSkills(output);
@@ -201,12 +245,14 @@ export async function runGlobalMearlSkillOperation(operation, options = {}) {
201
245
  ${result.stderr}`).trim();
202
246
  if (detail)
203
247
  writeLine(detail);
204
- if (/Failed to (?:update|remove)\s+[1-9]\d*\s+skills?/i.test(detail) || (operation === 'update' && !/\bInstalled [1-9]\d* skills?\b/.test(detail))) {
248
+ if (/Failed to (?:update|remove)\s+[1-9]\d*\s+skills?/i.test(detail) ||
249
+ (operation === 'update' && !/\bInstalled [1-9]\d* skills?\b/.test(detail))) {
205
250
  writeLine(`Skill: ${operation} failed.`);
206
251
  return false;
207
252
  }
208
253
  const remainingPaths = await listMearlPaths();
209
- if (!remainingPaths || (operation === 'uninstall' ? remainingPaths.length !== 0 : remainingPaths.length === 0)) {
254
+ if (!remainingPaths ||
255
+ (operation === 'uninstall' ? remainingPaths.length !== 0 : remainingPaths.length === 0)) {
210
256
  writeLine(`Skill: ${operation} did not reach the expected installation state.`);
211
257
  return false;
212
258
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mearl/setup",
3
- "version": "3.0.0",
3
+ "version": "3.0.2",
4
4
  "description": "One-shot environment setup and configuration for Mearl",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -79,11 +79,11 @@
79
79
  "ws": "^8.18.3",
80
80
  "semver": "^7.8.5",
81
81
  "adm-zip": "^0.6.1",
82
- "@mearl/client": "3.0.0",
83
- "@mearl/provider": "3.0.0",
84
- "@mearl/daemon-core": "3.0.0",
85
- "@mearl/preset": "3.0.0",
86
- "@mearl/browser-core": "3.0.0"
82
+ "@mearl/provider": "3.0.2",
83
+ "@mearl/preset": "3.0.2",
84
+ "@mearl/browser-core": "3.0.2",
85
+ "@mearl/daemon-core": "3.0.2",
86
+ "@mearl/client": "3.0.2"
87
87
  },
88
88
  "devDependencies": {
89
89
  "@types/node": "^24.9.1",