musubi-sdd 5.1.0 → 5.6.1

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 (232) hide show
  1. package/README.ja.md +106 -48
  2. package/README.md +110 -32
  3. package/bin/musubi-analyze.js +74 -67
  4. package/bin/musubi-browser.js +27 -26
  5. package/bin/musubi-change.js +48 -47
  6. package/bin/musubi-checkpoint.js +10 -7
  7. package/bin/musubi-convert.js +25 -25
  8. package/bin/musubi-costs.js +27 -10
  9. package/bin/musubi-gui.js +52 -46
  10. package/bin/musubi-init.js +1952 -10
  11. package/bin/musubi-orchestrate.js +327 -239
  12. package/bin/musubi-remember.js +69 -56
  13. package/bin/musubi-resolve.js +53 -45
  14. package/bin/musubi-trace.js +51 -22
  15. package/bin/musubi-validate.js +39 -30
  16. package/bin/musubi-workflow.js +33 -34
  17. package/bin/musubi.js +39 -2
  18. package/package.json +1 -1
  19. package/src/agents/agent-loop.js +94 -95
  20. package/src/agents/agentic/code-generator.js +119 -109
  21. package/src/agents/agentic/code-reviewer.js +105 -108
  22. package/src/agents/agentic/index.js +4 -4
  23. package/src/agents/browser/action-executor.js +13 -13
  24. package/src/agents/browser/ai-comparator.js +11 -10
  25. package/src/agents/browser/context-manager.js +6 -6
  26. package/src/agents/browser/index.js +5 -5
  27. package/src/agents/browser/nl-parser.js +31 -46
  28. package/src/agents/browser/screenshot.js +2 -2
  29. package/src/agents/browser/test-generator.js +6 -4
  30. package/src/agents/function-tool.js +71 -65
  31. package/src/agents/index.js +7 -7
  32. package/src/agents/schema-generator.js +98 -94
  33. package/src/analyzers/ast-extractor.js +158 -146
  34. package/src/analyzers/codegraph-auto-update.js +858 -0
  35. package/src/analyzers/complexity-analyzer.js +536 -0
  36. package/src/analyzers/context-optimizer.js +241 -126
  37. package/src/analyzers/impact-analyzer.js +1 -1
  38. package/src/analyzers/large-project-analyzer.js +766 -0
  39. package/src/analyzers/repository-map.js +77 -81
  40. package/src/analyzers/security-analyzer.js +19 -11
  41. package/src/analyzers/stuck-detector.js +19 -17
  42. package/src/converters/index.js +78 -57
  43. package/src/converters/ir/types.js +12 -12
  44. package/src/converters/parsers/musubi-parser.js +134 -126
  45. package/src/converters/parsers/openapi-parser.js +70 -53
  46. package/src/converters/parsers/speckit-parser.js +239 -175
  47. package/src/converters/writers/musubi-writer.js +123 -118
  48. package/src/converters/writers/speckit-writer.js +124 -113
  49. package/src/generators/rust-migration-generator.js +512 -0
  50. package/src/gui/public/index.html +1365 -1211
  51. package/src/gui/server.js +41 -40
  52. package/src/gui/services/file-watcher.js +23 -8
  53. package/src/gui/services/project-scanner.js +26 -20
  54. package/src/gui/services/replanning-service.js +27 -23
  55. package/src/gui/services/traceability-service.js +8 -8
  56. package/src/gui/services/workflow-service.js +14 -7
  57. package/src/index.js +151 -0
  58. package/src/integrations/cicd.js +90 -104
  59. package/src/integrations/codegraph-mcp.js +643 -0
  60. package/src/integrations/documentation.js +142 -103
  61. package/src/integrations/examples.js +95 -80
  62. package/src/integrations/github-client.js +17 -17
  63. package/src/integrations/index.js +5 -5
  64. package/src/integrations/mcp/index.js +21 -21
  65. package/src/integrations/mcp/mcp-context-provider.js +76 -78
  66. package/src/integrations/mcp/mcp-discovery.js +74 -72
  67. package/src/integrations/mcp/mcp-tool-registry.js +99 -94
  68. package/src/integrations/mcp-connector.js +70 -66
  69. package/src/integrations/platforms.js +50 -49
  70. package/src/integrations/tool-discovery.js +37 -31
  71. package/src/llm-providers/anthropic-provider.js +11 -11
  72. package/src/llm-providers/base-provider.js +16 -18
  73. package/src/llm-providers/copilot-provider.js +22 -19
  74. package/src/llm-providers/index.js +26 -25
  75. package/src/llm-providers/ollama-provider.js +11 -11
  76. package/src/llm-providers/openai-provider.js +12 -12
  77. package/src/managers/agent-memory.js +36 -24
  78. package/src/managers/checkpoint-manager.js +4 -8
  79. package/src/managers/delta-spec.js +19 -19
  80. package/src/managers/index.js +13 -4
  81. package/src/managers/memory-condenser.js +35 -45
  82. package/src/managers/repo-skill-manager.js +57 -31
  83. package/src/managers/skill-loader.js +25 -22
  84. package/src/managers/skill-tools.js +36 -72
  85. package/src/managers/workflow.js +30 -22
  86. package/src/monitoring/cost-tracker.js +48 -46
  87. package/src/monitoring/incident-manager.js +116 -106
  88. package/src/monitoring/index.js +144 -134
  89. package/src/monitoring/observability.js +75 -62
  90. package/src/monitoring/quality-dashboard.js +45 -41
  91. package/src/monitoring/release-manager.js +63 -53
  92. package/src/orchestration/agent-skill-binding.js +39 -47
  93. package/src/orchestration/error-handler.js +65 -107
  94. package/src/orchestration/guardrails/base-guardrail.js +26 -24
  95. package/src/orchestration/guardrails/guardrail-rules.js +50 -64
  96. package/src/orchestration/guardrails/index.js +5 -5
  97. package/src/orchestration/guardrails/input-guardrail.js +58 -45
  98. package/src/orchestration/guardrails/output-guardrail.js +104 -81
  99. package/src/orchestration/guardrails/safety-check.js +79 -79
  100. package/src/orchestration/index.js +38 -55
  101. package/src/orchestration/mcp-tool-adapters.js +96 -99
  102. package/src/orchestration/orchestration-engine.js +21 -21
  103. package/src/orchestration/pattern-registry.js +60 -45
  104. package/src/orchestration/patterns/auto.js +34 -47
  105. package/src/orchestration/patterns/group-chat.js +59 -65
  106. package/src/orchestration/patterns/handoff.js +67 -65
  107. package/src/orchestration/patterns/human-in-loop.js +51 -72
  108. package/src/orchestration/patterns/nested.js +25 -40
  109. package/src/orchestration/patterns/sequential.js +35 -34
  110. package/src/orchestration/patterns/swarm.js +63 -56
  111. package/src/orchestration/patterns/triage.js +150 -109
  112. package/src/orchestration/reasoning/index.js +9 -9
  113. package/src/orchestration/reasoning/planning-engine.js +143 -140
  114. package/src/orchestration/reasoning/reasoning-engine.js +206 -144
  115. package/src/orchestration/reasoning/self-correction.js +121 -128
  116. package/src/orchestration/replanning/adaptive-goal-modifier.js +107 -112
  117. package/src/orchestration/replanning/alternative-generator.js +37 -42
  118. package/src/orchestration/replanning/config.js +63 -59
  119. package/src/orchestration/replanning/goal-progress-tracker.js +98 -100
  120. package/src/orchestration/replanning/index.js +24 -20
  121. package/src/orchestration/replanning/plan-evaluator.js +49 -50
  122. package/src/orchestration/replanning/plan-monitor.js +32 -28
  123. package/src/orchestration/replanning/proactive-path-optimizer.js +175 -178
  124. package/src/orchestration/replanning/replan-history.js +33 -26
  125. package/src/orchestration/replanning/replanning-engine.js +106 -108
  126. package/src/orchestration/skill-executor.js +107 -109
  127. package/src/orchestration/skill-registry.js +85 -89
  128. package/src/orchestration/workflow-examples.js +228 -231
  129. package/src/orchestration/workflow-executor.js +65 -68
  130. package/src/orchestration/workflow-orchestrator.js +72 -73
  131. package/src/phase4-integration.js +47 -40
  132. package/src/phase5-integration.js +89 -30
  133. package/src/reporters/coverage-report.js +82 -30
  134. package/src/reporters/hierarchical-reporter.js +498 -0
  135. package/src/reporters/traceability-matrix-report.js +29 -20
  136. package/src/resolvers/issue-resolver.js +43 -31
  137. package/src/steering/advanced-validation.js +133 -124
  138. package/src/steering/auto-updater.js +60 -73
  139. package/src/steering/index.js +6 -6
  140. package/src/steering/quality-metrics.js +41 -35
  141. package/src/steering/steering-auto-update.js +83 -86
  142. package/src/steering/steering-validator.js +98 -106
  143. package/src/steering/template-constraints.js +53 -54
  144. package/src/templates/agents/claude-code/CLAUDE.md +32 -32
  145. package/src/templates/agents/claude-code/skills/agent-assistant/SKILL.md +13 -5
  146. package/src/templates/agents/claude-code/skills/ai-ml-engineer/mlops-guide.md +23 -23
  147. package/src/templates/agents/claude-code/skills/ai-ml-engineer/model-card-template.md +60 -41
  148. package/src/templates/agents/claude-code/skills/api-designer/api-patterns.md +27 -19
  149. package/src/templates/agents/claude-code/skills/api-designer/openapi-template.md +11 -7
  150. package/src/templates/agents/claude-code/skills/bug-hunter/SKILL.md +4 -3
  151. package/src/templates/agents/claude-code/skills/bug-hunter/root-cause-analysis.md +37 -15
  152. package/src/templates/agents/claude-code/skills/change-impact-analyzer/dependency-graph-patterns.md +36 -42
  153. package/src/templates/agents/claude-code/skills/change-impact-analyzer/impact-analysis-template.md +69 -60
  154. package/src/templates/agents/claude-code/skills/cloud-architect/aws-patterns.md +31 -38
  155. package/src/templates/agents/claude-code/skills/cloud-architect/azure-patterns.md +28 -23
  156. package/src/templates/agents/claude-code/skills/code-reviewer/SKILL.md +61 -0
  157. package/src/templates/agents/claude-code/skills/code-reviewer/best-practices.md +27 -0
  158. package/src/templates/agents/claude-code/skills/code-reviewer/review-checklist.md +29 -10
  159. package/src/templates/agents/claude-code/skills/code-reviewer/review-standards.md +29 -24
  160. package/src/templates/agents/claude-code/skills/constitution-enforcer/SKILL.md +8 -6
  161. package/src/templates/agents/claude-code/skills/constitution-enforcer/constitutional-articles.md +62 -26
  162. package/src/templates/agents/claude-code/skills/constitution-enforcer/phase-minus-one-gates.md +35 -16
  163. package/src/templates/agents/claude-code/skills/database-administrator/backup-recovery.md +27 -17
  164. package/src/templates/agents/claude-code/skills/database-administrator/tuning-guide.md +25 -20
  165. package/src/templates/agents/claude-code/skills/database-schema-designer/schema-patterns.md +39 -22
  166. package/src/templates/agents/claude-code/skills/devops-engineer/ci-cd-templates.md +25 -22
  167. package/src/templates/agents/claude-code/skills/issue-resolver/SKILL.md +24 -21
  168. package/src/templates/agents/claude-code/skills/orchestrator/SKILL.md +148 -63
  169. package/src/templates/agents/claude-code/skills/orchestrator/patterns.md +35 -16
  170. package/src/templates/agents/claude-code/skills/orchestrator/selection-matrix.md +69 -64
  171. package/src/templates/agents/claude-code/skills/performance-engineer/optimization-playbook.md +47 -47
  172. package/src/templates/agents/claude-code/skills/performance-optimizer/SKILL.md +69 -0
  173. package/src/templates/agents/claude-code/skills/performance-optimizer/benchmark-template.md +63 -45
  174. package/src/templates/agents/claude-code/skills/performance-optimizer/optimization-patterns.md +33 -35
  175. package/src/templates/agents/claude-code/skills/project-manager/SKILL.md +7 -6
  176. package/src/templates/agents/claude-code/skills/project-manager/agile-ceremonies.md +47 -28
  177. package/src/templates/agents/claude-code/skills/project-manager/project-templates.md +94 -78
  178. package/src/templates/agents/claude-code/skills/quality-assurance/SKILL.md +20 -17
  179. package/src/templates/agents/claude-code/skills/quality-assurance/qa-plan-template.md +63 -49
  180. package/src/templates/agents/claude-code/skills/release-coordinator/SKILL.md +5 -5
  181. package/src/templates/agents/claude-code/skills/release-coordinator/feature-flag-guide.md +30 -26
  182. package/src/templates/agents/claude-code/skills/release-coordinator/release-plan-template.md +67 -35
  183. package/src/templates/agents/claude-code/skills/requirements-analyst/ears-format.md +54 -42
  184. package/src/templates/agents/claude-code/skills/requirements-analyst/validation-rules.md +36 -33
  185. package/src/templates/agents/claude-code/skills/security-auditor/SKILL.md +77 -19
  186. package/src/templates/agents/claude-code/skills/security-auditor/audit-checklists.md +24 -24
  187. package/src/templates/agents/claude-code/skills/security-auditor/owasp-top-10.md +61 -20
  188. package/src/templates/agents/claude-code/skills/security-auditor/vulnerability-patterns.md +43 -11
  189. package/src/templates/agents/claude-code/skills/site-reliability-engineer/SKILL.md +1 -0
  190. package/src/templates/agents/claude-code/skills/site-reliability-engineer/incident-response-template.md +55 -25
  191. package/src/templates/agents/claude-code/skills/site-reliability-engineer/observability-patterns.md +78 -68
  192. package/src/templates/agents/claude-code/skills/site-reliability-engineer/slo-sli-guide.md +73 -53
  193. package/src/templates/agents/claude-code/skills/software-developer/solid-principles.md +83 -37
  194. package/src/templates/agents/claude-code/skills/software-developer/test-first-workflow.md +38 -31
  195. package/src/templates/agents/claude-code/skills/steering/SKILL.md +1 -0
  196. package/src/templates/agents/claude-code/skills/steering/auto-update-rules.md +31 -0
  197. package/src/templates/agents/claude-code/skills/system-architect/adr-template.md +25 -7
  198. package/src/templates/agents/claude-code/skills/system-architect/c4-model-guide.md +74 -61
  199. package/src/templates/agents/claude-code/skills/technical-writer/doc-templates/documentation-templates.md +70 -52
  200. package/src/templates/agents/claude-code/skills/test-engineer/SKILL.md +2 -0
  201. package/src/templates/agents/claude-code/skills/test-engineer/ears-test-mapping.md +75 -71
  202. package/src/templates/agents/claude-code/skills/test-engineer/test-types.md +85 -63
  203. package/src/templates/agents/claude-code/skills/traceability-auditor/coverage-matrix-template.md +39 -36
  204. package/src/templates/agents/claude-code/skills/traceability-auditor/gap-detection-rules.md +22 -17
  205. package/src/templates/agents/claude-code/skills/ui-ux-designer/SKILL.md +1 -0
  206. package/src/templates/agents/claude-code/skills/ui-ux-designer/accessibility-guidelines.md +49 -75
  207. package/src/templates/agents/claude-code/skills/ui-ux-designer/design-system-components.md +71 -59
  208. package/src/templates/agents/codex/AGENTS.md +74 -42
  209. package/src/templates/agents/cursor/AGENTS.md +74 -42
  210. package/src/templates/agents/gemini-cli/GEMINI.md +74 -42
  211. package/src/templates/agents/github-copilot/AGENTS.md +83 -51
  212. package/src/templates/agents/qwen-code/QWEN.md +74 -42
  213. package/src/templates/agents/windsurf/AGENTS.md +74 -42
  214. package/src/templates/architectures/README.md +41 -0
  215. package/src/templates/architectures/clean-architecture/README.md +113 -0
  216. package/src/templates/architectures/event-driven/README.md +162 -0
  217. package/src/templates/architectures/hexagonal/README.md +130 -0
  218. package/src/templates/index.js +6 -1
  219. package/src/templates/locale-manager.js +16 -16
  220. package/src/templates/shared/delta-spec-template.md +20 -13
  221. package/src/templates/shared/github-actions/musubi-issue-resolver.yml +5 -5
  222. package/src/templates/shared/github-actions/musubi-security-check.yml +3 -3
  223. package/src/templates/shared/github-actions/musubi-validate.yml +4 -4
  224. package/src/templates/shared/steering/structure.md +95 -0
  225. package/src/templates/skills/browser-agent.md +21 -16
  226. package/src/templates/skills/web-gui.md +8 -0
  227. package/src/templates/template-constraints.js +50 -53
  228. package/src/validators/advanced-validation.js +30 -36
  229. package/src/validators/constitutional-validator.js +77 -73
  230. package/src/validators/critic-system.js +49 -59
  231. package/src/validators/delta-format.js +59 -55
  232. package/src/validators/traceability-validator.js +7 -11
@@ -76,7 +76,7 @@ class ActionExecutor {
76
76
  */
77
77
  async executeNavigate(action, page, timeout) {
78
78
  await page.goto(action.url, { timeout, waitUntil: 'domcontentloaded' });
79
-
79
+
80
80
  return {
81
81
  success: true,
82
82
  type: 'navigate',
@@ -93,7 +93,7 @@ class ActionExecutor {
93
93
  */
94
94
  async executeClick(action, page, timeout) {
95
95
  const selectors = action.selector.split(',').map(s => s.trim());
96
-
96
+
97
97
  // Try each selector until one works
98
98
  for (const selector of selectors) {
99
99
  try {
@@ -110,7 +110,7 @@ class ActionExecutor {
110
110
 
111
111
  // If none worked, try with the original selector and let it fail
112
112
  await page.click(action.selector, { timeout });
113
-
113
+
114
114
  return {
115
115
  success: true,
116
116
  type: 'click',
@@ -127,7 +127,7 @@ class ActionExecutor {
127
127
  */
128
128
  async executeFill(action, page, timeout) {
129
129
  const selectors = action.selector.split(',').map(s => s.trim());
130
-
130
+
131
131
  // Try each selector until one works
132
132
  for (const selector of selectors) {
133
133
  try {
@@ -144,7 +144,7 @@ class ActionExecutor {
144
144
 
145
145
  // If none worked, try with the original selector
146
146
  await page.fill(action.selector, action.value, { timeout });
147
-
147
+
148
148
  return {
149
149
  success: true,
150
150
  type: 'fill',
@@ -161,7 +161,7 @@ class ActionExecutor {
161
161
  */
162
162
  async executeSelect(action, page, timeout) {
163
163
  const selectors = action.selector.split(',').map(s => s.trim());
164
-
164
+
165
165
  for (const selector of selectors) {
166
166
  try {
167
167
  await page.selectOption(selector, action.value, { timeout });
@@ -176,7 +176,7 @@ class ActionExecutor {
176
176
  }
177
177
 
178
178
  await page.selectOption(action.selector, action.value, { timeout });
179
-
179
+
180
180
  return {
181
181
  success: true,
182
182
  type: 'select',
@@ -191,7 +191,7 @@ class ActionExecutor {
191
191
  */
192
192
  async executeWait(action) {
193
193
  await new Promise(resolve => setTimeout(resolve, action.delay));
194
-
194
+
195
195
  return {
196
196
  success: true,
197
197
  type: 'wait',
@@ -207,12 +207,12 @@ class ActionExecutor {
207
207
  */
208
208
  async executeScreenshot(action, context) {
209
209
  const { page, screenshot } = context;
210
-
210
+
211
211
  const path = await screenshot.capture(page, {
212
212
  name: action.name,
213
213
  fullPage: action.fullPage,
214
214
  });
215
-
215
+
216
216
  return {
217
217
  success: true,
218
218
  type: 'screenshot',
@@ -229,9 +229,9 @@ class ActionExecutor {
229
229
  */
230
230
  async executeAssert(action, page, timeout) {
231
231
  const locator = page.locator(action.selector);
232
-
232
+
233
233
  await locator.waitFor({ state: 'visible', timeout });
234
-
234
+
235
235
  let text = null;
236
236
  if (action.expectedText) {
237
237
  text = await locator.textContent();
@@ -243,7 +243,7 @@ class ActionExecutor {
243
243
  };
244
244
  }
245
245
  }
246
-
246
+
247
247
  return {
248
248
  success: true,
249
249
  type: 'assert',
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  const fs = require('fs-extra');
7
- const path = require('path');
7
+ const _path = require('path');
8
8
 
9
9
  /**
10
10
  * @typedef {Object} ComparisonResult
@@ -45,10 +45,10 @@ class AIComparator {
45
45
  const description = options.description || 'Compare visual appearance';
46
46
 
47
47
  // Check if files exist
48
- if (!await fs.pathExists(expectedPath)) {
48
+ if (!(await fs.pathExists(expectedPath))) {
49
49
  throw new Error(`Expected screenshot not found: ${expectedPath}`);
50
50
  }
51
- if (!await fs.pathExists(actualPath)) {
51
+ if (!(await fs.pathExists(actualPath))) {
52
52
  throw new Error(`Actual screenshot not found: ${actualPath}`);
53
53
  }
54
54
 
@@ -64,7 +64,7 @@ class AIComparator {
64
64
 
65
65
  // Call Vision API
66
66
  const result = await this.callVisionAPI(expectedBase64, actualBase64, description);
67
-
67
+
68
68
  return {
69
69
  passed: result.similarity >= threshold * 100,
70
70
  similarity: result.similarity,
@@ -101,7 +101,7 @@ class AIComparator {
101
101
  method: 'POST',
102
102
  headers: {
103
103
  'Content-Type': 'application/json',
104
- 'Authorization': `Bearer ${this.apiKey}`,
104
+ Authorization: `Bearer ${this.apiKey}`,
105
105
  },
106
106
  body: JSON.stringify({
107
107
  model: this.model,
@@ -193,7 +193,7 @@ class AIComparator {
193
193
  // Calculate size difference
194
194
  const sizeDiff = Math.abs(expectedStat.size - actualStat.size);
195
195
  const maxSize = Math.max(expectedStat.size, actualStat.size);
196
- const sizeRatio = 1 - (sizeDiff / maxSize);
196
+ const sizeRatio = 1 - sizeDiff / maxSize;
197
197
 
198
198
  // Simple heuristic: if sizes are similar, likely similar images
199
199
  // This is a rough approximation and should be replaced with actual image comparison
@@ -202,9 +202,10 @@ class AIComparator {
202
202
  return {
203
203
  passed: similarity >= threshold * 100,
204
204
  similarity,
205
- differences: similarity < threshold * 100
206
- ? [`File size differs by ${sizeDiff} bytes (${((1 - sizeRatio) * 100).toFixed(1)}%)`]
207
- : [],
205
+ differences:
206
+ similarity < threshold * 100
207
+ ? [`File size differs by ${sizeDiff} bytes (${((1 - sizeRatio) * 100).toFixed(1)}%)`]
208
+ : [],
208
209
  details: {
209
210
  method: 'fallback-size-comparison',
210
211
  expectedSize: expectedStat.size,
@@ -221,7 +222,7 @@ class AIComparator {
221
222
  * @param {Object} options
222
223
  * @returns {string}
223
224
  */
224
- generateReport(result, options = {}) {
225
+ generateReport(result, _options = {}) {
225
226
  const lines = [
226
227
  '# Screenshot Comparison Report',
227
228
  '',
@@ -66,14 +66,14 @@ class ContextManager {
66
66
  */
67
67
  async getOrCreatePage(contextName = 'default') {
68
68
  const pageKey = `${contextName}:main`;
69
-
69
+
70
70
  if (this.pages.has(pageKey)) {
71
71
  return this.pages.get(pageKey);
72
72
  }
73
73
 
74
74
  const context = await this.getOrCreateContext(contextName);
75
75
  const page = await context.newPage();
76
-
76
+
77
77
  this.pages.set(pageKey, page);
78
78
  return page;
79
79
  }
@@ -87,10 +87,10 @@ class ContextManager {
87
87
  async createPage(contextName = 'default', pageName) {
88
88
  const context = await this.getOrCreateContext(contextName);
89
89
  const page = await context.newPage();
90
-
90
+
91
91
  const pageKey = `${contextName}:${pageName}`;
92
92
  this.pages.set(pageKey, page);
93
-
93
+
94
94
  return page;
95
95
  }
96
96
 
@@ -162,9 +162,9 @@ class ContextManager {
162
162
  if (context) {
163
163
  await context.close();
164
164
  this.contexts.delete(name);
165
-
165
+
166
166
  // Remove associated pages
167
- for (const [key, page] of this.pages.entries()) {
167
+ for (const [key, _page] of this.pages.entries()) {
168
168
  if (key.startsWith(`${name}:`)) {
169
169
  this.pages.delete(key);
170
170
  }
@@ -102,7 +102,7 @@ class BrowserAgent {
102
102
 
103
103
  // Parse natural language to actions
104
104
  const parseResult = this.parser.parse(command);
105
-
105
+
106
106
  if (!parseResult.success) {
107
107
  return {
108
108
  success: false,
@@ -122,9 +122,9 @@ class BrowserAgent {
122
122
  screenshot: this.screenshot,
123
123
  timeout: this.options.timeout,
124
124
  });
125
-
125
+
126
126
  results.push(result);
127
-
127
+
128
128
  if (!result.success) {
129
129
  return {
130
130
  success: false,
@@ -150,11 +150,11 @@ class BrowserAgent {
150
150
  */
151
151
  async executeSequence(commands) {
152
152
  const results = [];
153
-
153
+
154
154
  for (const command of commands) {
155
155
  const result = await this.execute(command);
156
156
  results.push(result);
157
-
157
+
158
158
  if (!result.success) {
159
159
  return {
160
160
  success: false,
@@ -26,36 +26,21 @@
26
26
  */
27
27
  const ACTION_PATTERNS = {
28
28
  navigate: {
29
- patterns: [
30
- /(?:に)?移動|開く|アクセス/,
31
- /(?:go to|navigate|open|visit)/i,
32
- ],
29
+ patterns: [/(?:に)?移動|開く|アクセス/, /(?:go to|navigate|open|visit)/i],
33
30
  urlPattern: /(https?:\/\/[^\s]+)/,
34
31
  },
35
32
  click: {
36
- patterns: [
37
- /クリック|押す|タップ|選択/,
38
- /click|press|tap|select/i,
39
- ],
33
+ patterns: [/クリック|押す|タップ|選択/, /click|press|tap|select/i],
40
34
  },
41
35
  fill: {
42
- patterns: [
43
- /(?:に|を)?入力|記入|タイプ/,
44
- /fill|type|enter|input/i,
45
- ],
36
+ patterns: [/(?:に|を)?入力|記入|タイプ/, /fill|type|enter|input/i],
46
37
  valuePattern: /[「「]([^」」]+)[」」]|"([^"]+)"|'([^']+)'/,
47
38
  },
48
39
  select: {
49
- patterns: [
50
- /ドロップダウン.*選択|選択.*オプション/,
51
- /select.*dropdown|choose.*option/i,
52
- ],
40
+ patterns: [/ドロップダウン.*選択|選択.*オプション/, /select.*dropdown|choose.*option/i],
53
41
  },
54
42
  wait: {
55
- patterns: [
56
- /秒?待つ|待機/,
57
- /wait|pause|delay/i,
58
- ],
43
+ patterns: [/秒?待つ|待機/, /wait|pause|delay/i],
59
44
  durationPattern: /(\d+)\s*秒|(\d+)\s*(?:seconds?|ms|milliseconds?)/i,
60
45
  },
61
46
  screenshot: {
@@ -66,10 +51,7 @@ const ACTION_PATTERNS = {
66
51
  namePattern: /[「「]([^」」]+)[」」]|"([^"]+)"|として\s*(\S+)/,
67
52
  },
68
53
  assert: {
69
- patterns: [
70
- /(?:が)?表示|確認|検証|存在/,
71
- /(?:is )?visible|assert|verify|check|exists?/i,
72
- ],
54
+ patterns: [/(?:が)?表示|確認|検証|存在/, /(?:is )?visible|assert|verify|check|exists?/i],
73
55
  textPattern: /[「「]([^」」]+)[」」]|"([^"]+)"/,
74
56
  },
75
57
  };
@@ -79,17 +61,19 @@ const ACTION_PATTERNS = {
79
61
  */
80
62
  const ELEMENT_PATTERNS = {
81
63
  // Japanese element names
82
- 'ログインボタン': 'button:has-text("ログイン"), [data-testid="login-button"], button[type="submit"]',
83
- '送信ボタン': 'button:has-text("送信"), [data-testid="submit-button"], button[type="submit"]',
84
- 'メール': 'input[type="email"], input[name="email"], [data-testid="email-input"]',
85
- 'パスワード': 'input[type="password"], [data-testid="password-input"]',
86
- '検索': 'input[type="search"], [data-testid="search-input"], input[name="q"]',
64
+ ログインボタン:
65
+ 'button:has-text("ログイン"), [data-testid="login-button"], button[type="submit"]',
66
+ 送信ボタン: 'button:has-text("送信"), [data-testid="submit-button"], button[type="submit"]',
67
+ メール: 'input[type="email"], input[name="email"], [data-testid="email-input"]',
68
+ パスワード: 'input[type="password"], [data-testid="password-input"]',
69
+ 検索: 'input[type="search"], [data-testid="search-input"], input[name="q"]',
87
70
  // English element names
88
71
  'login button': 'button:has-text("Login"), [data-testid="login-button"], button[type="submit"]',
89
- 'submit button': 'button:has-text("Submit"), [data-testid="submit-button"], button[type="submit"]',
90
- 'email': 'input[type="email"], input[name="email"], [data-testid="email-input"]',
91
- 'password': 'input[type="password"], [data-testid="password-input"]',
92
- 'search': 'input[type="search"], [data-testid="search-input"], input[name="q"]',
72
+ 'submit button':
73
+ 'button:has-text("Submit"), [data-testid="submit-button"], button[type="submit"]',
74
+ email: 'input[type="email"], input[name="email"], [data-testid="email-input"]',
75
+ password: 'input[type="password"], [data-testid="password-input"]',
76
+ search: 'input[type="search"], [data-testid="search-input"], input[name="q"]',
93
77
  };
94
78
 
95
79
  /**
@@ -138,11 +122,7 @@ class NLParser {
138
122
  * @returns {string}
139
123
  */
140
124
  normalizeCommand(command) {
141
- return command
142
- .trim()
143
- .replace(/\s+/g, ' ')
144
- .replace(/、/g, ',')
145
- .replace(/。/g, '.');
125
+ return command.trim().replace(/\s+/g, ' ').replace(/、/g, ',').replace(/。/g, '.');
146
126
  }
147
127
 
148
128
  /**
@@ -172,7 +152,10 @@ class NLParser {
172
152
  splitCommand(command) {
173
153
  // Split by conjunctions and separators
174
154
  const separators = /[,、]|\s+(?:そして|して|and|then)\s+/i;
175
- return command.split(separators).map(s => s.trim()).filter(Boolean);
155
+ return command
156
+ .split(separators)
157
+ .map(s => s.trim())
158
+ .filter(Boolean);
176
159
  }
177
160
 
178
161
  /**
@@ -262,7 +245,7 @@ class NLParser {
262
245
  parseFill(text) {
263
246
  const selector = this.extractSelector(text);
264
247
  const valueMatch = text.match(this.actionPatterns.fill.valuePattern);
265
- const value = valueMatch ? (valueMatch[1] || valueMatch[2] || valueMatch[3]) : '';
248
+ const value = valueMatch ? valueMatch[1] || valueMatch[2] || valueMatch[3] : '';
266
249
 
267
250
  return {
268
251
  type: 'fill',
@@ -280,7 +263,7 @@ class NLParser {
280
263
  parseSelect(text) {
281
264
  const selector = this.extractSelector(text);
282
265
  const valueMatch = text.match(this.actionPatterns.fill.valuePattern);
283
- const value = valueMatch ? (valueMatch[1] || valueMatch[2] || valueMatch[3]) : '';
266
+ const value = valueMatch ? valueMatch[1] || valueMatch[2] || valueMatch[3] : '';
284
267
 
285
268
  return {
286
269
  type: 'select',
@@ -302,7 +285,7 @@ class NLParser {
302
285
  if (durationMatch) {
303
286
  const seconds = durationMatch[1] || durationMatch[2];
304
287
  delay = parseInt(seconds, 10) * 1000;
305
-
288
+
306
289
  // Check if it's milliseconds
307
290
  if (/ms|milliseconds?/i.test(text)) {
308
291
  delay = parseInt(seconds, 10);
@@ -323,7 +306,7 @@ class NLParser {
323
306
  */
324
307
  parseScreenshot(text) {
325
308
  const nameMatch = text.match(this.actionPatterns.screenshot.namePattern);
326
- const name = nameMatch ? (nameMatch[1] || nameMatch[2] || nameMatch[3]) : undefined;
309
+ const name = nameMatch ? nameMatch[1] || nameMatch[2] || nameMatch[3] : undefined;
327
310
  const fullPage = /全体|full\s*page/i.test(text);
328
311
 
329
312
  return {
@@ -341,7 +324,7 @@ class NLParser {
341
324
  */
342
325
  parseAssert(text) {
343
326
  const textMatch = text.match(this.actionPatterns.assert.textPattern);
344
- const expectedText = textMatch ? (textMatch[1] || textMatch[2]) : null;
327
+ const expectedText = textMatch ? textMatch[1] || textMatch[2] : null;
345
328
  const selector = expectedText ? `text="${expectedText}"` : this.extractSelector(text);
346
329
 
347
330
  return {
@@ -366,7 +349,7 @@ class NLParser {
366
349
  }
367
350
 
368
351
  // Check for CSS selector in the text (match only the selector part)
369
- const selectorMatch = text.match(/([#\.][a-zA-Z][\w\-]*|\[[^\]]+\])/);
352
+ const selectorMatch = text.match(/([#.][a-zA-Z][\w-]*|\[[^\]]+\])/);
370
353
  if (selectorMatch) {
371
354
  return selectorMatch[0];
372
355
  }
@@ -378,7 +361,9 @@ class NLParser {
378
361
  }
379
362
 
380
363
  // Try to extract element description
381
- const elementMatch = text.match(/(?:の)?(?:ボタン|リンク|入力欄?|フィールド|テキスト|button|link|input|field|text)\s*[「「]?([^」」\s]*)[」」]?/i);
364
+ const elementMatch = text.match(
365
+ /(?:の)?(?:ボタン|リンク|入力欄?|フィールド|テキスト|button|link|input|field|text)\s*[「「]?([^」」\s]*)[」」]?/i
366
+ );
382
367
  if (elementMatch && elementMatch[1]) {
383
368
  return `text="${elementMatch[1]}"`;
384
369
  }
@@ -43,7 +43,7 @@ class ScreenshotCapture {
43
43
 
44
44
  const timestamp = Date.now();
45
45
  this.counter++;
46
-
46
+
47
47
  const name = options.name || `screenshot-${this.counter}`;
48
48
  const extension = options.type || 'png';
49
49
  const filename = `${timestamp}-${name}.${extension}`;
@@ -88,7 +88,7 @@ class ScreenshotCapture {
88
88
 
89
89
  const timestamp = Date.now();
90
90
  this.counter++;
91
-
91
+
92
92
  const name = options.name || `element-${this.counter}`;
93
93
  const extension = options.type || 'png';
94
94
  const filename = `${timestamp}-${name}.${extension}`;
@@ -94,9 +94,10 @@ class TestGenerator {
94
94
  case 'wait':
95
95
  return `await page.waitForTimeout(${action.delay});`;
96
96
 
97
- case 'screenshot':
97
+ case 'screenshot': {
98
98
  const name = action.name || 'screenshot';
99
99
  return `await page.screenshot({ path: 'screenshots/${name}.png'${action.fullPage ? ', fullPage: true' : ''} });`;
100
+ }
100
101
 
101
102
  case 'assert':
102
103
  if (action.expectedText) {
@@ -173,9 +174,10 @@ class TestGenerator {
173
174
  case 'wait':
174
175
  return `await new Promise(r => setTimeout(r, ${action.delay}));`;
175
176
 
176
- case 'screenshot':
177
+ case 'screenshot': {
177
178
  const name = action.name || 'screenshot';
178
179
  return `await page.screenshot({ path: 'screenshots/${name}.png'${action.fullPage ? ', fullPage: true' : ''} });`;
180
+ }
179
181
 
180
182
  case 'assert':
181
183
  return `await page.waitForSelector('${this.escapeSelector(action.selector)}');`;
@@ -191,7 +193,7 @@ class TestGenerator {
191
193
  * @param {Object} options
192
194
  * @returns {string}
193
195
  */
194
- generateFromSpec(specification, options = {}) {
196
+ generateFromSpec(specification, _options = {}) {
195
197
  const lines = [
196
198
  `import { test, expect } from '@playwright/test';`,
197
199
  ``,
@@ -217,7 +219,7 @@ class TestGenerator {
217
219
  */
218
220
  requirementToTest(requirement) {
219
221
  const testName = `${requirement.id}: ${requirement.title || requirement.action || 'Requirement'}`;
220
-
222
+
221
223
  const lines = [
222
224
  `test('${this.escapeString(testName)}', async ({ page }) => {`,
223
225
  ` // Pattern: ${requirement.pattern}`,