monomind 1.15.6 → 1.16.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 (96) hide show
  1. package/.claude/agents/github/repo-architect.md +1 -1
  2. package/.claude/agents/specialists/integration-architect.md +6 -6
  3. package/.claude/commands/hive-mind/hive-mind-init.md +1 -1
  4. package/.claude/commands/hive-mind/hive-mind-memory.md +1 -1
  5. package/.claude/commands/mastermind/brain.md +11 -11
  6. package/.claude/commands/mastermind/master.md +4 -4
  7. package/.claude/commands/mastermind/memory.md +6 -6
  8. package/.claude/commands/memory/README.md +4 -4
  9. package/.claude/commands/truth/start.md +3 -3
  10. package/.claude/helpers/extras-registry.json +2 -2
  11. package/.claude/helpers/skill-registry.json +26 -26
  12. package/.claude/helpers/statusline.cjs +8 -8
  13. package/.claude/skills/agentic-jujutsu/SKILL.md +3 -3
  14. package/.claude/skills/mastermind/_protocol.md +8 -8
  15. package/README.md +6 -6
  16. package/package.json +2 -2
  17. package/packages/@monomind/cli/README.md +6 -6
  18. package/packages/@monomind/cli/dist/src/__tests__/browse-analyzer.test.js +18 -1
  19. package/packages/@monomind/cli/dist/src/commands/agent.js +2 -2
  20. package/packages/@monomind/cli/dist/src/commands/autopilot.js +1 -1
  21. package/packages/@monomind/cli/dist/src/commands/completions.js +2 -21
  22. package/packages/@monomind/cli/dist/src/commands/config.js +1 -1
  23. package/packages/@monomind/cli/dist/src/commands/hive-mind.js +1 -1
  24. package/packages/@monomind/cli/dist/src/commands/hooks-coverage-commands.js +31 -31
  25. package/packages/@monomind/cli/dist/src/commands/hooks-routing-commands.js +1 -1
  26. package/packages/@monomind/cli/dist/src/commands/hooks.js +1 -1
  27. package/packages/@monomind/cli/dist/src/commands/index.d.ts +0 -1
  28. package/packages/@monomind/cli/dist/src/commands/index.js +0 -4
  29. package/packages/@monomind/cli/dist/src/commands/init.js +8 -8
  30. package/packages/@monomind/cli/dist/src/commands/memory.d.ts +1 -1
  31. package/packages/@monomind/cli/dist/src/commands/memory.js +138 -28
  32. package/packages/@monomind/cli/dist/src/commands/migrate.js +2 -2
  33. package/packages/@monomind/cli/dist/src/commands/neural.js +1 -1
  34. package/packages/@monomind/cli/dist/src/commands/swarm.js +1 -1
  35. package/packages/@monomind/cli/dist/src/config-adapter.js +8 -8
  36. package/packages/@monomind/cli/dist/src/index.js +1 -1
  37. package/packages/@monomind/cli/dist/src/init/claudemd-generator.js +2 -2
  38. package/packages/@monomind/cli/dist/src/init/executor.js +16 -16
  39. package/packages/@monomind/cli/dist/src/init/shared-instructions-generator.d.ts +1 -1
  40. package/packages/@monomind/cli/dist/src/init/shared-instructions-generator.js +1 -1
  41. package/packages/@monomind/cli/dist/src/init/statusline-generator.d.ts +1 -1
  42. package/packages/@monomind/cli/dist/src/init/statusline-generator.js +8 -8
  43. package/packages/@monomind/cli/dist/src/init/types.d.ts +3 -3
  44. package/packages/@monomind/cli/dist/src/init/types.js +3 -3
  45. package/packages/@monomind/cli/dist/src/mcp-client.js +1 -8
  46. package/packages/@monomind/cli/dist/src/mcp-tools/autopilot-tools.js +3 -3
  47. package/packages/@monomind/cli/dist/src/mcp-tools/daa-tools.js +13 -13
  48. package/packages/@monomind/cli/dist/src/mcp-tools/guidance-tools.js +4 -4
  49. package/packages/@monomind/cli/dist/src/mcp-tools/hive-mind-tools.js +4 -4
  50. package/packages/@monomind/cli/dist/src/mcp-tools/hooks-intelligence.js +1 -0
  51. package/packages/@monomind/cli/dist/src/mcp-tools/hooks-routing.js +23 -23
  52. package/packages/@monomind/cli/dist/src/mcp-tools/index.d.ts +0 -1
  53. package/packages/@monomind/cli/dist/src/mcp-tools/index.js +0 -2
  54. package/packages/@monomind/cli/dist/src/mcp-tools/memory-tools.d.ts +22 -6
  55. package/packages/@monomind/cli/dist/src/mcp-tools/memory-tools.js +553 -505
  56. package/packages/@monomind/cli/dist/src/mcp-tools/progress-tools.js +1 -1
  57. package/packages/@monomind/cli/dist/src/mcp-tools/system-tools.js +5 -5
  58. package/packages/@monomind/cli/dist/src/mcp-tools/transfer-tools.d.ts +1 -1
  59. package/packages/@monomind/cli/dist/src/mcp-tools/transfer-tools.js +1 -156
  60. package/packages/@monomind/cli/dist/src/memory/embedding-operations.js +3 -3
  61. package/packages/@monomind/cli/dist/src/memory/hnsw-operations.js +5 -5
  62. package/packages/@monomind/cli/dist/src/memory/intelligence.js +2 -2
  63. package/packages/@monomind/cli/dist/src/memory/memory-bridge.d.ts +86 -234
  64. package/packages/@monomind/cli/dist/src/memory/memory-bridge.js +455 -1702
  65. package/packages/@monomind/cli/dist/src/memory/memory-crud.js +3 -3
  66. package/packages/@monomind/cli/dist/src/memory/memory-initializer.d.ts +1 -1
  67. package/packages/@monomind/cli/dist/src/memory/memory-initializer.js +5 -5
  68. package/packages/@monomind/cli/dist/src/memory/memory-read.js +4 -4
  69. package/packages/@monomind/cli/dist/src/suggest.js +0 -1
  70. package/packages/@monomind/cli/dist/src/types.d.ts +1 -1
  71. package/packages/@monomind/cli/dist/src/ui/dashboard.html +41 -5
  72. package/packages/@monomind/cli/dist/src/ui/orgs.html +91 -5
  73. package/packages/@monomind/cli/dist/src/ui/server.mjs +44 -0
  74. package/packages/@monomind/cli/dist/src/update/validator.js +1 -3
  75. package/packages/@monomind/cli/package.json +4 -4
  76. package/scripts/verify-appliance.sh +1 -1
  77. package/packages/@monomind/cli/dist/src/commands/plugins.d.ts +0 -11
  78. package/packages/@monomind/cli/dist/src/commands/plugins.js +0 -799
  79. package/packages/@monomind/cli/dist/src/plugins/manager.d.ts +0 -133
  80. package/packages/@monomind/cli/dist/src/plugins/manager.js +0 -498
  81. package/packages/@monomind/cli/dist/src/plugins/store/discovery.d.ts +0 -88
  82. package/packages/@monomind/cli/dist/src/plugins/store/discovery.js +0 -650
  83. package/packages/@monomind/cli/dist/src/plugins/store/index.d.ts +0 -76
  84. package/packages/@monomind/cli/dist/src/plugins/store/index.js +0 -141
  85. package/packages/@monomind/cli/dist/src/plugins/store/search.d.ts +0 -46
  86. package/packages/@monomind/cli/dist/src/plugins/store/search.js +0 -231
  87. package/packages/@monomind/cli/dist/src/plugins/store/types.d.ts +0 -274
  88. package/packages/@monomind/cli/dist/src/plugins/store/types.js +0 -7
  89. package/packages/@monomind/cli/dist/src/plugins/tests/demo-plugin-store.d.ts +0 -7
  90. package/packages/@monomind/cli/dist/src/plugins/tests/demo-plugin-store.js +0 -126
  91. package/packages/@monomind/cli/dist/src/plugins/tests/standalone-test.d.ts +0 -12
  92. package/packages/@monomind/cli/dist/src/plugins/tests/standalone-test.js +0 -188
  93. package/packages/@monomind/cli/dist/src/plugins/tests/test-plugin-store.d.ts +0 -7
  94. package/packages/@monomind/cli/dist/src/plugins/tests/test-plugin-store.js +0 -206
  95. package/packages/@monomind/cli/dist/src/services/registry-api.d.ts +0 -58
  96. package/packages/@monomind/cli/dist/src/services/registry-api.js +0 -199
@@ -1,133 +0,0 @@
1
- /**
2
- * Plugin Manager
3
- * Handles actual plugin installation, persistence, and lifecycle
4
- * Bridges discovery service with file system persistence
5
- */
6
- export interface InstalledPlugin {
7
- name: string;
8
- version: string;
9
- installedAt: string;
10
- enabled: boolean;
11
- source: 'npm' | 'local' | 'ipfs';
12
- path?: string;
13
- commands?: string[];
14
- hooks?: string[];
15
- config?: Record<string, unknown>;
16
- }
17
- export interface InstalledPluginsManifest {
18
- version: '1.0.0';
19
- lastUpdated: string;
20
- plugins: Record<string, InstalledPlugin>;
21
- }
22
- export interface PluginManagerConfig {
23
- pluginsDir: string;
24
- manifestPath: string;
25
- }
26
- /**
27
- * Manages plugin installation, persistence, and lifecycle.
28
- *
29
- * Unlike the simulated version, this actually:
30
- * - Persists plugins to disk
31
- * - Downloads from npm
32
- * - Tracks enabled/disabled state
33
- * - Loads plugin modules
34
- */
35
- export declare class PluginManager {
36
- private config;
37
- private manifest;
38
- constructor(baseDir?: string);
39
- /**
40
- * Initialize the plugin manager, creating directories and loading manifest
41
- */
42
- initialize(): Promise<void>;
43
- private ensureDirectory;
44
- private loadManifest;
45
- private saveManifest;
46
- /**
47
- * Install a plugin from npm
48
- */
49
- installFromNpm(packageName: string, version?: string): Promise<{
50
- success: boolean;
51
- error?: string;
52
- plugin?: InstalledPlugin;
53
- }>;
54
- /**
55
- * Install a plugin from a local path
56
- */
57
- installFromLocal(sourcePath: string): Promise<{
58
- success: boolean;
59
- error?: string;
60
- plugin?: InstalledPlugin;
61
- }>;
62
- /**
63
- * Uninstall a plugin
64
- */
65
- uninstall(packageName: string): Promise<{
66
- success: boolean;
67
- error?: string;
68
- }>;
69
- /**
70
- * Enable a plugin
71
- */
72
- enable(packageName: string): Promise<{
73
- success: boolean;
74
- error?: string;
75
- }>;
76
- /**
77
- * Disable a plugin
78
- */
79
- disable(packageName: string): Promise<{
80
- success: boolean;
81
- error?: string;
82
- }>;
83
- /**
84
- * Toggle a plugin's enabled state
85
- */
86
- toggle(packageName: string): Promise<{
87
- success: boolean;
88
- enabled?: boolean;
89
- error?: string;
90
- }>;
91
- /**
92
- * Get all installed plugins
93
- */
94
- getInstalled(): Promise<InstalledPlugin[]>;
95
- /**
96
- * Get enabled plugins
97
- */
98
- getEnabled(): Promise<InstalledPlugin[]>;
99
- /**
100
- * Check if a plugin is installed
101
- */
102
- isInstalled(packageName: string): Promise<boolean>;
103
- /**
104
- * Get a specific installed plugin
105
- */
106
- getPlugin(packageName: string): Promise<InstalledPlugin | undefined>;
107
- /**
108
- * Upgrade a plugin to a new version
109
- */
110
- upgrade(packageName: string, version?: string): Promise<{
111
- success: boolean;
112
- error?: string;
113
- plugin?: InstalledPlugin;
114
- }>;
115
- /**
116
- * Update plugin config
117
- */
118
- setConfig(packageName: string, config: Record<string, unknown>): Promise<{
119
- success: boolean;
120
- error?: string;
121
- }>;
122
- /**
123
- * Get plugins directory path
124
- */
125
- getPluginsDir(): string;
126
- /**
127
- * Get manifest path
128
- */
129
- getManifestPath(): string;
130
- }
131
- export declare function getPluginManager(baseDir?: string): PluginManager;
132
- export declare function resetPluginManager(): void;
133
- //# sourceMappingURL=manager.d.ts.map
@@ -1,498 +0,0 @@
1
- /**
2
- * Plugin Manager
3
- * Handles actual plugin installation, persistence, and lifecycle
4
- * Bridges discovery service with file system persistence
5
- */
6
- import * as fs from 'fs';
7
- import * as path from 'path';
8
- import { execFile } from 'child_process';
9
- import { promisify } from 'util';
10
- const execFileAsync = promisify(execFile);
11
- /**
12
- * Validate npm package name to prevent shell injection (S-3)
13
- */
14
- const VALID_PACKAGE_RE = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*(@[a-z0-9._\-^~>=<]+)?$/;
15
- function validatePackageName(spec) {
16
- if (!VALID_PACKAGE_RE.test(spec)) {
17
- throw new Error(`Invalid package name: ${spec}`);
18
- }
19
- }
20
- const VALID_VERSION_RE = /^[a-zA-Z0-9._\-^~>=<*]+$/;
21
- function validateVersion(version) {
22
- if (!VALID_VERSION_RE.test(version) || version.length > 50) {
23
- throw new Error(`Invalid version specifier: ${version}`);
24
- }
25
- }
26
- /** Forbidden manifest keys (prototype pollution defense) */
27
- const FORBIDDEN_PLUGIN_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
28
- function isValidPluginKey(name) {
29
- return typeof name === 'string'
30
- && name.length > 0
31
- && name.length <= 214
32
- && !FORBIDDEN_PLUGIN_KEYS.has(name)
33
- && VALID_PACKAGE_RE.test(name);
34
- }
35
- // ============================================================================
36
- // Plugin Manager
37
- // ============================================================================
38
- /**
39
- * Manages plugin installation, persistence, and lifecycle.
40
- *
41
- * Unlike the simulated version, this actually:
42
- * - Persists plugins to disk
43
- * - Downloads from npm
44
- * - Tracks enabled/disabled state
45
- * - Loads plugin modules
46
- */
47
- export class PluginManager {
48
- config;
49
- manifest = null;
50
- constructor(baseDir = process.cwd()) {
51
- const pluginsDir = path.join(baseDir, '.monomind', 'plugins');
52
- this.config = {
53
- pluginsDir,
54
- manifestPath: path.join(pluginsDir, 'installed.json'),
55
- };
56
- }
57
- // =========================================================================
58
- // Initialization
59
- // =========================================================================
60
- /**
61
- * Initialize the plugin manager, creating directories and loading manifest
62
- */
63
- async initialize() {
64
- // Ensure plugins directory exists
65
- await this.ensureDirectory(this.config.pluginsDir);
66
- // Load or create manifest
67
- this.manifest = await this.loadManifest();
68
- }
69
- async ensureDirectory(dir) {
70
- if (!fs.existsSync(dir)) {
71
- fs.mkdirSync(dir, { recursive: true });
72
- }
73
- }
74
- async loadManifest() {
75
- try {
76
- const MAX_MANIFEST_BYTES = 10 * 1024 * 1024; // 10 MB
77
- if (fs.existsSync(this.config.manifestPath) && fs.statSync(this.config.manifestPath).size <= MAX_MANIFEST_BYTES) {
78
- const content = fs.readFileSync(this.config.manifestPath, 'utf-8');
79
- const parsed = JSON.parse(content);
80
- if (Object.prototype.hasOwnProperty.call(parsed, '__proto__') ||
81
- Object.prototype.hasOwnProperty.call(parsed, 'constructor') ||
82
- Object.prototype.hasOwnProperty.call(parsed, 'prototype')) {
83
- throw new Error('Manifest contains forbidden keys');
84
- }
85
- return parsed;
86
- }
87
- }
88
- catch (error) {
89
- console.warn('[PluginManager] Failed to load manifest, creating new one');
90
- }
91
- return {
92
- version: '1.0.0',
93
- lastUpdated: new Date().toISOString(),
94
- plugins: {},
95
- };
96
- }
97
- async saveManifest() {
98
- if (!this.manifest)
99
- return;
100
- this.manifest.lastUpdated = new Date().toISOString();
101
- await this.ensureDirectory(path.dirname(this.config.manifestPath));
102
- // Atomic write to prevent corruption on crash
103
- const tmp = this.config.manifestPath + '.tmp';
104
- fs.writeFileSync(tmp, JSON.stringify(this.manifest, null, 2), 'utf-8');
105
- fs.renameSync(tmp, this.config.manifestPath);
106
- }
107
- // =========================================================================
108
- // Installation
109
- // =========================================================================
110
- /**
111
- * Install a plugin from npm
112
- */
113
- async installFromNpm(packageName, version) {
114
- if (!this.manifest) {
115
- await this.initialize();
116
- }
117
- if (!isValidPluginKey(packageName)) {
118
- return { success: false, error: `Invalid package name: ${packageName}` };
119
- }
120
- if (version) {
121
- try {
122
- validateVersion(version);
123
- }
124
- catch {
125
- return { success: false, error: `Invalid version specifier: ${version}` };
126
- }
127
- }
128
- const versionSpec = version ? `${packageName}@${version}` : packageName;
129
- try {
130
- // Check if already installed
131
- if (Object.hasOwn(this.manifest.plugins, packageName)) {
132
- return {
133
- success: false,
134
- error: `Plugin ${packageName} is already installed. Use upgrade to update.`,
135
- };
136
- }
137
- // Install to local plugins directory
138
- const installDir = path.join(this.config.pluginsDir, 'node_modules');
139
- await this.ensureDirectory(installDir);
140
- // Validate package name to prevent injection (S-3)
141
- validatePackageName(versionSpec);
142
- // Use npm to install. --ignore-scripts blocks pre/post-install lifecycle hooks
143
- // from the plugin package, which would otherwise execute arbitrary code at
144
- // install time (the canonical npm supply-chain attack vector).
145
- console.log(`[PluginManager] Installing ${versionSpec}...`);
146
- await execFileAsync('npm', ['install', '--ignore-scripts', '--prefix', this.config.pluginsDir, versionSpec], { timeout: 120000 });
147
- // Get installed version
148
- const packageJsonPath = path.join(installDir, packageName, 'package.json');
149
- let installedVersion = version || 'latest';
150
- let commands = [];
151
- let hooks = [];
152
- const MAX_PKG_JSON_BYTES = 1024 * 1024; // 1 MB
153
- if (fs.existsSync(packageJsonPath) && fs.statSync(packageJsonPath).size <= MAX_PKG_JSON_BYTES) {
154
- const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
155
- installedVersion = pkg.version;
156
- // Check for monomind plugin metadata
157
- if (pkg['monomind']) {
158
- commands = Array.isArray(pkg['monomind'].commands) ? pkg['monomind'].commands : [];
159
- hooks = Array.isArray(pkg['monomind'].hooks) ? pkg['monomind'].hooks : [];
160
- }
161
- }
162
- // Create plugin entry
163
- const plugin = {
164
- name: packageName,
165
- version: installedVersion,
166
- installedAt: new Date().toISOString(),
167
- enabled: true,
168
- source: 'npm',
169
- path: path.join(installDir, packageName),
170
- commands,
171
- hooks,
172
- };
173
- // Save to manifest
174
- this.manifest.plugins[packageName] = plugin;
175
- await this.saveManifest();
176
- console.log(`[PluginManager] Installed ${packageName}@${installedVersion}`);
177
- return { success: true, plugin };
178
- }
179
- catch (error) {
180
- const errorMsg = error instanceof Error ? error.message : String(error);
181
- console.error(`[PluginManager] Failed to install ${packageName}:`, errorMsg);
182
- return { success: false, error: errorMsg };
183
- }
184
- }
185
- /**
186
- * Install a plugin from a local path
187
- */
188
- async installFromLocal(sourcePath) {
189
- if (!this.manifest) {
190
- await this.initialize();
191
- }
192
- try {
193
- const absolutePath = path.resolve(sourcePath);
194
- // Restrict local installs to paths under cwd or $HOME to prevent path traversal
195
- const cwd = process.cwd();
196
- const home = process.env.HOME ?? process.env.USERPROFILE ?? '';
197
- const underCwd = absolutePath.startsWith(cwd + path.sep) || absolutePath === cwd;
198
- const underHome = home && (absolutePath.startsWith(home + path.sep) || absolutePath === home);
199
- if (!underCwd && !underHome) {
200
- return { success: false, error: `Local path must be within the current directory or home: ${absolutePath}` };
201
- }
202
- if (!fs.existsSync(absolutePath)) {
203
- return { success: false, error: `Path does not exist: ${absolutePath}` };
204
- }
205
- // Read package.json
206
- const packageJsonPath = path.join(absolutePath, 'package.json');
207
- if (!fs.existsSync(packageJsonPath)) {
208
- return { success: false, error: 'No package.json found at path' };
209
- }
210
- if (fs.statSync(packageJsonPath).size > 1024 * 1024) {
211
- return { success: false, error: 'package.json exceeds size limit' };
212
- }
213
- const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
214
- const packageName = pkg.name;
215
- if (!isValidPluginKey(packageName)) {
216
- return { success: false, error: `Invalid package.json: name is missing or invalid` };
217
- }
218
- // Check if already installed
219
- if (Object.hasOwn(this.manifest.plugins, packageName)) {
220
- return {
221
- success: false,
222
- error: `Plugin ${packageName} is already installed`,
223
- };
224
- }
225
- // Create plugin entry (link to local path, don't copy)
226
- const plugin = {
227
- name: packageName,
228
- version: pkg.version,
229
- installedAt: new Date().toISOString(),
230
- enabled: true,
231
- source: 'local',
232
- path: absolutePath,
233
- commands: pkg['monomind']?.commands || [],
234
- hooks: pkg['monomind']?.hooks || [],
235
- };
236
- // Save to manifest
237
- this.manifest.plugins[packageName] = plugin;
238
- await this.saveManifest();
239
- console.log(`[PluginManager] Installed local plugin ${packageName}@${pkg.version}`);
240
- return { success: true, plugin };
241
- }
242
- catch (error) {
243
- const errorMsg = error instanceof Error ? error.message : String(error);
244
- console.error(`[PluginManager] Failed to install from local:`, errorMsg);
245
- return { success: false, error: errorMsg };
246
- }
247
- }
248
- // =========================================================================
249
- // Uninstallation
250
- // =========================================================================
251
- /**
252
- * Uninstall a plugin
253
- */
254
- async uninstall(packageName) {
255
- if (!this.manifest) {
256
- await this.initialize();
257
- }
258
- if (!isValidPluginKey(packageName)) {
259
- return { success: false, error: `Invalid package name` };
260
- }
261
- const plugin = Object.hasOwn(this.manifest.plugins, packageName)
262
- ? this.manifest.plugins[packageName]
263
- : undefined;
264
- if (!plugin) {
265
- return { success: false, error: `Plugin ${packageName} is not installed` };
266
- }
267
- try {
268
- // For npm-installed plugins, remove from node_modules
269
- if (plugin.source === 'npm') {
270
- validatePackageName(packageName);
271
- await execFileAsync('npm', ['uninstall', '--ignore-scripts', '--prefix', this.config.pluginsDir, packageName], { timeout: 60000 });
272
- }
273
- // Remove from manifest
274
- delete this.manifest.plugins[packageName];
275
- await this.saveManifest();
276
- console.log(`[PluginManager] Uninstalled ${packageName}`);
277
- return { success: true };
278
- }
279
- catch (error) {
280
- const errorMsg = error instanceof Error ? error.message : String(error);
281
- console.error(`[PluginManager] Failed to uninstall ${packageName}:`, errorMsg);
282
- return { success: false, error: errorMsg };
283
- }
284
- }
285
- // =========================================================================
286
- // Enable/Disable
287
- // =========================================================================
288
- /**
289
- * Enable a plugin
290
- */
291
- async enable(packageName) {
292
- if (!this.manifest) {
293
- await this.initialize();
294
- }
295
- if (!isValidPluginKey(packageName)) {
296
- return { success: false, error: `Invalid package name` };
297
- }
298
- const plugin = Object.hasOwn(this.manifest.plugins, packageName)
299
- ? this.manifest.plugins[packageName]
300
- : undefined;
301
- if (!plugin) {
302
- return { success: false, error: `Plugin ${packageName} is not installed` };
303
- }
304
- plugin.enabled = true;
305
- await this.saveManifest();
306
- return { success: true };
307
- }
308
- /**
309
- * Disable a plugin
310
- */
311
- async disable(packageName) {
312
- if (!this.manifest) {
313
- await this.initialize();
314
- }
315
- if (!isValidPluginKey(packageName)) {
316
- return { success: false, error: `Invalid package name` };
317
- }
318
- const plugin = Object.hasOwn(this.manifest.plugins, packageName)
319
- ? this.manifest.plugins[packageName]
320
- : undefined;
321
- if (!plugin) {
322
- return { success: false, error: `Plugin ${packageName} is not installed` };
323
- }
324
- plugin.enabled = false;
325
- await this.saveManifest();
326
- return { success: true };
327
- }
328
- /**
329
- * Toggle a plugin's enabled state
330
- */
331
- async toggle(packageName) {
332
- if (!this.manifest) {
333
- await this.initialize();
334
- }
335
- if (!isValidPluginKey(packageName)) {
336
- return { success: false, error: `Invalid package name` };
337
- }
338
- const plugin = Object.hasOwn(this.manifest.plugins, packageName)
339
- ? this.manifest.plugins[packageName]
340
- : undefined;
341
- if (!plugin) {
342
- return { success: false, error: `Plugin ${packageName} is not installed` };
343
- }
344
- plugin.enabled = !plugin.enabled;
345
- await this.saveManifest();
346
- return { success: true, enabled: plugin.enabled };
347
- }
348
- // =========================================================================
349
- // Query
350
- // =========================================================================
351
- /**
352
- * Get all installed plugins
353
- */
354
- async getInstalled() {
355
- if (!this.manifest) {
356
- await this.initialize();
357
- }
358
- return Object.values(this.manifest.plugins);
359
- }
360
- /**
361
- * Get enabled plugins
362
- */
363
- async getEnabled() {
364
- const all = await this.getInstalled();
365
- return all.filter(p => p.enabled);
366
- }
367
- /**
368
- * Check if a plugin is installed
369
- */
370
- async isInstalled(packageName) {
371
- if (!this.manifest) {
372
- await this.initialize();
373
- }
374
- if (!isValidPluginKey(packageName))
375
- return false;
376
- return Object.hasOwn(this.manifest.plugins, packageName);
377
- }
378
- /**
379
- * Get a specific installed plugin
380
- */
381
- async getPlugin(packageName) {
382
- if (!this.manifest) {
383
- await this.initialize();
384
- }
385
- if (!isValidPluginKey(packageName))
386
- return undefined;
387
- return Object.hasOwn(this.manifest.plugins, packageName)
388
- ? this.manifest.plugins[packageName]
389
- : undefined;
390
- }
391
- // =========================================================================
392
- // Upgrade
393
- // =========================================================================
394
- /**
395
- * Upgrade a plugin to a new version
396
- */
397
- async upgrade(packageName, version) {
398
- if (!this.manifest) {
399
- await this.initialize();
400
- }
401
- if (!isValidPluginKey(packageName)) {
402
- return { success: false, error: `Invalid package name` };
403
- }
404
- if (version) {
405
- try {
406
- validateVersion(version);
407
- }
408
- catch {
409
- return { success: false, error: `Invalid version specifier: ${version}` };
410
- }
411
- }
412
- const existing = Object.hasOwn(this.manifest.plugins, packageName)
413
- ? this.manifest.plugins[packageName]
414
- : undefined;
415
- if (!existing) {
416
- return { success: false, error: `Plugin ${packageName} is not installed` };
417
- }
418
- if (existing.source !== 'npm') {
419
- return { success: false, error: 'Can only upgrade npm-installed plugins' };
420
- }
421
- try {
422
- const versionSpec = version ? `${packageName}@${version}` : `${packageName}@latest`;
423
- // Validate package name to prevent injection (S-3)
424
- validatePackageName(versionSpec);
425
- // Reinstall with new version. --ignore-scripts blocks pre/post-install
426
- // lifecycle hooks from the plugin package.
427
- await execFileAsync('npm', ['install', '--ignore-scripts', '--prefix', this.config.pluginsDir, versionSpec], { timeout: 120000 });
428
- // Update manifest
429
- const installDir = path.join(this.config.pluginsDir, 'node_modules');
430
- const packageJsonPath = path.join(installDir, packageName, 'package.json');
431
- if (fs.existsSync(packageJsonPath) && fs.statSync(packageJsonPath).size <= 1024 * 1024) {
432
- const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
433
- existing.version = pkg.version;
434
- existing.commands = pkg['monomind']?.commands || existing.commands;
435
- existing.hooks = pkg['monomind']?.hooks || existing.hooks;
436
- }
437
- await this.saveManifest();
438
- console.log(`[PluginManager] Upgraded ${packageName} to ${existing.version}`);
439
- return { success: true, plugin: existing };
440
- }
441
- catch (error) {
442
- const errorMsg = error instanceof Error ? error.message : String(error);
443
- return { success: false, error: errorMsg };
444
- }
445
- }
446
- // =========================================================================
447
- // Config
448
- // =========================================================================
449
- /**
450
- * Update plugin config
451
- */
452
- async setConfig(packageName, config) {
453
- if (!this.manifest) {
454
- await this.initialize();
455
- }
456
- if (!isValidPluginKey(packageName)) {
457
- return { success: false, error: `Invalid package name` };
458
- }
459
- const plugin = Object.hasOwn(this.manifest.plugins, packageName)
460
- ? this.manifest.plugins[packageName]
461
- : undefined;
462
- if (!plugin) {
463
- return { success: false, error: `Plugin ${packageName} is not installed` };
464
- }
465
- plugin.config = { ...plugin.config, ...config };
466
- await this.saveManifest();
467
- return { success: true };
468
- }
469
- /**
470
- * Get plugins directory path
471
- */
472
- getPluginsDir() {
473
- return this.config.pluginsDir;
474
- }
475
- /**
476
- * Get manifest path
477
- */
478
- getManifestPath() {
479
- return this.config.manifestPath;
480
- }
481
- }
482
- // ============================================================================
483
- // Singleton Instance
484
- // ============================================================================
485
- let defaultManager = null;
486
- export function getPluginManager(baseDir) {
487
- if (!defaultManager) {
488
- defaultManager = new PluginManager(baseDir);
489
- }
490
- else if (baseDir && defaultManager.getPluginsDir() !== path.join(baseDir, '.monomind', 'plugins')) {
491
- console.warn(`[PluginManager] Warning: getPluginManager called with different baseDir. Using existing instance. Call resetPluginManager() first to change.`);
492
- }
493
- return defaultManager;
494
- }
495
- export function resetPluginManager() {
496
- defaultManager = null;
497
- }
498
- //# sourceMappingURL=manager.js.map