maskweaver 0.9.3 → 0.9.5

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 (246) hide show
  1. package/README.ko.md +279 -325
  2. package/README.md +109 -113
  3. package/assets/commands/meta/commands.json +34 -34
  4. package/assets/commands/weave-agents.md +12 -52
  5. package/assets/commands/weave-approve.md +12 -51
  6. package/assets/commands/weave-archive.md +21 -0
  7. package/assets/commands/weave-build.md +20 -89
  8. package/assets/commands/weave-craft.md +22 -43
  9. package/assets/commands/weave-help.md +37 -106
  10. package/assets/commands/weave-init.md +26 -108
  11. package/assets/commands/weave-interview.md +13 -111
  12. package/assets/commands/weave-map.md +13 -99
  13. package/assets/commands/weave-prepare.md +23 -69
  14. package/assets/commands/weave-refine-plan.md +26 -59
  15. package/assets/commands/weave-repair.md +22 -70
  16. package/assets/commands/weave-status.md +22 -155
  17. package/assets/commands/weave-troubleshoot.md +11 -47
  18. package/assets/commands/weave-verify.md +23 -44
  19. package/assets/commands/weave-worktree.md +27 -69
  20. package/dist/cli/doctor.js +5 -21
  21. package/dist/cli/install.d.ts +0 -8
  22. package/dist/cli/install.js +0 -39
  23. package/dist/context/config.d.ts +0 -22
  24. package/dist/context/config.js +0 -28
  25. package/dist/context/feature.d.ts +0 -39
  26. package/dist/context/feature.js +0 -77
  27. package/dist/context/files.d.ts +0 -13
  28. package/dist/context/files.js +1 -24
  29. package/dist/context/index.d.ts +0 -7
  30. package/dist/context/index.js +0 -12
  31. package/dist/context/project.d.ts +0 -21
  32. package/dist/context/project.js +0 -30
  33. package/dist/context/types.d.ts +0 -48
  34. package/dist/context/types.js +0 -12
  35. package/dist/context/utils.d.ts +0 -18
  36. package/dist/context/utils.js +0 -27
  37. package/dist/core/engine/promptBuilder.d.ts +0 -17
  38. package/dist/core/engine/promptBuilder.js +0 -28
  39. package/dist/core/index.d.ts +0 -6
  40. package/dist/core/index.js +0 -9
  41. package/dist/core/loader/MaskLoader.d.ts +0 -23
  42. package/dist/core/loader/MaskLoader.js +0 -29
  43. package/dist/core/schema/types.d.ts +0 -47
  44. package/dist/core/schema/types.js +0 -6
  45. package/dist/core/schema/validator.d.ts +0 -14
  46. package/dist/core/schema/validator.js +0 -18
  47. package/dist/i18n/index.d.ts +0 -18
  48. package/dist/i18n/index.js +4 -23
  49. package/dist/index.d.ts +0 -8
  50. package/dist/index.js +0 -8
  51. package/dist/lib.d.ts +0 -5
  52. package/dist/lib.js +0 -12
  53. package/dist/memory/chunking.d.ts +0 -22
  54. package/dist/memory/chunking.js +2 -37
  55. package/dist/memory/core.d.ts +0 -29
  56. package/dist/memory/core.js +1 -52
  57. package/dist/memory/index.d.ts +0 -5
  58. package/dist/memory/index.js +0 -10
  59. package/dist/memory/indexer.d.ts +0 -21
  60. package/dist/memory/indexer.js +0 -44
  61. package/dist/memory/providers/examples.d.ts +0 -5
  62. package/dist/memory/providers/examples.js +4 -64
  63. package/dist/memory/providers/factory.d.ts +0 -44
  64. package/dist/memory/providers/factory.js +0 -46
  65. package/dist/memory/providers/index.d.ts +0 -26
  66. package/dist/memory/providers/index.js +0 -28
  67. package/dist/memory/providers/ollama.d.ts +0 -6
  68. package/dist/memory/providers/ollama.js +1 -8
  69. package/dist/memory/providers/openai.d.ts +0 -6
  70. package/dist/memory/providers/openai.js +1 -8
  71. package/dist/memory/providers/openrouter.d.ts +0 -6
  72. package/dist/memory/providers/openrouter.js +0 -8
  73. package/dist/memory/providers/text-only.d.ts +0 -13
  74. package/dist/memory/providers/text-only.js +0 -17
  75. package/dist/memory/providers/types.d.ts +0 -39
  76. package/dist/memory/providers/types.js +0 -7
  77. package/dist/memory/providers/voyage.d.ts +0 -22
  78. package/dist/memory/providers/voyage.js +1 -24
  79. package/dist/memory/search/hybrid.d.ts +0 -12
  80. package/dist/memory/search/hybrid.js +1 -22
  81. package/dist/memory/store/sqlite.d.ts +0 -72
  82. package/dist/memory/store/sqlite.js +4 -127
  83. package/dist/plugin/config/index.d.ts +0 -112
  84. package/dist/plugin/config/index.js +0 -115
  85. package/dist/plugin/index.d.ts +0 -13
  86. package/dist/plugin/index.js +1 -124
  87. package/dist/plugin/tools/command-registry.d.ts +0 -6
  88. package/dist/plugin/tools/command-registry.js +0 -14
  89. package/dist/plugin/tools/context.d.ts +0 -12
  90. package/dist/plugin/tools/context.js +0 -58
  91. package/dist/plugin/tools/maskSave.d.ts +0 -3
  92. package/dist/plugin/tools/maskSave.js +0 -3
  93. package/dist/plugin/tools/memoryGet.d.ts +0 -3
  94. package/dist/plugin/tools/memoryGet.js +0 -3
  95. package/dist/plugin/tools/memoryIndexer.d.ts +0 -3
  96. package/dist/plugin/tools/memoryIndexer.js +0 -10
  97. package/dist/plugin/tools/memorySearch.d.ts +0 -31
  98. package/dist/plugin/tools/memorySearch.js +0 -79
  99. package/dist/plugin/tools/memoryWrite.d.ts +0 -8
  100. package/dist/plugin/tools/memoryWrite.js +0 -32
  101. package/dist/plugin/tools/retrospect.d.ts +0 -3
  102. package/dist/plugin/tools/retrospect.js +0 -3
  103. package/dist/plugin/tools/slashcommand.d.ts +0 -11
  104. package/dist/plugin/tools/slashcommand.js +0 -38
  105. package/dist/plugin/tools/squad.d.ts +0 -12
  106. package/dist/plugin/tools/squad.js +11 -83
  107. package/dist/plugin/tools/weave.d.ts +0 -6
  108. package/dist/plugin/tools/weave.js +0 -78
  109. package/dist/plugin/types.d.ts +0 -20
  110. package/dist/plugin/types.js +0 -7
  111. package/dist/retrospect/index.d.ts +0 -7
  112. package/dist/retrospect/index.js +0 -9
  113. package/dist/retrospect/mask-save.d.ts +0 -12
  114. package/dist/retrospect/mask-save.js +1 -80
  115. package/dist/retrospect/retrospect.d.ts +0 -18
  116. package/dist/retrospect/retrospect.js +0 -63
  117. package/dist/retrospect/strategies/base.d.ts +0 -15
  118. package/dist/retrospect/strategies/base.js +0 -7
  119. package/dist/retrospect/strategies/deep.d.ts +0 -12
  120. package/dist/retrospect/strategies/deep.js +0 -24
  121. package/dist/retrospect/strategies/index.d.ts +0 -12
  122. package/dist/retrospect/strategies/index.js +0 -12
  123. package/dist/retrospect/strategies/quick.d.ts +0 -12
  124. package/dist/retrospect/strategies/quick.js +0 -19
  125. package/dist/retrospect/strategies/standard.d.ts +0 -12
  126. package/dist/retrospect/strategies/standard.js +0 -15
  127. package/dist/retrospect/types.d.ts +0 -7
  128. package/dist/retrospect/types.js +0 -7
  129. package/dist/shared/config.d.ts +0 -105
  130. package/dist/shared/config.js +0 -33
  131. package/dist/shared/errors.d.ts +0 -18
  132. package/dist/shared/errors.js +0 -19
  133. package/dist/shared/generate-agents.d.ts +0 -69
  134. package/dist/shared/generate-agents.js +2 -86
  135. package/dist/shared/image.d.ts +0 -67
  136. package/dist/shared/image.js +6 -104
  137. package/dist/shared/index.d.ts +0 -5
  138. package/dist/shared/index.js +0 -7
  139. package/dist/shared/model-registry.d.ts +0 -72
  140. package/dist/shared/model-registry.js +5 -95
  141. package/dist/shared/types.d.ts +0 -15
  142. package/dist/shared/types.js +0 -3
  143. package/dist/shared-context/dag.d.ts +0 -105
  144. package/dist/shared-context/dag.js +3 -114
  145. package/dist/shared-context/index.d.ts +0 -5
  146. package/dist/shared-context/index.js +0 -15
  147. package/dist/shared-context/logger.d.ts +0 -37
  148. package/dist/shared-context/logger.js +0 -41
  149. package/dist/shared-context/parallel-executor.d.ts +0 -54
  150. package/dist/shared-context/parallel-executor.js +4 -56
  151. package/dist/shared-context/session.d.ts +0 -56
  152. package/dist/shared-context/session.js +0 -47
  153. package/dist/shared-context/squad.d.ts +0 -68
  154. package/dist/shared-context/squad.js +0 -63
  155. package/dist/shared-context/storage.d.ts +0 -132
  156. package/dist/shared-context/storage.js +0 -116
  157. package/dist/shared-context/task.d.ts +0 -120
  158. package/dist/shared-context/task.js +0 -152
  159. package/dist/shared-context/test/dag.test.js +9 -14
  160. package/dist/shared-context/test/logger.test.d.ts +0 -8
  161. package/dist/shared-context/test/logger.test.js +0 -52
  162. package/dist/shared-context/test/session.test.d.ts +0 -7
  163. package/dist/shared-context/test/session.test.js +0 -63
  164. package/dist/shared-context/test/squad.test.d.ts +0 -10
  165. package/dist/shared-context/test/squad.test.js +2 -68
  166. package/dist/shared-context/test/storage.test.d.ts +0 -8
  167. package/dist/shared-context/test/storage.test.js +0 -68
  168. package/dist/shared-context/test/task.test.d.ts +0 -7
  169. package/dist/shared-context/test/task.test.js +0 -54
  170. package/dist/shared-context/test/watchdog.test.d.ts +0 -7
  171. package/dist/shared-context/test/watchdog.test.js +3 -58
  172. package/dist/shared-context/types.d.ts +0 -215
  173. package/dist/shared-context/types.js +0 -125
  174. package/dist/shared-context/watchdog.d.ts +0 -127
  175. package/dist/shared-context/watchdog.js +0 -148
  176. package/dist/shared-context/worktree.d.ts +0 -68
  177. package/dist/shared-context/worktree.js +2 -34
  178. package/dist/verify/budget.d.ts +0 -29
  179. package/dist/verify/budget.js +0 -34
  180. package/dist/verify/critical-files.d.ts +0 -17
  181. package/dist/verify/critical-files.js +0 -37
  182. package/dist/verify/escalation.d.ts +0 -20
  183. package/dist/verify/escalation.js +0 -22
  184. package/dist/verify/index.d.ts +0 -5
  185. package/dist/verify/index.js +0 -11
  186. package/dist/verify/prompts.d.ts +0 -20
  187. package/dist/verify/prompts.js +0 -20
  188. package/dist/verify/types.d.ts +0 -26
  189. package/dist/verify/types.js +1 -12
  190. package/dist/verify/verifier.d.ts +0 -29
  191. package/dist/verify/verifier.js +0 -54
  192. package/dist/version.d.ts +1 -16
  193. package/dist/version.js +1 -16
  194. package/dist/weave/bridge.d.ts +0 -35
  195. package/dist/weave/bridge.js +0 -51
  196. package/dist/weave/environment/detector.d.ts +0 -6
  197. package/dist/weave/environment/detector.js +4 -45
  198. package/dist/weave/environment/index.d.ts +0 -19
  199. package/dist/weave/environment/index.js +1 -39
  200. package/dist/weave/environment/issues.d.ts +0 -35
  201. package/dist/weave/environment/issues.js +0 -59
  202. package/dist/weave/git.d.ts +0 -8
  203. package/dist/weave/git.js +0 -8
  204. package/dist/weave/index.d.ts +0 -13
  205. package/dist/weave/index.js +2 -28
  206. package/dist/weave/knowledge/global.d.ts +0 -39
  207. package/dist/weave/knowledge/global.js +2 -78
  208. package/dist/weave/loop.js +0 -3
  209. package/dist/weave/orchestrator.d.ts +0 -69
  210. package/dist/weave/orchestrator.js +1 -101
  211. package/dist/weave/phase-manager.d.ts +0 -64
  212. package/dist/weave/phase-manager.js +0 -89
  213. package/dist/weave/security/secret-scan.d.ts +0 -14
  214. package/dist/weave/security/secret-scan.js +0 -19
  215. package/dist/weave/stages/build.js +0 -15
  216. package/dist/weave/stages/execute.d.ts +0 -42
  217. package/dist/weave/stages/execute.js +4 -86
  218. package/dist/weave/stages/handoff.d.ts +0 -7
  219. package/dist/weave/stages/handoff.js +0 -43
  220. package/dist/weave/stages/index.d.ts +0 -3
  221. package/dist/weave/stages/index.js +0 -3
  222. package/dist/weave/stages/intake.d.ts +0 -8
  223. package/dist/weave/stages/intake.js +5 -65
  224. package/dist/weave/stages/map.d.ts +0 -1
  225. package/dist/weave/stages/openspec.d.ts +0 -1
  226. package/dist/weave/stages/plan.d.ts +0 -11
  227. package/dist/weave/stages/plan.js +1 -53
  228. package/dist/weave/stages/refine.d.ts +0 -7
  229. package/dist/weave/stages/refine.js +0 -7
  230. package/dist/weave/stages/research.d.ts +0 -6
  231. package/dist/weave/stages/research.js +0 -6
  232. package/dist/weave/stages/spec.d.ts +0 -12
  233. package/dist/weave/stages/spec.js +0 -17
  234. package/dist/weave/types.d.ts +0 -20
  235. package/dist/weave/types.js +0 -5
  236. package/dist/weave/verification/commands.d.ts +0 -12
  237. package/dist/weave/verification/commands.js +0 -19
  238. package/dist/weave/verification/index.d.ts +0 -6
  239. package/dist/weave/verification/index.js +1 -19
  240. package/dist/weave/verification/playwright.d.ts +0 -47
  241. package/dist/weave/verification/playwright.js +1 -90
  242. package/dist/weave/worktree.d.ts +0 -16
  243. package/dist/weave/worktree.js +0 -23
  244. package/dist/weave/yaml-repair.d.ts +0 -39
  245. package/dist/weave/yaml-repair.js +13 -116
  246. package/package.json +1 -1
@@ -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';
@@ -48,23 +34,19 @@ const REMOVED_WEAVE_COMMAND_FILES = [
48
34
  'weave-task.md',
49
35
  'weave-task-auto.md',
50
36
  'wave-task-auto.md',
51
- 'weave-approve.md',
52
37
  ];
53
38
  function getAssetsDir() {
54
39
  try {
55
40
  const __filename = fileURLToPath(import.meta.url);
56
41
  const __dirname = path.dirname(__filename);
57
- // 1. If in dist/plugin/ (production) -> ../../assets
58
42
  const distAssets = path.join(__dirname, '..', '..', 'assets');
59
43
  if (fs.existsSync(distAssets)) {
60
44
  return distAssets;
61
45
  }
62
- // 2. If in src/plugin/ (development) -> ../../assets
63
46
  const srcAssets = path.join(__dirname, '..', '..', 'assets');
64
47
  if (fs.existsSync(srcAssets)) {
65
48
  return srcAssets;
66
49
  }
67
- // 3. Fallback for npm package structure (node_modules/maskweaver/dist/plugin/index.js)
68
50
  return distAssets;
69
51
  }
70
52
  catch {
@@ -110,7 +92,6 @@ function installAssets(projectDir) {
110
92
  const homeDir = os.homedir();
111
93
  const globalConfigDir = path.join(homeDir, '.config', 'opencode');
112
94
  const projectOpencodeDir = path.join(projectDir, '.opencode');
113
- // Install to both global and project directories to ensure visibility
114
95
  const targetDirs = [projectOpencodeDir];
115
96
  if (fs.existsSync(globalConfigDir)) {
116
97
  targetDirs.push(globalConfigDir);
@@ -125,21 +106,17 @@ function installAssets(projectDir) {
125
106
  continue;
126
107
  }
127
108
  }
128
- // Install agents
129
109
  const agentsSrc = path.join(assetsDir, 'agents');
130
110
  const agentsDest = path.join(targetDir, 'agents');
131
111
  copyDirRecursive(agentsSrc, agentsDest, result);
132
- // Install masks
133
112
  const masksSrc = path.join(assetsDir, 'masks');
134
113
  const masksDest = path.join(targetDir, 'masks');
135
114
  copyDirRecursive(masksSrc, masksDest, result);
136
- // Install commands (always overwrite to keep commands up-to-date)
137
115
  const commandsSrc = path.join(assetsDir, 'commands');
138
116
  const commandsDest = path.join(targetDir, 'commands');
139
117
  if (fs.existsSync(commandsSrc)) {
140
118
  copyDirRecursive(commandsSrc, commandsDest, result, true);
141
119
  }
142
- // Hard-remove deprecated weave commands to keep a craft-centric flow.
143
120
  for (const commandFile of REMOVED_WEAVE_COMMAND_FILES) {
144
121
  const legacyPath = path.join(commandsDest, commandFile);
145
122
  if (!fs.existsSync(legacyPath))
@@ -154,29 +131,11 @@ function installAssets(projectDir) {
154
131
  }
155
132
  return result;
156
133
  }
157
- // ============================================================================
158
- // Pool Agent Generator
159
- // ============================================================================
160
- /**
161
- * Generate dummy-human agent .md files from maskweaver.config.json's dummyHumans.pool.
162
- *
163
- * For each pool entry with a non-empty model, creates .opencode/agents/dummy-{id}.md.
164
- * Skips existing files to protect user customizations — use `weave sync-agents`
165
- * to force overwrite from the config.
166
- *
167
- * Also skips entries with empty model names (template placeholders) to prevent
168
- * generating broken agent files.
169
- */
170
134
  function generatePoolAgents(projectDir) {
171
135
  const agentsDir = path.join(projectDir, '.opencode', 'agents');
172
- // Use shared utility — force=false means skip existing
173
136
  const result = generatePoolAgentFilesFromConfig(projectDir, agentsDir, { force: false });
174
- // Extract successfully created files (not skipped, not updated)
175
137
  return result.created;
176
138
  }
177
- // ============================================================================
178
- // Simple YAML Parser
179
- // ============================================================================
180
139
  function parseSimpleYaml(content) {
181
140
  const lines = content.split('\n');
182
141
  const result = {};
@@ -332,9 +291,6 @@ function parseValue(value) {
332
291
  return num;
333
292
  return value;
334
293
  }
335
- // ============================================================================
336
- // Mask Loader
337
- // ============================================================================
338
294
  class MaskLoader {
339
295
  masksDir;
340
296
  catalog = null;
@@ -355,7 +311,6 @@ class MaskLoader {
355
311
  return this.catalog;
356
312
  }
357
313
  async load(maskId) {
358
- // Check if mask is disabled in configuration
359
314
  if (!isMaskEnabled(this.config, maskId)) {
360
315
  return null;
361
316
  }
@@ -389,7 +344,6 @@ class MaskLoader {
389
344
  const result = [];
390
345
  for (const [categoryId, category] of Object.entries(catalog.categories)) {
391
346
  for (const mask of category.masks) {
392
- // Filter out disabled masks
393
347
  if (isMaskEnabled(this.config, mask.id)) {
394
348
  result.push({ ...mask, category: categoryId });
395
349
  }
@@ -400,7 +354,6 @@ class MaskLoader {
400
354
  async listCategories() {
401
355
  const catalog = await this.loadCatalog();
402
356
  return Object.entries(catalog.categories).map(([id, cat]) => {
403
- // Count only enabled masks
404
357
  const enabledMasks = cat.masks.filter(m => isMaskEnabled(this.config, m.id));
405
358
  return {
406
359
  id,
@@ -411,9 +364,6 @@ class MaskLoader {
411
364
  });
412
365
  }
413
366
  }
414
- // ============================================================================
415
- // Prompt Builder
416
- // ============================================================================
417
367
  function buildRichPrompt(mask) {
418
368
  const parts = [];
419
369
  parts.push(`You are ${mask.profile.name}.`);
@@ -464,9 +414,6 @@ function pluginLog(client, level, message) {
464
414
  },
465
415
  });
466
416
  }
467
- // ============================================================================
468
- // Helper functions for tool factories
469
- // ============================================================================
470
417
  function createListMasksTool(maskLoader, activeMask) {
471
418
  return {
472
419
  description: 'List all available expert persona masks.',
@@ -581,7 +528,7 @@ function createMaskweaverStatusTool(maskLoader, masksDir, activeMask) {
581
528
  masksCount = masks.length;
582
529
  categoriesCount = categories.length;
583
530
  }
584
- catch (_e) { /* ignore */ }
531
+ catch (_e) { }
585
532
  }
586
533
  const active = activeMask();
587
534
  return `Maskweaver v${VERSION}
@@ -636,42 +583,27 @@ function playCompletionSound(config) {
636
583
  process.stdout.write('\u0007');
637
584
  }
638
585
  catch {
639
- // Ignore failures - notification sound is best-effort only.
640
586
  }
641
587
  }
642
588
  }
643
589
  let state = null;
644
- // ============================================================================
645
590
  export const MaskweaverPlugin = async ({ client, directory, project, worktree, $, serverUrl }) => {
646
- // ==========================================================================
647
- // 1. Load Configuration (oh-my-opencode pattern)
648
- // ==========================================================================
649
591
  const pluginConfig = loadPluginConfig(directory, { client, verbose: false });
650
- // Validate configuration
651
592
  const configErrors = validateConfig(pluginConfig);
652
593
  if (configErrors.length > 0) {
653
594
  pluginLog(client, 'warn', `Configuration validation errors: ${configErrors.join(', ')}`);
654
595
  }
655
596
  const verbose = isVerboseLoggingEnabled(pluginConfig);
656
- // ==========================================================================
657
- // 2. Auto-install assets on first run
658
- // ==========================================================================
659
597
  const installResult = installAssets(directory);
660
- // Track if this is a first-time installation
661
598
  const isFirstInstall = installResult.installed.length > 0;
662
599
  if (isFirstInstall) {
663
600
  pluginLog(client, 'info', `Installed ${installResult.installed.length} files to .opencode/ (agents, masks)`);
664
- // Show prominent restart message for first-time installation
665
601
  pluginLog(client, 'warn', `⚠️ RESTART REQUIRED: Please restart OpenCode to activate all Maskweaver features (agents, masks, commands).`);
666
602
  }
667
603
  if (installResult.errors.length > 0) {
668
604
  pluginLog(client, 'warn', `Asset errors: ${installResult.errors.join(', ')}`);
669
605
  }
670
- // ==========================================================================
671
- // 2b. Auto-create/migrate default config files (global first, then project)
672
- // ==========================================================================
673
606
  const globalConfigDir = path.join(os.homedir(), '.config', 'opencode');
674
- // Migrate/update global config with missing fields
675
607
  const globalConfigPath = path.join(globalConfigDir, 'maskweaver.config.json');
676
608
  if (fs.existsSync(globalConfigPath)) {
677
609
  try {
@@ -704,25 +636,17 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
704
636
  if (createdPluginConfig) {
705
637
  pluginLog(client, 'info', `Created plugin config: ${path.relative(directory, createdPluginConfig)}`);
706
638
  }
707
- // ==========================================================================
708
- // 2c. Generate pool agents from maskweaver.config.json (dummyHumans.pool)
709
- // ==========================================================================
710
639
  const generatedAgents = generatePoolAgents(directory);
711
640
  if (generatedAgents.length > 0) {
712
641
  pluginLog(client, 'info', `Generated ${generatedAgents.length} pool agent files from maskweaver.config.json: ${generatedAgents.map(p => path.basename(p)).join(', ')}`);
713
642
  pluginLog(client, 'warn', `⚠️ RESTART REQUIRED: Please restart OpenCode to activate the new pool agent files.`);
714
643
  }
715
- // If project config was just created but pool has no agents, warn user
716
644
  if (createdRuntimeConfig && generatedAgents.length === 0) {
717
645
  pluginLog(client, 'warn', `⚠️ maskweaver.config.json was created. Edit it to configure your model pool, then restart OpenCode.`);
718
646
  }
719
- // ==========================================================================
720
- // 3. Initialize masks
721
- // ==========================================================================
722
647
  const homeDir = os.homedir();
723
648
  const globalMasksDir = path.join(homeDir, '.config', 'opencode', 'masks');
724
649
  const projectMasksDir = path.join(directory, '.opencode', 'masks');
725
- // Priority: project masks > global masks
726
650
  const masksDir = fs.existsSync(projectMasksDir) ? projectMasksDir : globalMasksDir;
727
651
  const pluginState = {
728
652
  maskLoader: null,
@@ -732,7 +656,6 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
732
656
  currentSessionID: null,
733
657
  };
734
658
  state = pluginState;
735
- // Log plugin loaded
736
659
  pluginLog(client, 'info', `Maskweaver plugin loaded v${VERSION}`);
737
660
  if (fs.existsSync(masksDir)) {
738
661
  pluginState.maskLoader = new MaskLoader(masksDir, pluginConfig);
@@ -747,9 +670,6 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
747
670
  pluginState.maskLoader = null;
748
671
  }
749
672
  }
750
- // ==========================================================================
751
- // 4. Auto-activate default mask (oh-my-opencode pattern)
752
- // ==========================================================================
753
673
  const defaultMaskId = getDefaultMask(pluginConfig);
754
674
  const autoActivate = isAutoActivateEnabled(pluginConfig);
755
675
  if (defaultMaskId && autoActivate && pluginState.maskLoader) {
@@ -767,28 +687,17 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
767
687
  pluginLog(client, 'warn', `Failed to auto-activate default mask: ${e}`);
768
688
  }
769
689
  }
770
- // ==========================================================================
771
- // 5. Helper functions for tool factories
772
- // ==========================================================================
773
690
  const getActiveMask = () => pluginState.activeMask;
774
691
  const setActiveMask = (mask) => {
775
692
  pluginState.activeMask = mask;
776
693
  };
777
- // ==========================================================================
778
- // 6. Conditional tool registration (oh-my-opencode pattern)
779
- // ==========================================================================
780
694
  const isToolActive = (toolName) => isToolEnabled(pluginConfig, toolName);
781
- // Helper to ensure tool arguments are compatible with opencode's expected format.
782
- // opencode expects a ZodRawShape (raw object), NOT a ZodObject instance.
783
- // Zod 4: schema.def.shape, Zod 3: schema._def.shape()
784
695
  const wrapSchema = (schema) => {
785
696
  if (!schema || typeof schema !== 'object')
786
697
  return schema;
787
- // Zod 4 — def.shape is a plain object
788
698
  if (schema.def && typeof schema.def === 'object' && schema.type === 'object' && schema.def.shape && typeof schema.def.shape === 'object') {
789
699
  return schema.def.shape;
790
700
  }
791
- // Zod 3 — _def.shape() returns a plain object
792
701
  if (schema._def && typeof schema._def.shape === 'function') {
793
702
  return schema._def.shape();
794
703
  }
@@ -822,7 +731,6 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
822
731
  tool.args = wrapSchema(tool.args);
823
732
  tools.maskweaver_status = tool;
824
733
  }
825
- // Memory tools
826
734
  if (isToolActive('memory_search')) {
827
735
  const memorySearchTool = createMemorySearchTool();
828
736
  tools.memory_search = {
@@ -855,7 +763,6 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
855
763
  execute: (args) => memoryIndexerTool.execute(args, { worktree: directory }),
856
764
  };
857
765
  }
858
- // Context tool
859
766
  if (isToolActive('context')) {
860
767
  const contextTool = createContextTool();
861
768
  tools.context = {
@@ -864,7 +771,6 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
864
771
  execute: (args) => contextTool.execute(args, { worktree: directory }),
865
772
  };
866
773
  }
867
- // Retrospect tool
868
774
  if (isToolActive('retrospect')) {
869
775
  const retrospectTool = createRetrospectTool();
870
776
  tools.retrospect = {
@@ -873,7 +779,6 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
873
779
  execute: (args) => retrospectTool.execute(args, { worktree: directory }),
874
780
  };
875
781
  }
876
- // Mask save tool
877
782
  if (isToolActive('mask_save')) {
878
783
  const maskSaveTool = createMaskSaveTool();
879
784
  tools.mask_save = {
@@ -882,7 +787,6 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
882
787
  execute: (args) => maskSaveTool.execute(args, { worktree: directory }),
883
788
  };
884
789
  }
885
- // Squad tool (multi-agent collaboration)
886
790
  if (isToolActive('squad')) {
887
791
  const squadTool = createSquadTool();
888
792
  tools.squad = {
@@ -891,7 +795,6 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
891
795
  execute: (args) => squadTool.execute(args, { worktree: directory }),
892
796
  };
893
797
  }
894
- // Weave tool (phase-driven development workflow)
895
798
  if (isToolActive('weave')) {
896
799
  const weaveTool = createWeaveTool();
897
800
  tools.weave = {
@@ -900,7 +803,6 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
900
803
  execute: (args) => weaveTool.execute(args, { worktree: directory }),
901
804
  };
902
805
  }
903
- // Slashcommand tool (handles /weave etc. on first run without restart)
904
806
  if (isToolActive('slashcommand')) {
905
807
  const slashcommandTool = createSlashcommandTool(getAssetsDir());
906
808
  tools.slashcommand = {
@@ -909,22 +811,7 @@ export const MaskweaverPlugin = async ({ client, directory, project, worktree, $
909
811
  execute: (args) => slashcommandTool.execute(args, { worktree: directory }),
910
812
  };
911
813
  }
912
- // ==========================================================================
913
- // 8. Agents are loaded from .opencode/agents/*.md files by OpenCode's
914
- // filesystem-based agent loader (see config/agent.ts:110-140).
915
- // installAssets() in step 2 copies agent .md files so they are picked up.
916
- // The 'agent' property in Hooks is NOT consumed by OpenCode — confirmed
917
- // by source analysis (packages/opencode/src/plugin/index.ts:92-103).
918
- // ==========================================================================
919
- // ==========================================================================
920
- // 9. Return plugin hooks (official OpenCode Hooks interface only)
921
- // Note: Agents are registered via .opencode/agents/*.md files (installed by
922
- // installAssets()), NOT via the plugin return. The Hooks type does not
923
- // include 'agent' — OpenCode loads agents from the filesystem exclusively.
924
- // ==========================================================================
925
814
  return {
926
- // Agent registration handled via .opencode/agents/*.md files (see installAssets)
927
- // System prompt transform - inject active mask
928
815
  'experimental.chat.system.transform': async (_input, output) => {
929
816
  if (state?.activeMask) {
930
817
  const maskPrompt = `<ACTIVE_PERSONA>
@@ -935,11 +822,8 @@ ${buildRichPrompt(state.activeMask)}
935
822
  (output.system ||= []).push(maskPrompt);
936
823
  }
937
824
  },
938
- // Conditional tools
939
825
  tool: tools,
940
- // Event hooks (oh-my-opencode pattern)
941
826
  event: async ({ event }) => {
942
- // Session created - log available masks
943
827
  if (event.type === 'session.created') {
944
828
  pluginState.currentSessionID = getSessionId(event);
945
829
  if (pluginState.maskLoader && verbose) {
@@ -949,11 +833,9 @@ ${buildRichPrompt(state.activeMask)}
949
833
  pluginLog(client, 'info', `Session started - ${masks.length} masks available across ${categories.length} categories`);
950
834
  }
951
835
  catch (_e) {
952
- // Ignore errors
953
836
  }
954
837
  }
955
838
  }
956
- // Session idle - generation completed
957
839
  if (event.type === 'session.idle') {
958
840
  const idleSessionID = getSessionId(event);
959
841
  const isCurrentSession = !idleSessionID ||
@@ -963,7 +845,6 @@ ${buildRichPrompt(state.activeMask)}
963
845
  playCompletionSound(pluginState.config);
964
846
  }
965
847
  }
966
- // Session deleted - cleanup
967
848
  if (event.type === 'session.deleted') {
968
849
  const deletedSessionID = getSessionId(event);
969
850
  if (!deletedSessionID || deletedSessionID === pluginState.currentSessionID) {
@@ -978,11 +859,7 @@ ${buildRichPrompt(state.activeMask)}
978
859
  }
979
860
  }
980
861
  },
981
- // Config hook - allows plugins to modify opencode configuration
982
862
  config: async (config) => {
983
- // opencode discovers slash commands from config.command and command files.
984
- // installAssets() writes command files for subsequent starts, while this
985
- // hook makes the direct /build command visible on the current plugin load.
986
863
  config.command ||= {};
987
864
  config.command.build ||= {
988
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;
@@ -1,15 +1,3 @@
1
- /**
2
- * Context Management Tool
3
- *
4
- * 피처 기반 작업 컨텍스트 관리 도구
5
- *
6
- * 설계 원칙:
7
- * - 의도를 드러내는 코드 (Intention-Revealing)
8
- * - 명확한 에러 메시지
9
- * - 일관된 JSON 응답 형식
10
- *
11
- * @author Martin Fowler's Dummy Human
12
- */
13
1
  import { z } from "zod";
14
2
  import type { ToolFactory } from '../types.js';
15
3
  export declare const contextSchema: z.ZodObject<{
@@ -1,20 +1,5 @@
1
- /**
2
- * Context Management Tool
3
- *
4
- * 피처 기반 작업 컨텍스트 관리 도구
5
- *
6
- * 설계 원칙:
7
- * - 의도를 드러내는 코드 (Intention-Revealing)
8
- * - 명확한 에러 메시지
9
- * - 일관된 JSON 응답 형식
10
- *
11
- * @author Martin Fowler's Dummy Human
12
- */
13
1
  import { z } from "zod";
14
2
  import * as core from '../../context/index.js';
15
- // ============================================================================
16
- // Schema 정의
17
- // ============================================================================
18
3
  export const contextSchema = z.object({
19
4
  action: z.enum([
20
5
  "start", "switch", "status", "done",
@@ -38,9 +23,6 @@ function successResponse(action, message, data) {
38
23
  function errorResponse(action, message) {
39
24
  return createResponse(false, action, message);
40
25
  }
41
- // ============================================================================
42
- // Tool Factory
43
- // ============================================================================
44
26
  export function createContextTool() {
45
27
  return {
46
28
  description: `작업 컨텍스트를 관리합니다.
@@ -91,14 +73,6 @@ export function createContextTool() {
91
73
  }
92
74
  };
93
75
  }
94
- // ============================================================================
95
- // 액션 핸들러
96
- // ============================================================================
97
- /**
98
- * 새 피처 시작
99
- *
100
- * 피처를 생성하고 즉시 활성화합니다.
101
- */
102
76
  async function handleStart(basePath, name, goal) {
103
77
  if (!name || name.trim().length === 0) {
104
78
  return errorResponse("start", "피처 이름(name)을 입력해주세요. 예: name=\"login-oauth\"");
@@ -106,12 +80,10 @@ async function handleStart(basePath, name, goal) {
106
80
  if (!goal || goal.trim().length === 0) {
107
81
  return errorResponse("start", "피처 목표(goal)를 입력해주세요. 예: goal=\"OAuth 로그인 구현\"");
108
82
  }
109
- // 피처 생성
110
83
  const createResult = await core.createFeature(basePath, name, goal);
111
84
  if (!createResult.success || !createResult.data) {
112
85
  return errorResponse("start", createResult.error || "피처 생성에 실패했습니다");
113
86
  }
114
- // 생성된 피처를 활성화
115
87
  const switchResult = await core.switchFeature(basePath, createResult.data.id);
116
88
  if (!switchResult.success) {
117
89
  return errorResponse("start", switchResult.error || "피처 활성화에 실패했습니다");
@@ -123,16 +95,10 @@ async function handleStart(basePath, name, goal) {
123
95
  status: "active"
124
96
  });
125
97
  }
126
- /**
127
- * 피처 전환
128
- *
129
- * ID 또는 이름으로 피처를 찾아 전환합니다.
130
- */
131
98
  async function handleSwitch(basePath, id, name) {
132
99
  if (!id && !name) {
133
100
  return errorResponse("switch", "피처 ID(id) 또는 이름(name)을 입력해주세요");
134
101
  }
135
- // ID가 없으면 이름으로 피처 찾기
136
102
  let featureId = id;
137
103
  if (!featureId && name) {
138
104
  const listResult = await core.listFeatures(basePath);
@@ -158,9 +124,6 @@ async function handleSwitch(basePath, id, name) {
158
124
  files: result.data.files
159
125
  });
160
126
  }
161
- /**
162
- * 현재 상태 표시
163
- */
164
127
  async function handleStatus(basePath) {
165
128
  const activeResult = await core.getActiveFeature(basePath);
166
129
  if (!activeResult.success) {
@@ -184,12 +147,8 @@ async function handleStatus(basePath) {
184
147
  blockers: feature.blockers
185
148
  });
186
149
  }
187
- /**
188
- * 피처 완료
189
- */
190
150
  async function handleDone(basePath, id) {
191
151
  let featureId = id;
192
- // ID가 없으면 현재 활성 피처 사용
193
152
  if (!featureId) {
194
153
  const activeResult = await core.getActiveFeature(basePath);
195
154
  if (!activeResult.success) {
@@ -212,14 +171,10 @@ async function handleDone(basePath, id) {
212
171
  totalFiles: result.data.files.length
213
172
  });
214
173
  }
215
- /**
216
- * 파일 추가
217
- */
218
174
  async function handleAdd(basePath, file) {
219
175
  if (!file || file.trim().length === 0) {
220
176
  return errorResponse("add", "추가할 파일 경로(file)를 입력해주세요. 예: file=\"src/auth/oauth.ts\"");
221
177
  }
222
- // 활성 피처 확인
223
178
  const activeResult = await core.getActiveFeature(basePath);
224
179
  if (!activeResult.success) {
225
180
  return errorResponse("add", activeResult.error || "활성 피처 조회에 실패했습니다");
@@ -237,14 +192,10 @@ async function handleAdd(basePath, file) {
237
192
  fileCount: result.data.files.length
238
193
  });
239
194
  }
240
- /**
241
- * 파일 제거
242
- */
243
195
  async function handleDrop(basePath, file) {
244
196
  if (!file || file.trim().length === 0) {
245
197
  return errorResponse("drop", "제거할 파일 경로(file)를 입력해주세요. 예: file=\"src/old-file.ts\"");
246
198
  }
247
- // 활성 피처 확인
248
199
  const activeResult = await core.getActiveFeature(basePath);
249
200
  if (!activeResult.success) {
250
201
  return errorResponse("drop", activeResult.error || "활성 피처 조회에 실패했습니다");
@@ -262,14 +213,10 @@ async function handleDrop(basePath, file) {
262
213
  fileCount: result.data.files.length
263
214
  });
264
215
  }
265
- /**
266
- * 목표 변경
267
- */
268
216
  async function handleGoal(basePath, goal) {
269
217
  if (!goal || goal.trim().length === 0) {
270
218
  return errorResponse("goal", "새 목표(goal)를 입력해주세요. 예: goal=\"OAuth 로그인 + 소셜 연동\"");
271
219
  }
272
- // 활성 피처 확인
273
220
  const activeResult = await core.getActiveFeature(basePath);
274
221
  if (!activeResult.success) {
275
222
  return errorResponse("goal", activeResult.error || "활성 피처 조회에 실패했습니다");
@@ -287,9 +234,6 @@ async function handleGoal(basePath, goal) {
287
234
  newGoal: result.data.goal
288
235
  });
289
236
  }
290
- /**
291
- * 모든 피처 목록
292
- */
293
237
  async function handleList(basePath) {
294
238
  const listResult = await core.listFeatures(basePath);
295
239
  if (!listResult.success || !listResult.data) {
@@ -302,7 +246,6 @@ async function handleList(basePath) {
302
246
  features: []
303
247
  });
304
248
  }
305
- // 활성 피처 확인
306
249
  const projectResult = await core.getProjectContext(basePath);
307
250
  const activeId = projectResult.success && projectResult.data
308
251
  ? projectResult.data.activeFeatureId
@@ -316,7 +259,6 @@ async function handleList(basePath) {
316
259
  fileCount: f.files.length,
317
260
  updatedAt: f.updatedAt
318
261
  }));
319
- // 상태별 카운트
320
262
  const counts = {
321
263
  active: features.filter(f => f.status === "active").length,
322
264
  paused: features.filter(f => f.status === "paused").length,
@@ -1,5 +1,2 @@
1
- /**
2
- * Mask Save Tool - Save effective masks to library
3
- */
4
1
  import type { ToolFactory } from "../types.js";
5
2
  export declare function createMaskSaveTool(): ToolFactory;
@@ -1,6 +1,3 @@
1
- /**
2
- * Mask Save Tool - Save effective masks to library
3
- */
4
1
  import { z } from "zod";
5
2
  import { saveMask } from "../../retrospect/index.js";
6
3
  export function createMaskSaveTool() {
@@ -1,6 +1,3 @@
1
- /**
2
- * Memory Get Tool - Read memory file contents
3
- */
4
1
  import { z } from "zod";
5
2
  import type { ToolFactory } from '../types.js';
6
3
  export declare const memoryGetSchema: z.ZodObject<{
@@ -1,6 +1,3 @@
1
- /**
2
- * Memory Get Tool - Read memory file contents
3
- */
4
1
  import { z } from "zod";
5
2
  import { existsSync, readFileSync } from 'fs';
6
3
  export const memoryGetSchema = z.object({
@@ -1,5 +1,2 @@
1
- /**
2
- * Memory Indexer Tool - Index memory files for semantic search
3
- */
4
1
  import type { ToolFactory } from "../types.js";
5
2
  export declare function createMemoryIndexerTool(): ToolFactory;