maskweaver 0.7.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 (284) hide show
  1. package/assets/agents/dummy-human.md +31 -0
  2. package/assets/agents/dummy-template.md +57 -0
  3. package/assets/agents/mask-master.md +225 -0
  4. package/assets/masks/ai-ml/andrew-ng.yaml +207 -0
  5. package/assets/masks/architecture/jeff-dean.yaml +208 -0
  6. package/assets/masks/index.json +65 -0
  7. package/assets/masks/software-engineering/dan-abramov.yaml +188 -0
  8. package/assets/masks/software-engineering/kent-beck.yaml +191 -0
  9. package/assets/masks/software-engineering/linus-torvalds.yaml +152 -0
  10. package/assets/masks/software-engineering/martin-fowler.yaml +173 -0
  11. package/dist/cli/install.d.ts +11 -0
  12. package/dist/cli/install.d.ts.map +1 -0
  13. package/dist/cli/install.js +299 -0
  14. package/dist/cli/install.js.map +1 -0
  15. package/dist/context/config.d.ts +38 -0
  16. package/dist/context/config.d.ts.map +1 -0
  17. package/dist/context/config.js +55 -0
  18. package/dist/context/config.js.map +1 -0
  19. package/dist/context/feature.d.ts +49 -0
  20. package/dist/context/feature.d.ts.map +1 -0
  21. package/dist/context/feature.js +290 -0
  22. package/dist/context/feature.js.map +1 -0
  23. package/dist/context/files.d.ts +17 -0
  24. package/dist/context/files.d.ts.map +1 -0
  25. package/dist/context/files.js +50 -0
  26. package/dist/context/files.js.map +1 -0
  27. package/dist/context/index.d.ts +14 -0
  28. package/dist/context/index.d.ts.map +1 -0
  29. package/dist/context/index.js +18 -0
  30. package/dist/context/index.js.map +1 -0
  31. package/dist/context/project.d.ts +26 -0
  32. package/dist/context/project.d.ts.map +1 -0
  33. package/dist/context/project.js +95 -0
  34. package/dist/context/project.js.map +1 -0
  35. package/dist/context/types.d.ts +72 -0
  36. package/dist/context/types.d.ts.map +1 -0
  37. package/dist/context/types.js +14 -0
  38. package/dist/context/types.js.map +1 -0
  39. package/dist/context/utils.d.ts +22 -0
  40. package/dist/context/utils.d.ts.map +1 -0
  41. package/dist/context/utils.js +40 -0
  42. package/dist/context/utils.js.map +1 -0
  43. package/dist/core/engine/promptBuilder.d.ts +32 -0
  44. package/dist/core/engine/promptBuilder.d.ts.map +1 -0
  45. package/dist/core/engine/promptBuilder.js +117 -0
  46. package/dist/core/engine/promptBuilder.js.map +1 -0
  47. package/dist/core/index.d.ts +11 -0
  48. package/dist/core/index.d.ts.map +1 -0
  49. package/dist/core/index.js +13 -0
  50. package/dist/core/index.js.map +1 -0
  51. package/dist/core/loader/MaskLoader.d.ts +47 -0
  52. package/dist/core/loader/MaskLoader.d.ts.map +1 -0
  53. package/dist/core/loader/MaskLoader.js +132 -0
  54. package/dist/core/loader/MaskLoader.js.map +1 -0
  55. package/dist/core/schema/types.d.ts +128 -0
  56. package/dist/core/schema/types.d.ts.map +1 -0
  57. package/dist/core/schema/types.js +8 -0
  58. package/dist/core/schema/types.js.map +1 -0
  59. package/dist/core/schema/validator.d.ts +290 -0
  60. package/dist/core/schema/validator.d.ts.map +1 -0
  61. package/dist/core/schema/validator.js +105 -0
  62. package/dist/core/schema/validator.js.map +1 -0
  63. package/dist/i18n/index.d.ts +33 -0
  64. package/dist/i18n/index.d.ts.map +1 -0
  65. package/dist/i18n/index.js +57 -0
  66. package/dist/i18n/index.js.map +1 -0
  67. package/dist/i18n/locales/en.json +16 -0
  68. package/dist/index.d.ts +17 -0
  69. package/dist/index.d.ts.map +1 -0
  70. package/dist/index.js +29 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/memory/chunking.d.ts +35 -0
  73. package/dist/memory/chunking.d.ts.map +1 -0
  74. package/dist/memory/chunking.js +168 -0
  75. package/dist/memory/chunking.js.map +1 -0
  76. package/dist/memory/core.d.ts +73 -0
  77. package/dist/memory/core.d.ts.map +1 -0
  78. package/dist/memory/core.js +186 -0
  79. package/dist/memory/core.js.map +1 -0
  80. package/dist/memory/index.d.ts +21 -0
  81. package/dist/memory/index.d.ts.map +1 -0
  82. package/dist/memory/index.js +22 -0
  83. package/dist/memory/index.js.map +1 -0
  84. package/dist/memory/indexer.d.ts +37 -0
  85. package/dist/memory/indexer.d.ts.map +1 -0
  86. package/dist/memory/indexer.js +162 -0
  87. package/dist/memory/indexer.js.map +1 -0
  88. package/dist/memory/providers/examples.d.ts +17 -0
  89. package/dist/memory/providers/examples.d.ts.map +1 -0
  90. package/dist/memory/providers/examples.js +271 -0
  91. package/dist/memory/providers/examples.js.map +1 -0
  92. package/dist/memory/providers/factory.d.ts +49 -0
  93. package/dist/memory/providers/factory.d.ts.map +1 -0
  94. package/dist/memory/providers/factory.js +111 -0
  95. package/dist/memory/providers/factory.js.map +1 -0
  96. package/dist/memory/providers/index.d.ts +34 -0
  97. package/dist/memory/providers/index.d.ts.map +1 -0
  98. package/dist/memory/providers/index.js +35 -0
  99. package/dist/memory/providers/index.js.map +1 -0
  100. package/dist/memory/providers/ollama.d.ts +18 -0
  101. package/dist/memory/providers/ollama.d.ts.map +1 -0
  102. package/dist/memory/providers/ollama.js +68 -0
  103. package/dist/memory/providers/ollama.js.map +1 -0
  104. package/dist/memory/providers/openai.d.ts +21 -0
  105. package/dist/memory/providers/openai.d.ts.map +1 -0
  106. package/dist/memory/providers/openai.js +91 -0
  107. package/dist/memory/providers/openai.js.map +1 -0
  108. package/dist/memory/providers/openrouter.d.ts +22 -0
  109. package/dist/memory/providers/openrouter.d.ts.map +1 -0
  110. package/dist/memory/providers/openrouter.js +89 -0
  111. package/dist/memory/providers/openrouter.js.map +1 -0
  112. package/dist/memory/providers/text-only.d.ts +20 -0
  113. package/dist/memory/providers/text-only.d.ts.map +1 -0
  114. package/dist/memory/providers/text-only.js +35 -0
  115. package/dist/memory/providers/text-only.js.map +1 -0
  116. package/dist/memory/providers/types.d.ts +63 -0
  117. package/dist/memory/providers/types.d.ts.map +1 -0
  118. package/dist/memory/providers/types.js +9 -0
  119. package/dist/memory/providers/types.js.map +1 -0
  120. package/dist/memory/providers/voyage.d.ts +39 -0
  121. package/dist/memory/providers/voyage.d.ts.map +1 -0
  122. package/dist/memory/providers/voyage.js +127 -0
  123. package/dist/memory/providers/voyage.js.map +1 -0
  124. package/dist/memory/search/hybrid.d.ts +12 -0
  125. package/dist/memory/search/hybrid.d.ts.map +1 -0
  126. package/dist/memory/search/hybrid.js +59 -0
  127. package/dist/memory/search/hybrid.js.map +1 -0
  128. package/dist/memory/store/sqlite.d.ts +86 -0
  129. package/dist/memory/store/sqlite.d.ts.map +1 -0
  130. package/dist/memory/store/sqlite.js +390 -0
  131. package/dist/memory/store/sqlite.js.map +1 -0
  132. package/dist/plugin/config/index.d.ts +148 -0
  133. package/dist/plugin/config/index.d.ts.map +1 -0
  134. package/dist/plugin/config/index.js +236 -0
  135. package/dist/plugin/config/index.js.map +1 -0
  136. package/dist/plugin/index.d.ts +19 -0
  137. package/dist/plugin/index.d.ts.map +1 -0
  138. package/dist/plugin/index.js +811 -0
  139. package/dist/plugin/index.js.map +1 -0
  140. package/dist/plugin/tools/context.d.ts +36 -0
  141. package/dist/plugin/tools/context.d.ts.map +1 -0
  142. package/dist/plugin/tools/context.js +332 -0
  143. package/dist/plugin/tools/context.js.map +1 -0
  144. package/dist/plugin/tools/maskSave.d.ts +6 -0
  145. package/dist/plugin/tools/maskSave.d.ts.map +1 -0
  146. package/dist/plugin/tools/maskSave.js +42 -0
  147. package/dist/plugin/tools/maskSave.js.map +1 -0
  148. package/dist/plugin/tools/memoryGet.d.ts +21 -0
  149. package/dist/plugin/tools/memoryGet.d.ts.map +1 -0
  150. package/dist/plugin/tools/memoryGet.js +40 -0
  151. package/dist/plugin/tools/memoryGet.js.map +1 -0
  152. package/dist/plugin/tools/memoryIndexer.d.ts +6 -0
  153. package/dist/plugin/tools/memoryIndexer.d.ts.map +1 -0
  154. package/dist/plugin/tools/memoryIndexer.js +75 -0
  155. package/dist/plugin/tools/memoryIndexer.js.map +1 -0
  156. package/dist/plugin/tools/memorySearch.d.ts +74 -0
  157. package/dist/plugin/tools/memorySearch.d.ts.map +1 -0
  158. package/dist/plugin/tools/memorySearch.js +172 -0
  159. package/dist/plugin/tools/memorySearch.js.map +1 -0
  160. package/dist/plugin/tools/memoryWrite.d.ts +11 -0
  161. package/dist/plugin/tools/memoryWrite.d.ts.map +1 -0
  162. package/dist/plugin/tools/memoryWrite.js +161 -0
  163. package/dist/plugin/tools/memoryWrite.js.map +1 -0
  164. package/dist/plugin/tools/retrospect.d.ts +6 -0
  165. package/dist/plugin/tools/retrospect.d.ts.map +1 -0
  166. package/dist/plugin/tools/retrospect.js +46 -0
  167. package/dist/plugin/tools/retrospect.js.map +1 -0
  168. package/dist/plugin/types.d.ts +34 -0
  169. package/dist/plugin/types.d.ts.map +1 -0
  170. package/dist/plugin/types.js +7 -0
  171. package/dist/plugin/types.js.map +1 -0
  172. package/dist/retrospect/index.d.ts +14 -0
  173. package/dist/retrospect/index.d.ts.map +1 -0
  174. package/dist/retrospect/index.js +13 -0
  175. package/dist/retrospect/index.js.map +1 -0
  176. package/dist/retrospect/mask-save.d.ts +31 -0
  177. package/dist/retrospect/mask-save.d.ts.map +1 -0
  178. package/dist/retrospect/mask-save.js +263 -0
  179. package/dist/retrospect/mask-save.js.map +1 -0
  180. package/dist/retrospect/retrospect.d.ts +24 -0
  181. package/dist/retrospect/retrospect.d.ts.map +1 -0
  182. package/dist/retrospect/retrospect.js +165 -0
  183. package/dist/retrospect/retrospect.js.map +1 -0
  184. package/dist/retrospect/strategies/base.d.ts +20 -0
  185. package/dist/retrospect/strategies/base.d.ts.map +1 -0
  186. package/dist/retrospect/strategies/base.js +9 -0
  187. package/dist/retrospect/strategies/base.js.map +1 -0
  188. package/dist/retrospect/strategies/deep.d.ts +18 -0
  189. package/dist/retrospect/strategies/deep.d.ts.map +1 -0
  190. package/dist/retrospect/strategies/deep.js +105 -0
  191. package/dist/retrospect/strategies/deep.js.map +1 -0
  192. package/dist/retrospect/strategies/index.d.ts +20 -0
  193. package/dist/retrospect/strategies/index.d.ts.map +1 -0
  194. package/dist/retrospect/strategies/index.js +27 -0
  195. package/dist/retrospect/strategies/index.js.map +1 -0
  196. package/dist/retrospect/strategies/quick.d.ts +18 -0
  197. package/dist/retrospect/strategies/quick.d.ts.map +1 -0
  198. package/dist/retrospect/strategies/quick.js +55 -0
  199. package/dist/retrospect/strategies/quick.js.map +1 -0
  200. package/dist/retrospect/strategies/standard.d.ts +18 -0
  201. package/dist/retrospect/strategies/standard.d.ts.map +1 -0
  202. package/dist/retrospect/strategies/standard.js +66 -0
  203. package/dist/retrospect/strategies/standard.js.map +1 -0
  204. package/dist/retrospect/types.d.ts +34 -0
  205. package/dist/retrospect/types.d.ts.map +1 -0
  206. package/dist/retrospect/types.js +9 -0
  207. package/dist/retrospect/types.js.map +1 -0
  208. package/dist/shared/config.d.ts +130 -0
  209. package/dist/shared/config.d.ts.map +1 -0
  210. package/dist/shared/config.js +12 -0
  211. package/dist/shared/config.js.map +1 -0
  212. package/dist/shared/errors.d.ts +36 -0
  213. package/dist/shared/errors.d.ts.map +1 -0
  214. package/dist/shared/errors.js +57 -0
  215. package/dist/shared/errors.js.map +1 -0
  216. package/dist/shared/index.d.ts +10 -0
  217. package/dist/shared/index.d.ts.map +1 -0
  218. package/dist/shared/index.js +9 -0
  219. package/dist/shared/index.js.map +1 -0
  220. package/dist/shared/types.d.ts +34 -0
  221. package/dist/shared/types.d.ts.map +1 -0
  222. package/dist/shared/types.js +5 -0
  223. package/dist/shared/types.js.map +1 -0
  224. package/dist/shared-context/index.d.ts +11 -0
  225. package/dist/shared-context/index.d.ts.map +1 -0
  226. package/dist/shared-context/index.js +16 -0
  227. package/dist/shared-context/index.js.map +1 -0
  228. package/dist/shared-context/logger.d.ts +10 -0
  229. package/dist/shared-context/logger.d.ts.map +1 -0
  230. package/dist/shared-context/logger.js +28 -0
  231. package/dist/shared-context/logger.js.map +1 -0
  232. package/dist/shared-context/session.d.ts +23 -0
  233. package/dist/shared-context/session.d.ts.map +1 -0
  234. package/dist/shared-context/session.js +34 -0
  235. package/dist/shared-context/session.js.map +1 -0
  236. package/dist/shared-context/squad.d.ts +30 -0
  237. package/dist/shared-context/squad.d.ts.map +1 -0
  238. package/dist/shared-context/squad.js +66 -0
  239. package/dist/shared-context/squad.js.map +1 -0
  240. package/dist/shared-context/storage.d.ts +25 -0
  241. package/dist/shared-context/storage.d.ts.map +1 -0
  242. package/dist/shared-context/storage.js +66 -0
  243. package/dist/shared-context/storage.js.map +1 -0
  244. package/dist/shared-context/types.d.ts +107 -0
  245. package/dist/shared-context/types.d.ts.map +1 -0
  246. package/dist/shared-context/types.js +18 -0
  247. package/dist/shared-context/types.js.map +1 -0
  248. package/dist/verify/budget.d.ts +45 -0
  249. package/dist/verify/budget.d.ts.map +1 -0
  250. package/dist/verify/budget.js +89 -0
  251. package/dist/verify/budget.js.map +1 -0
  252. package/dist/verify/critical-files.d.ts +22 -0
  253. package/dist/verify/critical-files.d.ts.map +1 -0
  254. package/dist/verify/critical-files.js +130 -0
  255. package/dist/verify/critical-files.js.map +1 -0
  256. package/dist/verify/escalation.d.ts +27 -0
  257. package/dist/verify/escalation.d.ts.map +1 -0
  258. package/dist/verify/escalation.js +68 -0
  259. package/dist/verify/escalation.js.map +1 -0
  260. package/dist/verify/index.d.ts +13 -0
  261. package/dist/verify/index.d.ts.map +1 -0
  262. package/dist/verify/index.js +18 -0
  263. package/dist/verify/index.js.map +1 -0
  264. package/dist/verify/prompts.d.ts +27 -0
  265. package/dist/verify/prompts.d.ts.map +1 -0
  266. package/dist/verify/prompts.js +158 -0
  267. package/dist/verify/prompts.js.map +1 -0
  268. package/dist/verify/types.d.ts +80 -0
  269. package/dist/verify/types.d.ts.map +1 -0
  270. package/dist/verify/types.js +22 -0
  271. package/dist/verify/types.js.map +1 -0
  272. package/dist/verify/verifier.d.ts +47 -0
  273. package/dist/verify/verifier.d.ts.map +1 -0
  274. package/dist/verify/verifier.js +180 -0
  275. package/dist/verify/verifier.js.map +1 -0
  276. package/masks/ai-ml/andrew-ng.yaml +207 -0
  277. package/masks/architecture/jeff-dean.yaml +208 -0
  278. package/masks/index.json +65 -0
  279. package/masks/orchestration/squad-operator.yaml +205 -0
  280. package/masks/software-engineering/dan-abramov.yaml +188 -0
  281. package/masks/software-engineering/kent-beck.yaml +191 -0
  282. package/masks/software-engineering/linus-torvalds.yaml +152 -0
  283. package/masks/software-engineering/martin-fowler.yaml +173 -0
  284. package/package.json +111 -0
@@ -0,0 +1,811 @@
1
+ /**
2
+ * Maskweaver Plugin for opencode
3
+ *
4
+ * v0.6.0 - Memory, Context, and Retrospect tools integration
5
+ *
6
+ * Key features:
7
+ * - Configuration-driven tool activation/deactivation
8
+ * - Auto-activation of default masks
9
+ * - Agent configuration overrides
10
+ * - Event-based lifecycle hooks
11
+ * - Memory and context management tools
12
+ * - Clean plugin architecture
13
+ *
14
+ * Based on oh-my-opencode plugin development patterns.
15
+ */
16
+ import * as fs from 'node:fs';
17
+ import * as path from 'node:path';
18
+ import * as os from 'node:os';
19
+ import { fileURLToPath } from 'node:url';
20
+ import { z } from 'zod';
21
+ import { loadPluginConfig, isMaskEnabled, isToolEnabled, getDefaultMask, isAutoActivateEnabled, getAgentOverride, isVerboseLoggingEnabled, validateConfig, } from './config';
22
+ // New tool imports
23
+ import { createMemorySearchTool } from './tools/memorySearch.js';
24
+ import { createMemoryWriteTool } from './tools/memoryWrite.js';
25
+ import { createMemoryGetTool } from './tools/memoryGet.js';
26
+ import { createMemoryIndexerTool } from './tools/memoryIndexer.js';
27
+ import { createContextTool } from './tools/context.js';
28
+ import { createRetrospectTool } from './tools/retrospect.js';
29
+ import { createMaskSaveTool } from './tools/maskSave.js';
30
+ function getAssetsDir() {
31
+ // In ESM, use import.meta.url to find the assets directory
32
+ // When installed via npm: node_modules/@maskweaver/plugin/dist/index.js -> ../assets
33
+ // When local file: plugins/maskweaver.js -> ./assets (same directory)
34
+ try {
35
+ const __filename = fileURLToPath(import.meta.url);
36
+ const __dirname = path.dirname(__filename);
37
+ // First try: assets as sibling (npm package structure: dist/../assets)
38
+ const npmAssets = path.join(__dirname, '..', 'assets');
39
+ if (fs.existsSync(npmAssets)) {
40
+ return npmAssets;
41
+ }
42
+ // Second try: assets as subdirectory (local file: plugins/assets)
43
+ const localAssets = path.join(__dirname, 'assets');
44
+ if (fs.existsSync(localAssets)) {
45
+ return localAssets;
46
+ }
47
+ // Fallback to npm structure
48
+ return npmAssets;
49
+ }
50
+ catch {
51
+ // Fallback for CommonJS or other environments
52
+ return path.join(__dirname, '..', 'assets');
53
+ }
54
+ }
55
+ function copyDirRecursive(src, dest, result) {
56
+ if (!fs.existsSync(src))
57
+ return;
58
+ if (!fs.existsSync(dest)) {
59
+ fs.mkdirSync(dest, { recursive: true });
60
+ }
61
+ const entries = fs.readdirSync(src, { withFileTypes: true });
62
+ for (const entry of entries) {
63
+ const srcPath = path.join(src, entry.name);
64
+ const destPath = path.join(dest, entry.name);
65
+ if (entry.isDirectory()) {
66
+ copyDirRecursive(srcPath, destPath, result);
67
+ }
68
+ else {
69
+ // Only copy if destination doesn't exist (don't overwrite user customizations)
70
+ if (!fs.existsSync(destPath)) {
71
+ try {
72
+ fs.copyFileSync(srcPath, destPath);
73
+ result.installed.push(destPath);
74
+ }
75
+ catch (e) {
76
+ result.errors.push(`Failed to copy ${entry.name}: ${e}`);
77
+ }
78
+ }
79
+ else {
80
+ result.skipped.push(destPath);
81
+ }
82
+ }
83
+ }
84
+ }
85
+ function installAssets(projectDir) {
86
+ const result = {
87
+ installed: [],
88
+ skipped: [],
89
+ errors: [],
90
+ };
91
+ const assetsDir = getAssetsDir();
92
+ const opencodeDir = path.join(projectDir, '.opencode');
93
+ // Ensure .opencode directory exists
94
+ if (!fs.existsSync(opencodeDir)) {
95
+ fs.mkdirSync(opencodeDir, { recursive: true });
96
+ }
97
+ // Install agents
98
+ const agentsSrc = path.join(assetsDir, 'agents');
99
+ const agentsDest = path.join(opencodeDir, 'agents');
100
+ copyDirRecursive(agentsSrc, agentsDest, result);
101
+ // Install masks
102
+ const masksSrc = path.join(assetsDir, 'masks');
103
+ const masksDest = path.join(opencodeDir, 'masks');
104
+ copyDirRecursive(masksSrc, masksDest, result);
105
+ // Install commands (if any)
106
+ const commandsSrc = path.join(assetsDir, 'commands');
107
+ const commandsDest = path.join(opencodeDir, 'commands');
108
+ if (fs.existsSync(commandsSrc)) {
109
+ copyDirRecursive(commandsSrc, commandsDest, result);
110
+ }
111
+ return result;
112
+ }
113
+ // ============================================================================
114
+ // Simple YAML Parser
115
+ // ============================================================================
116
+ function parseSimpleYaml(content) {
117
+ const lines = content.split('\n');
118
+ const result = {};
119
+ const stack = [
120
+ { indent: -2, obj: result },
121
+ ];
122
+ let currentArrayKey = undefined;
123
+ let currentArray = [];
124
+ let multilineKey = null;
125
+ let multilineValue = [];
126
+ let multilineIndent = 0;
127
+ for (let i = 0; i < lines.length; i++) {
128
+ const line = lines[i];
129
+ const trimmed = line.trimStart();
130
+ if (!trimmed || trimmed.startsWith('#')) {
131
+ if (multilineKey)
132
+ multilineValue.push('');
133
+ continue;
134
+ }
135
+ const indent = line.length - trimmed.length;
136
+ if (multilineKey) {
137
+ if (indent > multilineIndent || (indent === multilineIndent && !trimmed.includes(':'))) {
138
+ multilineValue.push(trimmed);
139
+ continue;
140
+ }
141
+ else {
142
+ const parent = stack[stack.length - 1];
143
+ parent.obj[multilineKey] = multilineValue.join('\n').trim();
144
+ multilineKey = null;
145
+ multilineValue = [];
146
+ }
147
+ }
148
+ if (trimmed.startsWith('- ')) {
149
+ const value = trimmed.slice(2).trim();
150
+ while (stack.length > 1 && stack[stack.length - 1].indent >= indent) {
151
+ const popped = stack.pop();
152
+ if (popped.key && currentArrayKey === popped.key) {
153
+ const parent = stack[stack.length - 1];
154
+ parent.obj[popped.key] = currentArray;
155
+ currentArrayKey = undefined;
156
+ currentArray = [];
157
+ }
158
+ }
159
+ if (value.includes(':')) {
160
+ const colonIdx = value.indexOf(':');
161
+ const objKey = value.slice(0, colonIdx).trim();
162
+ const objVal = value.slice(colonIdx + 1).trim();
163
+ const arrayItem = {};
164
+ if (objVal)
165
+ arrayItem[objKey] = parseValue(objVal);
166
+ let j = i + 1;
167
+ const itemIndent = indent + 2;
168
+ while (j < lines.length) {
169
+ const nextLine = lines[j];
170
+ const nextTrimmed = nextLine.trimStart();
171
+ const nextIndent = nextLine.length - nextTrimmed.length;
172
+ if (!nextTrimmed || nextTrimmed.startsWith('#')) {
173
+ j++;
174
+ continue;
175
+ }
176
+ if (nextIndent < itemIndent || nextTrimmed.startsWith('- '))
177
+ break;
178
+ if (nextTrimmed.includes(':')) {
179
+ const nColonIdx = nextTrimmed.indexOf(':');
180
+ const nKey = nextTrimmed.slice(0, nColonIdx).trim();
181
+ const nVal = nextTrimmed.slice(nColonIdx + 1).trim();
182
+ if (nVal)
183
+ arrayItem[nKey] = parseValue(nVal);
184
+ }
185
+ j++;
186
+ }
187
+ i = j - 1;
188
+ currentArray.push(arrayItem);
189
+ }
190
+ else {
191
+ currentArray.push(parseValue(value));
192
+ }
193
+ if (!currentArrayKey) {
194
+ for (let s = stack.length - 1; s >= 0; s--) {
195
+ if (stack[s].key) {
196
+ currentArrayKey = stack[s].key;
197
+ break;
198
+ }
199
+ }
200
+ }
201
+ continue;
202
+ }
203
+ if (trimmed.includes(':')) {
204
+ while (stack.length > 1 && stack[stack.length - 1].indent >= indent) {
205
+ const popped = stack.pop();
206
+ if (popped.key && currentArrayKey === popped.key) {
207
+ const parent = stack[stack.length - 1];
208
+ parent.obj[popped.key] = currentArray;
209
+ currentArrayKey = undefined;
210
+ currentArray = [];
211
+ }
212
+ }
213
+ if (currentArrayKey) {
214
+ const parent = stack[stack.length - 1];
215
+ parent.obj[currentArrayKey] = currentArray;
216
+ currentArrayKey = undefined;
217
+ currentArray = [];
218
+ }
219
+ const colonIdx = trimmed.indexOf(':');
220
+ const key = trimmed.slice(0, colonIdx).trim();
221
+ const value = trimmed.slice(colonIdx + 1).trim();
222
+ const parent = stack[stack.length - 1];
223
+ if (!value) {
224
+ const nextLine = lines[i + 1];
225
+ if (nextLine && nextLine.trimStart().startsWith('|')) {
226
+ multilineKey = key;
227
+ multilineIndent = indent;
228
+ i++;
229
+ continue;
230
+ }
231
+ const newObj = {};
232
+ parent.obj[key] = newObj;
233
+ stack.push({ indent, obj: newObj, key });
234
+ }
235
+ else if (value === '|' || value === '>') {
236
+ multilineKey = key;
237
+ multilineIndent = indent;
238
+ }
239
+ else {
240
+ parent.obj[key] = parseValue(value);
241
+ }
242
+ }
243
+ }
244
+ if (multilineKey) {
245
+ const parent = stack[stack.length - 1];
246
+ parent.obj[multilineKey] = multilineValue.join('\n').trim();
247
+ }
248
+ if (currentArrayKey) {
249
+ const parent = stack[stack.length - 1];
250
+ parent.obj[currentArrayKey] = currentArray;
251
+ }
252
+ return result;
253
+ }
254
+ function parseValue(value) {
255
+ if (!value)
256
+ return '';
257
+ if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
258
+ return value.slice(1, -1);
259
+ }
260
+ if (value === 'true')
261
+ return true;
262
+ if (value === 'false')
263
+ return false;
264
+ if (value === 'null' || value === '~')
265
+ return null;
266
+ const num = Number(value);
267
+ if (!isNaN(num) && value !== '')
268
+ return num;
269
+ return value;
270
+ }
271
+ // ============================================================================
272
+ // Mask Loader
273
+ // ============================================================================
274
+ class MaskLoader {
275
+ masksDir;
276
+ catalog = null;
277
+ cache = new Map();
278
+ config;
279
+ constructor(masksDir, config) {
280
+ this.masksDir = masksDir;
281
+ this.config = config;
282
+ }
283
+ async loadCatalog() {
284
+ if (this.catalog)
285
+ return this.catalog;
286
+ const indexPath = path.join(this.masksDir, 'index.json');
287
+ if (!fs.existsSync(indexPath))
288
+ throw new Error(`Catalog not found: ${indexPath}`);
289
+ const content = fs.readFileSync(indexPath, 'utf-8');
290
+ this.catalog = JSON.parse(content);
291
+ return this.catalog;
292
+ }
293
+ async load(maskId) {
294
+ // Check if mask is disabled in configuration
295
+ if (!isMaskEnabled(this.config, maskId)) {
296
+ return null;
297
+ }
298
+ if (this.cache.has(maskId))
299
+ return this.cache.get(maskId);
300
+ const catalog = await this.loadCatalog();
301
+ let entry = null;
302
+ let categoryId = null;
303
+ for (const [catId, category] of Object.entries(catalog.categories)) {
304
+ const found = category.masks.find(m => m.id === maskId);
305
+ if (found) {
306
+ entry = found;
307
+ categoryId = catId;
308
+ break;
309
+ }
310
+ }
311
+ if (!entry || !categoryId)
312
+ return null;
313
+ const filePath = path.join(this.masksDir, entry.file);
314
+ if (!fs.existsSync(filePath))
315
+ throw new Error(`File not found: ${filePath}`);
316
+ const content = fs.readFileSync(filePath, 'utf-8');
317
+ const parsed = filePath.endsWith('.yaml') || filePath.endsWith('.yml')
318
+ ? parseSimpleYaml(content) : JSON.parse(content);
319
+ const loadedMask = { ...parsed, category: categoryId, filePath };
320
+ this.cache.set(maskId, loadedMask);
321
+ return loadedMask;
322
+ }
323
+ async listAll() {
324
+ const catalog = await this.loadCatalog();
325
+ const result = [];
326
+ for (const [categoryId, category] of Object.entries(catalog.categories)) {
327
+ for (const mask of category.masks) {
328
+ // Filter out disabled masks
329
+ if (isMaskEnabled(this.config, mask.id)) {
330
+ result.push({ ...mask, category: categoryId });
331
+ }
332
+ }
333
+ }
334
+ return result;
335
+ }
336
+ async listCategories() {
337
+ const catalog = await this.loadCatalog();
338
+ return Object.entries(catalog.categories).map(([id, cat]) => {
339
+ // Count only enabled masks
340
+ const enabledMasks = cat.masks.filter(m => isMaskEnabled(this.config, m.id));
341
+ return {
342
+ id,
343
+ name: cat.name,
344
+ description: cat.description,
345
+ count: enabledMasks.length,
346
+ };
347
+ });
348
+ }
349
+ }
350
+ // ============================================================================
351
+ // Prompt Builder
352
+ // ============================================================================
353
+ function buildRichPrompt(mask) {
354
+ const parts = [];
355
+ parts.push(`You are ${mask.profile.name}.`);
356
+ parts.push(`${mask.profile.tagline}`);
357
+ parts.push('');
358
+ parts.push('BACKGROUND:');
359
+ parts.push(mask.profile.background.trim());
360
+ parts.push('');
361
+ parts.push('YOUR EXPERTISE:');
362
+ for (const exp of mask.profile.expertise)
363
+ parts.push(`- ${exp}`);
364
+ parts.push('');
365
+ parts.push('YOUR THINKING STYLE:');
366
+ parts.push(mask.profile.thinkingStyle.trim());
367
+ parts.push('');
368
+ parts.push('INSTRUCTIONS:');
369
+ parts.push(mask.behavior.systemPrompt.trim());
370
+ parts.push('');
371
+ const style = mask.behavior.communicationStyle;
372
+ parts.push('COMMUNICATION STYLE:');
373
+ parts.push(`- Tone: ${style.tone}`);
374
+ parts.push(`- Verbosity: ${style.verbosity}`);
375
+ parts.push(`- Technical depth: ${style.technicalDepth}`);
376
+ parts.push('');
377
+ parts.push('YOUR STRENGTHS:');
378
+ for (const strength of mask.profile.strengths)
379
+ parts.push(`- ${strength}`);
380
+ if (mask.profile.limitations?.length) {
381
+ parts.push('');
382
+ parts.push('ACKNOWLEDGE YOUR LIMITATIONS:');
383
+ for (const limitation of mask.profile.limitations)
384
+ parts.push(`- ${limitation}`);
385
+ }
386
+ if (mask.behavior.signaturePhrases?.length) {
387
+ parts.push('');
388
+ parts.push('PHRASES YOU MIGHT USE:');
389
+ for (const phrase of mask.behavior.signaturePhrases)
390
+ parts.push(`- "${phrase}"`);
391
+ }
392
+ return parts.join('\n');
393
+ }
394
+ // ============================================================================
395
+ // Tool Factory Functions (oh-my-opencode pattern)
396
+ // ============================================================================
397
+ function createListMasksTool(maskLoader, activeMask) {
398
+ return {
399
+ description: 'List all available expert persona masks.',
400
+ args: z.object({
401
+ category: z.string().optional().describe('Filter by category'),
402
+ }),
403
+ async execute(args) {
404
+ try {
405
+ const masks = await maskLoader.listAll();
406
+ const categories = await maskLoader.listCategories();
407
+ let filtered = masks;
408
+ if (args.category) {
409
+ filtered = masks.filter(m => m.category === args.category);
410
+ }
411
+ const lines = [];
412
+ lines.push(`Maskweaver v0.6.0 - ${filtered.length} masks available`);
413
+ const active = activeMask();
414
+ lines.push(`Active mask: ${active?.metadata.id || 'none'}`);
415
+ lines.push('');
416
+ lines.push('Categories:');
417
+ for (const cat of categories) {
418
+ lines.push(` - ${cat.id}: ${cat.name} (${cat.count} masks)`);
419
+ }
420
+ lines.push('');
421
+ lines.push('Masks:');
422
+ for (const mask of filtered) {
423
+ lines.push(` - ${mask.id}: ${mask.name} [${mask.category}]`);
424
+ }
425
+ return lines.join('\n');
426
+ }
427
+ catch (e) {
428
+ return `Error: ${e}`;
429
+ }
430
+ },
431
+ };
432
+ }
433
+ function createSelectMaskTool(maskLoader, activeMask, setActiveMask) {
434
+ return {
435
+ description: 'Select and apply an expert persona mask.',
436
+ args: z.object({
437
+ maskId: z.string().describe('Mask ID (e.g., "kent-beck")'),
438
+ }),
439
+ async execute(args) {
440
+ try {
441
+ const mask = await maskLoader.load(args.maskId);
442
+ if (!mask) {
443
+ const available = await maskLoader.listAll();
444
+ return `Error: Mask "${args.maskId}" not found.\nAvailable: ${available.map(m => m.id).join(', ')}`;
445
+ }
446
+ setActiveMask(mask);
447
+ return `✓ Mask activated: ${mask.profile.name}
448
+
449
+ "${mask.profile.tagline}"
450
+
451
+ Expertise: ${mask.profile.expertise.join(', ')}
452
+
453
+ The mask prompt will be injected into all future messages.`;
454
+ }
455
+ catch (e) {
456
+ return `Error: ${e}`;
457
+ }
458
+ },
459
+ };
460
+ }
461
+ function createDeselectMaskTool(activeMask, setActiveMask) {
462
+ return {
463
+ description: 'Remove the current mask and return to default behavior.',
464
+ args: z.object({}),
465
+ async execute() {
466
+ const prev = activeMask();
467
+ setActiveMask(null);
468
+ if (prev) {
469
+ return `✓ Mask removed: ${prev.profile.name}\nReturned to default behavior.`;
470
+ }
471
+ return 'No mask was active.';
472
+ },
473
+ };
474
+ }
475
+ function createGetMaskPromptTool(maskLoader, activeMask) {
476
+ return {
477
+ description: 'View the full system prompt for a mask.',
478
+ args: z.object({
479
+ maskId: z.string().optional().describe('Mask ID (uses active mask if not specified)'),
480
+ }),
481
+ async execute(args) {
482
+ const maskId = args.maskId || activeMask()?.metadata.id;
483
+ if (!maskId)
484
+ return 'Error: No mask specified and no active mask.';
485
+ try {
486
+ const mask = await maskLoader.load(maskId);
487
+ if (!mask)
488
+ return `Error: Mask "${maskId}" not found.`;
489
+ return `# ${mask.profile.name}\n\n${buildRichPrompt(mask)}`;
490
+ }
491
+ catch (e) {
492
+ return `Error: ${e}`;
493
+ }
494
+ },
495
+ };
496
+ }
497
+ function createMaskweaverStatusTool(maskLoader, masksDir, activeMask) {
498
+ return {
499
+ description: 'Check Maskweaver status.',
500
+ args: z.object({}),
501
+ async execute() {
502
+ let masksCount = 0;
503
+ let categoriesCount = 0;
504
+ if (maskLoader) {
505
+ try {
506
+ const masks = await maskLoader.listAll();
507
+ const categories = await maskLoader.listCategories();
508
+ masksCount = masks.length;
509
+ categoriesCount = categories.length;
510
+ }
511
+ catch (_e) { /* ignore */ }
512
+ }
513
+ const active = activeMask();
514
+ return `Maskweaver v0.6.0
515
+ Masks directory: ${masksDir}
516
+ Available: ${maskLoader ? 'yes' : 'no'}
517
+ Total masks: ${masksCount}
518
+ Categories: ${categoriesCount}
519
+ Active mask: ${active ? `${active.profile.name} (${active.metadata.id})` : 'none'}`;
520
+ },
521
+ };
522
+ }
523
+ let state = null;
524
+ // ============================================================================
525
+ // Plugin (oh-my-opencode pattern)
526
+ // ============================================================================
527
+ export const MaskweaverPlugin = async ({ client, directory }) => {
528
+ // ==========================================================================
529
+ // 1. Load Configuration (oh-my-opencode pattern)
530
+ // ==========================================================================
531
+ const pluginConfig = loadPluginConfig(directory, { client, verbose: false });
532
+ // Validate configuration
533
+ const configErrors = validateConfig(pluginConfig);
534
+ if (configErrors.length > 0) {
535
+ client.app.log({
536
+ service: 'maskweaver',
537
+ level: 'warn',
538
+ message: `Configuration validation errors: ${configErrors.join(', ')}`,
539
+ });
540
+ }
541
+ const verbose = isVerboseLoggingEnabled(pluginConfig);
542
+ // ==========================================================================
543
+ // 2. Auto-install assets on first run
544
+ // ==========================================================================
545
+ const installResult = installAssets(directory);
546
+ if (installResult.installed.length > 0) {
547
+ client.app.log({
548
+ service: 'maskweaver',
549
+ level: 'info',
550
+ message: `Installed ${installResult.installed.length} files to .opencode/ (agents, masks)`,
551
+ });
552
+ }
553
+ if (installResult.errors.length > 0) {
554
+ client.app.log({
555
+ service: 'maskweaver',
556
+ level: 'warn',
557
+ message: `Asset errors: ${installResult.errors.join(', ')}`,
558
+ });
559
+ }
560
+ // ==========================================================================
561
+ // 3. Initialize masks
562
+ // ==========================================================================
563
+ const homeDir = os.homedir();
564
+ const globalMasksDir = path.join(homeDir, '.config', 'opencode', 'masks');
565
+ const projectMasksDir = path.join(directory, '.opencode', 'masks');
566
+ // Priority: project masks > global masks
567
+ const masksDir = fs.existsSync(projectMasksDir) ? projectMasksDir : globalMasksDir;
568
+ state = {
569
+ maskLoader: null,
570
+ activeMask: null,
571
+ masksDir,
572
+ config: pluginConfig,
573
+ };
574
+ // Log plugin loaded
575
+ client.app.log({
576
+ service: 'maskweaver',
577
+ level: 'info',
578
+ message: `Maskweaver plugin loaded v0.6.0 (oh-my-opencode pattern)`,
579
+ });
580
+ if (fs.existsSync(masksDir)) {
581
+ state.maskLoader = new MaskLoader(masksDir, pluginConfig);
582
+ try {
583
+ await state.maskLoader.loadCatalog();
584
+ if (verbose) {
585
+ client.app.log({
586
+ service: 'maskweaver',
587
+ level: 'info',
588
+ message: `Masks found at: ${masksDir}`,
589
+ });
590
+ }
591
+ }
592
+ catch (e) {
593
+ client.app.log({
594
+ service: 'maskweaver',
595
+ level: 'warn',
596
+ message: `Failed to load masks: ${e}`,
597
+ });
598
+ state.maskLoader = null;
599
+ }
600
+ }
601
+ // ==========================================================================
602
+ // 4. Auto-activate default mask (oh-my-opencode pattern)
603
+ // ==========================================================================
604
+ const defaultMaskId = getDefaultMask(pluginConfig);
605
+ const autoActivate = isAutoActivateEnabled(pluginConfig);
606
+ if (defaultMaskId && autoActivate && state.maskLoader) {
607
+ try {
608
+ const defaultMask = await state.maskLoader.load(defaultMaskId);
609
+ if (defaultMask) {
610
+ state.activeMask = defaultMask;
611
+ client.app.log({
612
+ service: 'maskweaver',
613
+ level: 'info',
614
+ message: `Auto-activated default mask: ${defaultMaskId} (${defaultMask.profile.name})`,
615
+ });
616
+ }
617
+ else {
618
+ client.app.log({
619
+ service: 'maskweaver',
620
+ level: 'warn',
621
+ message: `Default mask "${defaultMaskId}" not found or disabled`,
622
+ });
623
+ }
624
+ }
625
+ catch (e) {
626
+ client.app.log({
627
+ service: 'maskweaver',
628
+ level: 'warn',
629
+ message: `Failed to auto-activate default mask: ${e}`,
630
+ });
631
+ }
632
+ }
633
+ // ==========================================================================
634
+ // 5. Helper functions for tool factories
635
+ // ==========================================================================
636
+ const getActiveMask = () => state?.activeMask || null;
637
+ const setActiveMask = (mask) => {
638
+ if (state)
639
+ state.activeMask = mask;
640
+ };
641
+ // ==========================================================================
642
+ // 6. Conditional tool registration (oh-my-opencode pattern)
643
+ // ==========================================================================
644
+ const isToolActive = (toolName) => isToolEnabled(pluginConfig, toolName);
645
+ const tools = {};
646
+ if (state.maskLoader) {
647
+ if (isToolActive('list_masks')) {
648
+ tools.list_masks = createListMasksTool(state.maskLoader, getActiveMask);
649
+ }
650
+ if (isToolActive('select_mask')) {
651
+ tools.select_mask = createSelectMaskTool(state.maskLoader, getActiveMask, setActiveMask);
652
+ }
653
+ if (isToolActive('deselect_mask')) {
654
+ tools.deselect_mask = createDeselectMaskTool(getActiveMask, setActiveMask);
655
+ }
656
+ if (isToolActive('get_mask_prompt')) {
657
+ tools.get_mask_prompt = createGetMaskPromptTool(state.maskLoader, getActiveMask);
658
+ }
659
+ }
660
+ if (isToolActive('maskweaver_status')) {
661
+ tools.maskweaver_status = createMaskweaverStatusTool(state.maskLoader, masksDir, getActiveMask);
662
+ }
663
+ // Memory tools
664
+ if (isToolActive('memory_search')) {
665
+ const memorySearchTool = createMemorySearchTool();
666
+ tools.memory_search = {
667
+ description: memorySearchTool.description,
668
+ args: memorySearchTool.args,
669
+ execute: (args) => memorySearchTool.execute(args, { worktree: directory }),
670
+ };
671
+ }
672
+ if (isToolActive('memory_write')) {
673
+ const memoryWriteTool = createMemoryWriteTool();
674
+ tools.memory_write = {
675
+ description: memoryWriteTool.description,
676
+ args: memoryWriteTool.args,
677
+ execute: (args) => memoryWriteTool.execute(args, { worktree: directory }),
678
+ };
679
+ }
680
+ if (isToolActive('memory_get')) {
681
+ const memoryGetTool = createMemoryGetTool();
682
+ tools.memory_get = {
683
+ description: memoryGetTool.description,
684
+ args: memoryGetTool.args,
685
+ execute: (args) => memoryGetTool.execute(args, { worktree: directory }),
686
+ };
687
+ }
688
+ if (isToolActive('memory_indexer')) {
689
+ const memoryIndexerTool = createMemoryIndexerTool();
690
+ tools.memory_indexer = {
691
+ description: memoryIndexerTool.description,
692
+ args: memoryIndexerTool.args,
693
+ execute: (args) => memoryIndexerTool.execute(args, { worktree: directory }),
694
+ };
695
+ }
696
+ // Context tool
697
+ if (isToolActive('context')) {
698
+ const contextTool = createContextTool();
699
+ tools.context = {
700
+ description: contextTool.description,
701
+ args: contextTool.args,
702
+ execute: (args) => contextTool.execute(args, { worktree: directory }),
703
+ };
704
+ }
705
+ // Retrospect tool
706
+ if (isToolActive('retrospect')) {
707
+ const retrospectTool = createRetrospectTool();
708
+ tools.retrospect = {
709
+ description: retrospectTool.description,
710
+ args: retrospectTool.args,
711
+ execute: (args) => retrospectTool.execute(args, { worktree: directory }),
712
+ };
713
+ }
714
+ // Mask save tool
715
+ if (isToolActive('mask_save')) {
716
+ const maskSaveTool = createMaskSaveTool();
717
+ tools.mask_save = {
718
+ description: maskSaveTool.description,
719
+ args: maskSaveTool.args,
720
+ execute: (args) => maskSaveTool.execute(args, { worktree: directory }),
721
+ };
722
+ }
723
+ // ==========================================================================
724
+ // 7. Return plugin hooks
725
+ // ==========================================================================
726
+ return {
727
+ // System prompt transform - inject active mask
728
+ 'experimental.chat.system.transform': async (_input, output) => {
729
+ if (state?.activeMask) {
730
+ const maskPrompt = `<ACTIVE_PERSONA>
731
+ You are currently embodying the "${state.activeMask.profile.name}" persona.
732
+
733
+ ${buildRichPrompt(state.activeMask)}
734
+ </ACTIVE_PERSONA>`;
735
+ (output.system ||= []).push(maskPrompt);
736
+ }
737
+ },
738
+ // Conditional tools
739
+ tool: tools,
740
+ // Event hooks (oh-my-opencode pattern)
741
+ event: async ({ event }) => {
742
+ // Session created - log available masks
743
+ if (event.type === 'session.created') {
744
+ if (state?.maskLoader && verbose) {
745
+ try {
746
+ const masks = await state.maskLoader.listAll();
747
+ const categories = await state.maskLoader.listCategories();
748
+ client.app.log({
749
+ service: 'maskweaver',
750
+ level: 'info',
751
+ message: `Session started - ${masks.length} masks available across ${categories.length} categories`,
752
+ });
753
+ }
754
+ catch (_e) {
755
+ // Ignore errors
756
+ }
757
+ }
758
+ }
759
+ // Session deleted - cleanup
760
+ if (event.type === 'session.deleted') {
761
+ if (state && verbose) {
762
+ const wasActive = state.activeMask !== null;
763
+ state.activeMask = null;
764
+ if (wasActive) {
765
+ client.app.log({
766
+ service: 'maskweaver',
767
+ level: 'info',
768
+ message: 'Session ended - active mask cleared',
769
+ });
770
+ }
771
+ }
772
+ }
773
+ },
774
+ // Config hook - agent overrides (oh-my-opencode pattern)
775
+ config: {
776
+ agent: async (agentConfig, context) => {
777
+ // Apply agent overrides from configuration
778
+ const agentName = context?.name;
779
+ if (!agentName)
780
+ return agentConfig;
781
+ const override = getAgentOverride(pluginConfig, agentName);
782
+ if (!override)
783
+ return agentConfig;
784
+ const modified = { ...agentConfig };
785
+ if (override.model) {
786
+ modified.model = override.model;
787
+ if (verbose) {
788
+ client.app.log({
789
+ service: 'maskweaver',
790
+ level: 'info',
791
+ message: `Agent "${agentName}" model overridden: ${override.model}`,
792
+ });
793
+ }
794
+ }
795
+ if (override.systemPrompt) {
796
+ modified.systemPrompt = override.systemPrompt;
797
+ if (verbose) {
798
+ client.app.log({
799
+ service: 'maskweaver',
800
+ level: 'info',
801
+ message: `Agent "${agentName}" system prompt overridden`,
802
+ });
803
+ }
804
+ }
805
+ return modified;
806
+ },
807
+ },
808
+ };
809
+ };
810
+ export default MaskweaverPlugin;
811
+ //# sourceMappingURL=index.js.map