maskweaver 0.9.4 → 0.9.6

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 (229) hide show
  1. package/README.ko.md +638 -592
  2. package/README.md +671 -667
  3. package/dist/cli/doctor.js +5 -21
  4. package/dist/cli/install.d.ts +0 -8
  5. package/dist/cli/install.js +0 -39
  6. package/dist/context/config.d.ts +0 -22
  7. package/dist/context/config.js +0 -28
  8. package/dist/context/feature.d.ts +0 -39
  9. package/dist/context/feature.js +0 -77
  10. package/dist/context/files.d.ts +0 -13
  11. package/dist/context/files.js +1 -24
  12. package/dist/context/index.d.ts +0 -7
  13. package/dist/context/index.js +0 -12
  14. package/dist/context/project.d.ts +0 -21
  15. package/dist/context/project.js +0 -30
  16. package/dist/context/types.d.ts +0 -48
  17. package/dist/context/types.js +0 -12
  18. package/dist/context/utils.d.ts +0 -18
  19. package/dist/context/utils.js +0 -27
  20. package/dist/core/engine/promptBuilder.d.ts +0 -17
  21. package/dist/core/engine/promptBuilder.js +0 -28
  22. package/dist/core/index.d.ts +0 -6
  23. package/dist/core/index.js +0 -9
  24. package/dist/core/loader/MaskLoader.d.ts +0 -23
  25. package/dist/core/loader/MaskLoader.js +0 -29
  26. package/dist/core/schema/types.d.ts +0 -47
  27. package/dist/core/schema/types.js +0 -6
  28. package/dist/core/schema/validator.d.ts +0 -14
  29. package/dist/core/schema/validator.js +0 -18
  30. package/dist/i18n/index.d.ts +0 -18
  31. package/dist/i18n/index.js +4 -23
  32. package/dist/index.d.ts +0 -8
  33. package/dist/index.js +0 -8
  34. package/dist/lib.d.ts +0 -5
  35. package/dist/lib.js +0 -12
  36. package/dist/memory/chunking.d.ts +0 -22
  37. package/dist/memory/chunking.js +2 -37
  38. package/dist/memory/core.d.ts +0 -29
  39. package/dist/memory/core.js +1 -52
  40. package/dist/memory/index.d.ts +0 -5
  41. package/dist/memory/index.js +0 -10
  42. package/dist/memory/indexer.d.ts +0 -21
  43. package/dist/memory/indexer.js +0 -44
  44. package/dist/memory/providers/examples.d.ts +0 -5
  45. package/dist/memory/providers/examples.js +4 -64
  46. package/dist/memory/providers/factory.d.ts +0 -44
  47. package/dist/memory/providers/factory.js +0 -46
  48. package/dist/memory/providers/index.d.ts +0 -26
  49. package/dist/memory/providers/index.js +0 -28
  50. package/dist/memory/providers/ollama.d.ts +0 -6
  51. package/dist/memory/providers/ollama.js +1 -8
  52. package/dist/memory/providers/openai.d.ts +0 -6
  53. package/dist/memory/providers/openai.js +1 -8
  54. package/dist/memory/providers/openrouter.d.ts +0 -6
  55. package/dist/memory/providers/openrouter.js +0 -8
  56. package/dist/memory/providers/text-only.d.ts +0 -13
  57. package/dist/memory/providers/text-only.js +0 -17
  58. package/dist/memory/providers/types.d.ts +0 -39
  59. package/dist/memory/providers/types.js +0 -7
  60. package/dist/memory/providers/voyage.d.ts +0 -22
  61. package/dist/memory/providers/voyage.js +1 -24
  62. package/dist/memory/search/hybrid.d.ts +0 -12
  63. package/dist/memory/search/hybrid.js +1 -22
  64. package/dist/memory/store/sqlite.d.ts +0 -72
  65. package/dist/memory/store/sqlite.js +4 -127
  66. package/dist/plugin/config/index.d.ts +0 -112
  67. package/dist/plugin/config/index.js +0 -115
  68. package/dist/plugin/index.d.ts +0 -13
  69. package/dist/plugin/index.js +1 -123
  70. package/dist/plugin/tools/command-registry.d.ts +0 -6
  71. package/dist/plugin/tools/command-registry.js +0 -14
  72. package/dist/plugin/tools/context.d.ts +0 -12
  73. package/dist/plugin/tools/context.js +0 -58
  74. package/dist/plugin/tools/maskSave.d.ts +0 -3
  75. package/dist/plugin/tools/maskSave.js +0 -3
  76. package/dist/plugin/tools/memoryGet.d.ts +0 -3
  77. package/dist/plugin/tools/memoryGet.js +0 -3
  78. package/dist/plugin/tools/memoryIndexer.d.ts +0 -3
  79. package/dist/plugin/tools/memoryIndexer.js +0 -10
  80. package/dist/plugin/tools/memorySearch.d.ts +0 -31
  81. package/dist/plugin/tools/memorySearch.js +0 -79
  82. package/dist/plugin/tools/memoryWrite.d.ts +0 -8
  83. package/dist/plugin/tools/memoryWrite.js +0 -32
  84. package/dist/plugin/tools/retrospect.d.ts +0 -3
  85. package/dist/plugin/tools/retrospect.js +0 -3
  86. package/dist/plugin/tools/slashcommand.d.ts +0 -11
  87. package/dist/plugin/tools/slashcommand.js +0 -38
  88. package/dist/plugin/tools/squad.d.ts +0 -12
  89. package/dist/plugin/tools/squad.js +11 -83
  90. package/dist/plugin/tools/weave.d.ts +0 -6
  91. package/dist/plugin/tools/weave.js +0 -78
  92. package/dist/plugin/types.d.ts +0 -20
  93. package/dist/plugin/types.js +0 -7
  94. package/dist/retrospect/index.d.ts +0 -7
  95. package/dist/retrospect/index.js +0 -9
  96. package/dist/retrospect/mask-save.d.ts +0 -12
  97. package/dist/retrospect/mask-save.js +1 -80
  98. package/dist/retrospect/retrospect.d.ts +0 -18
  99. package/dist/retrospect/retrospect.js +0 -63
  100. package/dist/retrospect/strategies/base.d.ts +0 -15
  101. package/dist/retrospect/strategies/base.js +0 -7
  102. package/dist/retrospect/strategies/deep.d.ts +0 -12
  103. package/dist/retrospect/strategies/deep.js +0 -24
  104. package/dist/retrospect/strategies/index.d.ts +0 -12
  105. package/dist/retrospect/strategies/index.js +0 -12
  106. package/dist/retrospect/strategies/quick.d.ts +0 -12
  107. package/dist/retrospect/strategies/quick.js +0 -19
  108. package/dist/retrospect/strategies/standard.d.ts +0 -12
  109. package/dist/retrospect/strategies/standard.js +0 -15
  110. package/dist/retrospect/types.d.ts +0 -7
  111. package/dist/retrospect/types.js +0 -7
  112. package/dist/shared/config.d.ts +0 -105
  113. package/dist/shared/config.js +0 -33
  114. package/dist/shared/errors.d.ts +0 -18
  115. package/dist/shared/errors.js +0 -19
  116. package/dist/shared/generate-agents.d.ts +0 -69
  117. package/dist/shared/generate-agents.js +2 -86
  118. package/dist/shared/image.d.ts +0 -67
  119. package/dist/shared/image.js +6 -104
  120. package/dist/shared/index.d.ts +0 -5
  121. package/dist/shared/index.js +0 -7
  122. package/dist/shared/model-registry.d.ts +0 -72
  123. package/dist/shared/model-registry.js +5 -95
  124. package/dist/shared/types.d.ts +0 -15
  125. package/dist/shared/types.js +0 -3
  126. package/dist/shared-context/dag.d.ts +0 -105
  127. package/dist/shared-context/dag.js +3 -114
  128. package/dist/shared-context/index.d.ts +0 -5
  129. package/dist/shared-context/index.js +0 -15
  130. package/dist/shared-context/logger.d.ts +0 -37
  131. package/dist/shared-context/logger.js +0 -41
  132. package/dist/shared-context/parallel-executor.d.ts +0 -54
  133. package/dist/shared-context/parallel-executor.js +4 -56
  134. package/dist/shared-context/session.d.ts +0 -56
  135. package/dist/shared-context/session.js +0 -47
  136. package/dist/shared-context/squad.d.ts +0 -68
  137. package/dist/shared-context/squad.js +0 -63
  138. package/dist/shared-context/storage.d.ts +0 -132
  139. package/dist/shared-context/storage.js +0 -116
  140. package/dist/shared-context/task.d.ts +0 -120
  141. package/dist/shared-context/task.js +0 -152
  142. package/dist/shared-context/test/dag.test.js +9 -14
  143. package/dist/shared-context/test/logger.test.d.ts +0 -8
  144. package/dist/shared-context/test/logger.test.js +0 -52
  145. package/dist/shared-context/test/session.test.d.ts +0 -7
  146. package/dist/shared-context/test/session.test.js +0 -63
  147. package/dist/shared-context/test/squad.test.d.ts +0 -10
  148. package/dist/shared-context/test/squad.test.js +2 -68
  149. package/dist/shared-context/test/storage.test.d.ts +0 -8
  150. package/dist/shared-context/test/storage.test.js +0 -68
  151. package/dist/shared-context/test/task.test.d.ts +0 -7
  152. package/dist/shared-context/test/task.test.js +0 -54
  153. package/dist/shared-context/test/watchdog.test.d.ts +0 -7
  154. package/dist/shared-context/test/watchdog.test.js +3 -58
  155. package/dist/shared-context/types.d.ts +0 -215
  156. package/dist/shared-context/types.js +0 -125
  157. package/dist/shared-context/watchdog.d.ts +0 -127
  158. package/dist/shared-context/watchdog.js +0 -148
  159. package/dist/shared-context/worktree.d.ts +0 -68
  160. package/dist/shared-context/worktree.js +2 -34
  161. package/dist/verify/budget.d.ts +0 -29
  162. package/dist/verify/budget.js +0 -34
  163. package/dist/verify/critical-files.d.ts +0 -17
  164. package/dist/verify/critical-files.js +0 -37
  165. package/dist/verify/escalation.d.ts +0 -20
  166. package/dist/verify/escalation.js +0 -22
  167. package/dist/verify/index.d.ts +0 -5
  168. package/dist/verify/index.js +0 -11
  169. package/dist/verify/prompts.d.ts +0 -20
  170. package/dist/verify/prompts.js +0 -20
  171. package/dist/verify/types.d.ts +0 -26
  172. package/dist/verify/types.js +1 -12
  173. package/dist/verify/verifier.d.ts +0 -29
  174. package/dist/verify/verifier.js +0 -54
  175. package/dist/version.d.ts +1 -16
  176. package/dist/version.js +1 -16
  177. package/dist/weave/bridge.d.ts +0 -35
  178. package/dist/weave/bridge.js +0 -51
  179. package/dist/weave/environment/detector.d.ts +0 -6
  180. package/dist/weave/environment/detector.js +4 -45
  181. package/dist/weave/environment/index.d.ts +0 -19
  182. package/dist/weave/environment/index.js +1 -39
  183. package/dist/weave/environment/issues.d.ts +0 -35
  184. package/dist/weave/environment/issues.js +0 -59
  185. package/dist/weave/git.d.ts +0 -8
  186. package/dist/weave/git.js +0 -8
  187. package/dist/weave/index.d.ts +0 -13
  188. package/dist/weave/index.js +2 -28
  189. package/dist/weave/knowledge/global.d.ts +0 -39
  190. package/dist/weave/knowledge/global.js +2 -78
  191. package/dist/weave/loop.js +0 -3
  192. package/dist/weave/orchestrator.d.ts +0 -69
  193. package/dist/weave/orchestrator.js +1 -101
  194. package/dist/weave/phase-manager.d.ts +0 -64
  195. package/dist/weave/phase-manager.js +0 -89
  196. package/dist/weave/security/secret-scan.d.ts +0 -14
  197. package/dist/weave/security/secret-scan.js +0 -19
  198. package/dist/weave/stages/build.js +0 -15
  199. package/dist/weave/stages/execute.d.ts +0 -42
  200. package/dist/weave/stages/execute.js +4 -86
  201. package/dist/weave/stages/handoff.d.ts +0 -7
  202. package/dist/weave/stages/handoff.js +0 -43
  203. package/dist/weave/stages/index.d.ts +0 -3
  204. package/dist/weave/stages/index.js +0 -3
  205. package/dist/weave/stages/intake.d.ts +0 -8
  206. package/dist/weave/stages/intake.js +5 -65
  207. package/dist/weave/stages/map.d.ts +0 -1
  208. package/dist/weave/stages/openspec.d.ts +0 -1
  209. package/dist/weave/stages/plan.d.ts +0 -11
  210. package/dist/weave/stages/plan.js +1 -53
  211. package/dist/weave/stages/refine.d.ts +0 -7
  212. package/dist/weave/stages/refine.js +0 -7
  213. package/dist/weave/stages/research.d.ts +0 -6
  214. package/dist/weave/stages/research.js +0 -6
  215. package/dist/weave/stages/spec.d.ts +0 -12
  216. package/dist/weave/stages/spec.js +0 -17
  217. package/dist/weave/types.d.ts +0 -20
  218. package/dist/weave/types.js +0 -5
  219. package/dist/weave/verification/commands.d.ts +0 -12
  220. package/dist/weave/verification/commands.js +0 -19
  221. package/dist/weave/verification/index.d.ts +0 -6
  222. package/dist/weave/verification/index.js +1 -19
  223. package/dist/weave/verification/playwright.d.ts +0 -47
  224. package/dist/weave/verification/playwright.js +1 -90
  225. package/dist/weave/worktree.d.ts +0 -16
  226. package/dist/weave/worktree.js +0 -23
  227. package/dist/weave/yaml-repair.d.ts +0 -39
  228. package/dist/weave/yaml-repair.js +13 -116
  229. package/package.json +1 -1
@@ -1,13 +1,3 @@
1
- /**
2
- * Maskweaver Plugin Configuration Loader
3
- *
4
- * Loads maskweaver.json(c) configuration files with support for:
5
- * - Project-level configuration (.opencode/maskweaver.json)
6
- * - Global configuration (~/.config/opencode/maskweaver.json)
7
- * - JSONC format (comments, trailing commas)
8
- *
9
- * Based on oh-my-opencode pattern for plugin configuration management.
10
- */
11
1
  import { parse as parseJsonc } from 'jsonc-parser';
12
2
  import * as fs from 'node:fs';
13
3
  import * as path from 'node:path';
@@ -21,51 +11,23 @@ function pluginLog(ctx, level, message) {
21
11
  },
22
12
  });
23
13
  }
24
- // ============================================================================
25
- // Configuration Loader
26
- // ============================================================================
27
- /**
28
- * Get all possible configuration file locations in priority order
29
- *
30
- * Priority:
31
- * 1. .opencode/maskweaver.json (project)
32
- * 2. .opencode/maskweaver.jsonc (project)
33
- * 3. ~/.config/opencode/maskweaver.json (global)
34
- * 4. ~/.config/opencode/maskweaver.jsonc (global)
35
- */
36
14
  function getConfigLocations(directory) {
37
15
  const homeDir = os.homedir();
38
16
  return [
39
- // Project-level configurations (highest priority)
40
17
  path.join(directory, '.opencode', 'maskweaver.json'),
41
18
  path.join(directory, '.opencode', 'maskweaver.jsonc'),
42
- // Global configurations
43
19
  path.join(homeDir, '.config', 'opencode', 'maskweaver.json'),
44
20
  path.join(homeDir, '.config', 'opencode', 'maskweaver.jsonc'),
45
21
  ];
46
22
  }
47
- /**
48
- * Parse JSONC content (JSON with comments and trailing commas)
49
- */
50
23
  function parseJsoncContent(content) {
51
24
  try {
52
- // Use jsonc-parser for robust JSONC parsing
53
25
  return parseJsonc(content);
54
26
  }
55
27
  catch (error) {
56
28
  throw new Error(`Failed to parse JSONC: ${error}`);
57
29
  }
58
30
  }
59
- /**
60
- * Load plugin configuration from directory
61
- *
62
- * Searches for configuration files in priority order and returns
63
- * the first found configuration. Returns empty object if no config found.
64
- *
65
- * @param directory - Project directory to search for config
66
- * @param ctx - Optional plugin context (for logging)
67
- * @returns Parsed configuration object
68
- */
69
31
  export function loadPluginConfig(directory, ctx) {
70
32
  const locations = getConfigLocations(directory);
71
33
  for (const location of locations) {
@@ -73,133 +35,61 @@ export function loadPluginConfig(directory, ctx) {
73
35
  try {
74
36
  const content = fs.readFileSync(location, 'utf-8');
75
37
  const config = parseJsoncContent(content);
76
- // Log successful config load
77
38
  if (ctx?.verbose) {
78
39
  pluginLog(ctx, 'info', `Loaded config from: ${location}`);
79
40
  }
80
41
  return config;
81
42
  }
82
43
  catch (error) {
83
- // Log error but continue searching
84
44
  if (ctx) {
85
45
  pluginLog(ctx, 'warn', `Failed to load config from ${location}: ${error}`);
86
46
  }
87
47
  }
88
48
  }
89
49
  }
90
- // No configuration found - return empty config
91
50
  if (ctx?.verbose) {
92
51
  pluginLog(ctx, 'info', 'No maskweaver.json found, using defaults');
93
52
  }
94
53
  return {};
95
54
  }
96
- // ============================================================================
97
- // Helper Functions
98
- // ============================================================================
99
- /**
100
- * Check if a tool is enabled in the configuration
101
- *
102
- * A tool is considered enabled if:
103
- * - No disabled_tools list exists, OR
104
- * - disabled_tools list exists but doesn't include the tool name
105
- *
106
- * @param config - Plugin configuration
107
- * @param toolName - Name of the tool to check
108
- * @returns true if tool is enabled, false otherwise
109
- */
110
55
  export function isToolEnabled(config, toolName) {
111
56
  if (!config.disabled_tools || config.disabled_tools.length === 0) {
112
57
  return true;
113
58
  }
114
59
  return !config.disabled_tools.includes(toolName);
115
60
  }
116
- /**
117
- * Check if a mask is enabled in the configuration
118
- *
119
- * A mask is considered enabled if:
120
- * - No disabled_masks list exists, OR
121
- * - disabled_masks list exists but doesn't include the mask ID
122
- *
123
- * @param config - Plugin configuration
124
- * @param maskId - ID of the mask to check
125
- * @returns true if mask is enabled, false otherwise
126
- */
127
61
  export function isMaskEnabled(config, maskId) {
128
62
  if (!config.disabled_masks || config.disabled_masks.length === 0) {
129
63
  return true;
130
64
  }
131
65
  return !config.disabled_masks.includes(maskId);
132
66
  }
133
- /**
134
- * Get the default mask ID from configuration
135
- *
136
- * @param config - Plugin configuration
137
- * @returns Default mask ID if configured, undefined otherwise
138
- */
139
67
  export function getDefaultMask(config) {
140
68
  return config.masks?.default;
141
69
  }
142
- /**
143
- * Check if auto-activation is enabled for the default mask
144
- *
145
- * @param config - Plugin configuration
146
- * @returns true if auto-activation is enabled, false otherwise
147
- */
148
70
  export function isAutoActivateEnabled(config) {
149
71
  return config.masks?.autoActivate ?? false;
150
72
  }
151
- /**
152
- * Get agent override for a specific agent
153
- *
154
- * @param config - Plugin configuration
155
- * @param agentName - Name of the agent
156
- * @returns Agent override config if exists, undefined otherwise
157
- */
158
73
  export function getAgentOverride(config, agentName) {
159
74
  return config.agents?.[agentName];
160
75
  }
161
- /**
162
- * Check if verbose logging is enabled
163
- *
164
- * @param config - Plugin configuration
165
- * @returns true if verbose logging is enabled, false otherwise
166
- */
167
76
  export function isVerboseLoggingEnabled(config) {
168
77
  return config.logging?.verbose ?? false;
169
78
  }
170
- /**
171
- * Check if completion sound notification is enabled
172
- *
173
- * @param config - Plugin configuration
174
- * @returns true if completion sound is enabled, false otherwise
175
- */
176
79
  export function isCompletionSoundEnabled(config) {
177
80
  return config.notifications?.completionSound?.enabled ?? false;
178
81
  }
179
- // ============================================================================
180
- // Configuration Validation
181
- // ============================================================================
182
- /**
183
- * Validate configuration structure
184
- *
185
- * @param config - Configuration to validate
186
- * @returns Array of validation error messages (empty if valid)
187
- */
188
82
  export function validateConfig(config) {
189
83
  const errors = [];
190
- // Validate disabled_masks
191
84
  if (config.disabled_masks && !Array.isArray(config.disabled_masks)) {
192
85
  errors.push('disabled_masks must be an array of strings');
193
86
  }
194
- // Validate disabled_tools
195
87
  if (config.disabled_tools && !Array.isArray(config.disabled_tools)) {
196
88
  errors.push('disabled_tools must be an array of strings');
197
89
  }
198
- // Validate agents
199
90
  if (config.agents && typeof config.agents !== 'object') {
200
91
  errors.push('agents must be an object');
201
92
  }
202
- // Validate masks config
203
93
  if (config.masks) {
204
94
  if (typeof config.masks !== 'object') {
205
95
  errors.push('masks must be an object');
@@ -213,7 +103,6 @@ export function validateConfig(config) {
213
103
  }
214
104
  }
215
105
  }
216
- // Validate logging
217
106
  if (config.logging) {
218
107
  if (typeof config.logging !== 'object') {
219
108
  errors.push('logging must be an object');
@@ -224,7 +113,6 @@ export function validateConfig(config) {
224
113
  }
225
114
  }
226
115
  }
227
- // Validate notifications
228
116
  if (config.notifications) {
229
117
  if (typeof config.notifications !== 'object') {
230
118
  errors.push('notifications must be an object');
@@ -240,9 +128,6 @@ export function validateConfig(config) {
240
128
  }
241
129
  return errors;
242
130
  }
243
- // ============================================================================
244
- // Export default for convenience
245
- // ============================================================================
246
131
  export default {
247
132
  loadPluginConfig,
248
133
  isToolEnabled,
@@ -1,16 +1,3 @@
1
- /**
2
- * Maskweaver Plugin for opencode
3
- *
4
- * Key features:
5
- * - Configuration-driven tool activation/deactivation
6
- * - Auto-activation of default masks
7
- * - Agent configuration overrides
8
- * - Event-based lifecycle hooks
9
- * - Memory and context management tools
10
- * - Clean plugin architecture
11
- *
12
- * Based on oh-my-opencode plugin development patterns.
13
- */
14
1
  import { type Plugin } from '@opencode-ai/plugin';
15
2
  export declare const MaskweaverPlugin: Plugin;
16
3
  declare const _default: {
@@ -1,16 +1,3 @@
1
- /**
2
- * Maskweaver Plugin for opencode
3
- *
4
- * Key features:
5
- * - Configuration-driven tool activation/deactivation
6
- * - Auto-activation of default masks
7
- * - Agent configuration overrides
8
- * - Event-based lifecycle hooks
9
- * - Memory and context management tools
10
- * - Clean plugin architecture
11
- *
12
- * Based on oh-my-opencode plugin development patterns.
13
- */
14
1
  import { z } from 'zod';
15
2
  import * as fs from 'node:fs';
16
3
  import * as path from 'node:path';
@@ -19,7 +6,6 @@ import { spawnSync } from 'node:child_process';
19
6
  import { fileURLToPath } from 'node:url';
20
7
  import { VERSION } from '../version.js';
21
8
  import { loadPluginConfig, isMaskEnabled, isToolEnabled, getDefaultMask, isAutoActivateEnabled, isVerboseLoggingEnabled, isCompletionSoundEnabled, validateConfig, } from './config/index.js';
22
- // New tool imports
23
9
  import { createMemorySearchTool } from './tools/memorySearch.js';
24
10
  import { createMemoryWriteTool } from './tools/memoryWrite.js';
25
11
  import { createMemoryGetTool } from './tools/memoryGet.js';
@@ -53,17 +39,14 @@ function getAssetsDir() {
53
39
  try {
54
40
  const __filename = fileURLToPath(import.meta.url);
55
41
  const __dirname = path.dirname(__filename);
56
- // 1. If in dist/plugin/ (production) -> ../../assets
57
42
  const distAssets = path.join(__dirname, '..', '..', 'assets');
58
43
  if (fs.existsSync(distAssets)) {
59
44
  return distAssets;
60
45
  }
61
- // 2. If in src/plugin/ (development) -> ../../assets
62
46
  const srcAssets = path.join(__dirname, '..', '..', 'assets');
63
47
  if (fs.existsSync(srcAssets)) {
64
48
  return srcAssets;
65
49
  }
66
- // 3. Fallback for npm package structure (node_modules/maskweaver/dist/plugin/index.js)
67
50
  return distAssets;
68
51
  }
69
52
  catch {
@@ -109,7 +92,6 @@ function installAssets(projectDir) {
109
92
  const homeDir = os.homedir();
110
93
  const globalConfigDir = path.join(homeDir, '.config', 'opencode');
111
94
  const projectOpencodeDir = path.join(projectDir, '.opencode');
112
- // Install to both global and project directories to ensure visibility
113
95
  const targetDirs = [projectOpencodeDir];
114
96
  if (fs.existsSync(globalConfigDir)) {
115
97
  targetDirs.push(globalConfigDir);
@@ -124,21 +106,17 @@ function installAssets(projectDir) {
124
106
  continue;
125
107
  }
126
108
  }
127
- // Install agents
128
109
  const agentsSrc = path.join(assetsDir, 'agents');
129
110
  const agentsDest = path.join(targetDir, 'agents');
130
111
  copyDirRecursive(agentsSrc, agentsDest, result);
131
- // Install masks
132
112
  const masksSrc = path.join(assetsDir, 'masks');
133
113
  const masksDest = path.join(targetDir, 'masks');
134
114
  copyDirRecursive(masksSrc, masksDest, result);
135
- // Install commands (always overwrite to keep commands up-to-date)
136
115
  const commandsSrc = path.join(assetsDir, 'commands');
137
116
  const commandsDest = path.join(targetDir, 'commands');
138
117
  if (fs.existsSync(commandsSrc)) {
139
118
  copyDirRecursive(commandsSrc, commandsDest, result, true);
140
119
  }
141
- // Hard-remove deprecated weave commands to keep a craft-centric flow.
142
120
  for (const commandFile of REMOVED_WEAVE_COMMAND_FILES) {
143
121
  const legacyPath = path.join(commandsDest, commandFile);
144
122
  if (!fs.existsSync(legacyPath))
@@ -153,29 +131,11 @@ function installAssets(projectDir) {
153
131
  }
154
132
  return result;
155
133
  }
156
- // ============================================================================
157
- // Pool Agent Generator
158
- // ============================================================================
159
- /**
160
- * Generate dummy-human agent .md files from maskweaver.config.json's dummyHumans.pool.
161
- *
162
- * For each pool entry with a non-empty model, creates .opencode/agents/dummy-{id}.md.
163
- * Skips existing files to protect user customizations — use `weave sync-agents`
164
- * to force overwrite from the config.
165
- *
166
- * Also skips entries with empty model names (template placeholders) to prevent
167
- * generating broken agent files.
168
- */
169
134
  function generatePoolAgents(projectDir) {
170
135
  const agentsDir = path.join(projectDir, '.opencode', 'agents');
171
- // Use shared utility — force=false means skip existing
172
136
  const result = generatePoolAgentFilesFromConfig(projectDir, agentsDir, { force: false });
173
- // Extract successfully created files (not skipped, not updated)
174
137
  return result.created;
175
138
  }
176
- // ============================================================================
177
- // Simple YAML Parser
178
- // ============================================================================
179
139
  function parseSimpleYaml(content) {
180
140
  const lines = content.split('\n');
181
141
  const result = {};
@@ -331,9 +291,6 @@ function parseValue(value) {
331
291
  return num;
332
292
  return value;
333
293
  }
334
- // ============================================================================
335
- // Mask Loader
336
- // ============================================================================
337
294
  class MaskLoader {
338
295
  masksDir;
339
296
  catalog = null;
@@ -354,7 +311,6 @@ class MaskLoader {
354
311
  return this.catalog;
355
312
  }
356
313
  async load(maskId) {
357
- // Check if mask is disabled in configuration
358
314
  if (!isMaskEnabled(this.config, maskId)) {
359
315
  return null;
360
316
  }
@@ -388,7 +344,6 @@ class MaskLoader {
388
344
  const result = [];
389
345
  for (const [categoryId, category] of Object.entries(catalog.categories)) {
390
346
  for (const mask of category.masks) {
391
- // Filter out disabled masks
392
347
  if (isMaskEnabled(this.config, mask.id)) {
393
348
  result.push({ ...mask, category: categoryId });
394
349
  }
@@ -399,7 +354,6 @@ class MaskLoader {
399
354
  async listCategories() {
400
355
  const catalog = await this.loadCatalog();
401
356
  return Object.entries(catalog.categories).map(([id, cat]) => {
402
- // Count only enabled masks
403
357
  const enabledMasks = cat.masks.filter(m => isMaskEnabled(this.config, m.id));
404
358
  return {
405
359
  id,
@@ -410,9 +364,6 @@ class MaskLoader {
410
364
  });
411
365
  }
412
366
  }
413
- // ============================================================================
414
- // Prompt Builder
415
- // ============================================================================
416
367
  function buildRichPrompt(mask) {
417
368
  const parts = [];
418
369
  parts.push(`You are ${mask.profile.name}.`);
@@ -463,9 +414,6 @@ function pluginLog(client, level, message) {
463
414
  },
464
415
  });
465
416
  }
466
- // ============================================================================
467
- // Helper functions for tool factories
468
- // ============================================================================
469
417
  function createListMasksTool(maskLoader, activeMask) {
470
418
  return {
471
419
  description: 'List all available expert persona masks.',
@@ -580,7 +528,7 @@ function createMaskweaverStatusTool(maskLoader, masksDir, activeMask) {
580
528
  masksCount = masks.length;
581
529
  categoriesCount = categories.length;
582
530
  }
583
- catch (_e) { /* ignore */ }
531
+ catch (_e) { }
584
532
  }
585
533
  const active = activeMask();
586
534
  return `Maskweaver v${VERSION}
@@ -635,42 +583,27 @@ function playCompletionSound(config) {
635
583
  process.stdout.write('\u0007');
636
584
  }
637
585
  catch {
638
- // Ignore failures - notification sound is best-effort only.
639
586
  }
640
587
  }
641
588
  }
642
589
  let state = null;
643
- // ============================================================================
644
590
  export const MaskweaverPlugin = async ({ client, directory, project, worktree, $, serverUrl }) => {
645
- // ==========================================================================
646
- // 1. Load Configuration (oh-my-opencode pattern)
647
- // ==========================================================================
648
591
  const pluginConfig = loadPluginConfig(directory, { client, verbose: false });
649
- // Validate configuration
650
592
  const configErrors = validateConfig(pluginConfig);
651
593
  if (configErrors.length > 0) {
652
594
  pluginLog(client, 'warn', `Configuration validation errors: ${configErrors.join(', ')}`);
653
595
  }
654
596
  const verbose = isVerboseLoggingEnabled(pluginConfig);
655
- // ==========================================================================
656
- // 2. Auto-install assets on first run
657
- // ==========================================================================
658
597
  const installResult = installAssets(directory);
659
- // Track if this is a first-time installation
660
598
  const isFirstInstall = installResult.installed.length > 0;
661
599
  if (isFirstInstall) {
662
600
  pluginLog(client, 'info', `Installed ${installResult.installed.length} files to .opencode/ (agents, masks)`);
663
- // Show prominent restart message for first-time installation
664
601
  pluginLog(client, 'warn', `⚠️ RESTART REQUIRED: Please restart OpenCode to activate all Maskweaver features (agents, masks, commands).`);
665
602
  }
666
603
  if (installResult.errors.length > 0) {
667
604
  pluginLog(client, 'warn', `Asset errors: ${installResult.errors.join(', ')}`);
668
605
  }
669
- // ==========================================================================
670
- // 2b. Auto-create/migrate default config files (global first, then project)
671
- // ==========================================================================
672
606
  const globalConfigDir = path.join(os.homedir(), '.config', 'opencode');
673
- // Migrate/update global config with missing fields
674
607
  const globalConfigPath = path.join(globalConfigDir, 'maskweaver.config.json');
675
608
  if (fs.existsSync(globalConfigPath)) {
676
609
  try {
@@ -703,25 +636,17 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
703
636
  if (createdPluginConfig) {
704
637
  pluginLog(client, 'info', `Created plugin config: ${path.relative(directory, createdPluginConfig)}`);
705
638
  }
706
- // ==========================================================================
707
- // 2c. Generate pool agents from maskweaver.config.json (dummyHumans.pool)
708
- // ==========================================================================
709
639
  const generatedAgents = generatePoolAgents(directory);
710
640
  if (generatedAgents.length > 0) {
711
641
  pluginLog(client, 'info', `Generated ${generatedAgents.length} pool agent files from maskweaver.config.json: ${generatedAgents.map(p => path.basename(p)).join(', ')}`);
712
642
  pluginLog(client, 'warn', `⚠️ RESTART REQUIRED: Please restart OpenCode to activate the new pool agent files.`);
713
643
  }
714
- // If project config was just created but pool has no agents, warn user
715
644
  if (createdRuntimeConfig && generatedAgents.length === 0) {
716
645
  pluginLog(client, 'warn', `⚠️ maskweaver.config.json was created. Edit it to configure your model pool, then restart OpenCode.`);
717
646
  }
718
- // ==========================================================================
719
- // 3. Initialize masks
720
- // ==========================================================================
721
647
  const homeDir = os.homedir();
722
648
  const globalMasksDir = path.join(homeDir, '.config', 'opencode', 'masks');
723
649
  const projectMasksDir = path.join(directory, '.opencode', 'masks');
724
- // Priority: project masks > global masks
725
650
  const masksDir = fs.existsSync(projectMasksDir) ? projectMasksDir : globalMasksDir;
726
651
  const pluginState = {
727
652
  maskLoader: null,
@@ -731,7 +656,6 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
731
656
  currentSessionID: null,
732
657
  };
733
658
  state = pluginState;
734
- // Log plugin loaded
735
659
  pluginLog(client, 'info', `Maskweaver plugin loaded v${VERSION}`);
736
660
  if (fs.existsSync(masksDir)) {
737
661
  pluginState.maskLoader = new MaskLoader(masksDir, pluginConfig);
@@ -746,9 +670,6 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
746
670
  pluginState.maskLoader = null;
747
671
  }
748
672
  }
749
- // ==========================================================================
750
- // 4. Auto-activate default mask (oh-my-opencode pattern)
751
- // ==========================================================================
752
673
  const defaultMaskId = getDefaultMask(pluginConfig);
753
674
  const autoActivate = isAutoActivateEnabled(pluginConfig);
754
675
  if (defaultMaskId && autoActivate && pluginState.maskLoader) {
@@ -766,28 +687,17 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
766
687
  pluginLog(client, 'warn', `Failed to auto-activate default mask: ${e}`);
767
688
  }
768
689
  }
769
- // ==========================================================================
770
- // 5. Helper functions for tool factories
771
- // ==========================================================================
772
690
  const getActiveMask = () => pluginState.activeMask;
773
691
  const setActiveMask = (mask) => {
774
692
  pluginState.activeMask = mask;
775
693
  };
776
- // ==========================================================================
777
- // 6. Conditional tool registration (oh-my-opencode pattern)
778
- // ==========================================================================
779
694
  const isToolActive = (toolName) => isToolEnabled(pluginConfig, toolName);
780
- // Helper to ensure tool arguments are compatible with opencode's expected format.
781
- // opencode expects a ZodRawShape (raw object), NOT a ZodObject instance.
782
- // Zod 4: schema.def.shape, Zod 3: schema._def.shape()
783
695
  const wrapSchema = (schema) => {
784
696
  if (!schema || typeof schema !== 'object')
785
697
  return schema;
786
- // Zod 4 — def.shape is a plain object
787
698
  if (schema.def && typeof schema.def === 'object' && schema.type === 'object' && schema.def.shape && typeof schema.def.shape === 'object') {
788
699
  return schema.def.shape;
789
700
  }
790
- // Zod 3 — _def.shape() returns a plain object
791
701
  if (schema._def && typeof schema._def.shape === 'function') {
792
702
  return schema._def.shape();
793
703
  }
@@ -821,7 +731,6 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
821
731
  tool.args = wrapSchema(tool.args);
822
732
  tools.maskweaver_status = tool;
823
733
  }
824
- // Memory tools
825
734
  if (isToolActive('memory_search')) {
826
735
  const memorySearchTool = createMemorySearchTool();
827
736
  tools.memory_search = {
@@ -854,7 +763,6 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
854
763
  execute: (args) => memoryIndexerTool.execute(args, { worktree: directory }),
855
764
  };
856
765
  }
857
- // Context tool
858
766
  if (isToolActive('context')) {
859
767
  const contextTool = createContextTool();
860
768
  tools.context = {
@@ -863,7 +771,6 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
863
771
  execute: (args) => contextTool.execute(args, { worktree: directory }),
864
772
  };
865
773
  }
866
- // Retrospect tool
867
774
  if (isToolActive('retrospect')) {
868
775
  const retrospectTool = createRetrospectTool();
869
776
  tools.retrospect = {
@@ -872,7 +779,6 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
872
779
  execute: (args) => retrospectTool.execute(args, { worktree: directory }),
873
780
  };
874
781
  }
875
- // Mask save tool
876
782
  if (isToolActive('mask_save')) {
877
783
  const maskSaveTool = createMaskSaveTool();
878
784
  tools.mask_save = {
@@ -881,7 +787,6 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
881
787
  execute: (args) => maskSaveTool.execute(args, { worktree: directory }),
882
788
  };
883
789
  }
884
- // Squad tool (multi-agent collaboration)
885
790
  if (isToolActive('squad')) {
886
791
  const squadTool = createSquadTool();
887
792
  tools.squad = {
@@ -890,7 +795,6 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
890
795
  execute: (args) => squadTool.execute(args, { worktree: directory }),
891
796
  };
892
797
  }
893
- // Weave tool (phase-driven development workflow)
894
798
  if (isToolActive('weave')) {
895
799
  const weaveTool = createWeaveTool();
896
800
  tools.weave = {
@@ -899,7 +803,6 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
899
803
  execute: (args) => weaveTool.execute(args, { worktree: directory }),
900
804
  };
901
805
  }
902
- // Slashcommand tool (handles /weave etc. on first run without restart)
903
806
  if (isToolActive('slashcommand')) {
904
807
  const slashcommandTool = createSlashcommandTool(getAssetsDir());
905
808
  tools.slashcommand = {
@@ -908,22 +811,7 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
908
811
  execute: (args) => slashcommandTool.execute(args, { worktree: directory }),
909
812
  };
910
813
  }
911
- // ==========================================================================
912
- // 8. Agents are loaded from .opencode/agents/*.md files by OpenCode's
913
- // filesystem-based agent loader (see config/agent.ts:110-140).
914
- // installAssets() in step 2 copies agent .md files so they are picked up.
915
- // The 'agent' property in Hooks is NOT consumed by OpenCode — confirmed
916
- // by source analysis (packages/opencode/src/plugin/index.ts:92-103).
917
- // ==========================================================================
918
- // ==========================================================================
919
- // 9. Return plugin hooks (official OpenCode Hooks interface only)
920
- // Note: Agents are registered via .opencode/agents/*.md files (installed by
921
- // installAssets()), NOT via the plugin return. The Hooks type does not
922
- // include 'agent' — OpenCode loads agents from the filesystem exclusively.
923
- // ==========================================================================
924
814
  return {
925
- // Agent registration handled via .opencode/agents/*.md files (see installAssets)
926
- // System prompt transform - inject active mask
927
815
  'experimental.chat.system.transform': async (_input, output) => {
928
816
  if (state?.activeMask) {
929
817
  const maskPrompt = `<ACTIVE_PERSONA>
@@ -934,11 +822,8 @@ ${buildRichPrompt(state.activeMask)}
934
822
  (output.system ||= []).push(maskPrompt);
935
823
  }
936
824
  },
937
- // Conditional tools
938
825
  tool: tools,
939
- // Event hooks (oh-my-opencode pattern)
940
826
  event: async ({ event }) => {
941
- // Session created - log available masks
942
827
  if (event.type === 'session.created') {
943
828
  pluginState.currentSessionID = getSessionId(event);
944
829
  if (pluginState.maskLoader && verbose) {
@@ -948,11 +833,9 @@ ${buildRichPrompt(state.activeMask)}
948
833
  pluginLog(client, 'info', `Session started - ${masks.length} masks available across ${categories.length} categories`);
949
834
  }
950
835
  catch (_e) {
951
- // Ignore errors
952
836
  }
953
837
  }
954
838
  }
955
- // Session idle - generation completed
956
839
  if (event.type === 'session.idle') {
957
840
  const idleSessionID = getSessionId(event);
958
841
  const isCurrentSession = !idleSessionID ||
@@ -962,7 +845,6 @@ ${buildRichPrompt(state.activeMask)}
962
845
  playCompletionSound(pluginState.config);
963
846
  }
964
847
  }
965
- // Session deleted - cleanup
966
848
  if (event.type === 'session.deleted') {
967
849
  const deletedSessionID = getSessionId(event);
968
850
  if (!deletedSessionID || deletedSessionID === pluginState.currentSessionID) {
@@ -977,11 +859,7 @@ ${buildRichPrompt(state.activeMask)}
977
859
  }
978
860
  }
979
861
  },
980
- // Config hook - allows plugins to modify opencode configuration
981
862
  config: async (config) => {
982
- // opencode discovers slash commands from config.command and command files.
983
- // installAssets() writes command files for subsequent starts, while this
984
- // hook makes the direct /build command visible on the current plugin load.
985
863
  config.command ||= {};
986
864
  config.command.build ||= {
987
865
  description: 'Run or manage the Maskweaver autonomous build loop',
@@ -1,9 +1,3 @@
1
- /**
2
- * Command Registry for Weave Tool
3
- *
4
- * Loads commands.json and provides alias resolution, deprecation warnings,
5
- * and dynamic description/help generation.
6
- */
7
1
  export interface CommandArg {
8
2
  name: string;
9
3
  type: 'string' | 'boolean' | 'number' | 'enum';
@@ -1,14 +1,5 @@
1
- /**
2
- * Command Registry for Weave Tool
3
- *
4
- * Loads commands.json and provides alias resolution, deprecation warnings,
5
- * and dynamic description/help generation.
6
- */
7
1
  import * as fs from 'node:fs';
8
2
  import * as path from 'node:path';
9
- // ============================================================================
10
- // Inline Default (fail-safe fallback when commands.json cannot be loaded)
11
- // ============================================================================
12
3
  const INLINE_DEFAULT = {
13
4
  schemaVersion: '1.0',
14
5
  lastUpdated: '2026-04-29',
@@ -246,13 +237,9 @@ const INLINE_DEFAULT = {
246
237
  },
247
238
  ],
248
239
  };
249
- // ============================================================================
250
- // Resolution
251
- // ============================================================================
252
240
  let _cached = null;
253
241
  let _cachePath = null;
254
242
  function resolveCommandsJsonPath() {
255
- // Try relative to dist first, then src (for dev)
256
243
  const candidates = [
257
244
  path.join(process.cwd(), 'assets', 'commands', 'meta', 'commands.json'),
258
245
  path.join(process.cwd(), 'dist', 'assets', 'commands', 'meta', 'commands.json'),
@@ -279,7 +266,6 @@ export function loadCommandsJson() {
279
266
  return parsed;
280
267
  }
281
268
  catch {
282
- // fall through to inline default
283
269
  }
284
270
  }
285
271
  _cached = INLINE_DEFAULT;