musubi-sdd 5.0.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.
- package/README.ja.md +106 -48
- package/README.md +110 -32
- package/bin/musubi-analyze.js +74 -67
- package/bin/musubi-browser.js +27 -26
- package/bin/musubi-change.js +48 -47
- package/bin/musubi-checkpoint.js +10 -7
- package/bin/musubi-convert.js +25 -25
- package/bin/musubi-costs.js +27 -10
- package/bin/musubi-gui.js +52 -46
- package/bin/musubi-init.js +1952 -10
- package/bin/musubi-orchestrate.js +327 -239
- package/bin/musubi-remember.js +69 -56
- package/bin/musubi-resolve.js +53 -45
- package/bin/musubi-trace.js +51 -22
- package/bin/musubi-validate.js +39 -30
- package/bin/musubi-workflow.js +33 -34
- package/bin/musubi.js +39 -2
- package/package.json +1 -1
- package/src/agents/agent-loop.js +94 -95
- package/src/agents/agentic/code-generator.js +119 -109
- package/src/agents/agentic/code-reviewer.js +105 -108
- package/src/agents/agentic/index.js +4 -4
- package/src/agents/browser/action-executor.js +13 -13
- package/src/agents/browser/ai-comparator.js +11 -10
- package/src/agents/browser/context-manager.js +6 -6
- package/src/agents/browser/index.js +5 -5
- package/src/agents/browser/nl-parser.js +31 -46
- package/src/agents/browser/screenshot.js +2 -2
- package/src/agents/browser/test-generator.js +6 -4
- package/src/agents/function-tool.js +71 -65
- package/src/agents/index.js +7 -7
- package/src/agents/schema-generator.js +98 -94
- package/src/analyzers/ast-extractor.js +164 -145
- package/src/analyzers/codegraph-auto-update.js +858 -0
- package/src/analyzers/complexity-analyzer.js +536 -0
- package/src/analyzers/context-optimizer.js +247 -125
- package/src/analyzers/impact-analyzer.js +1 -1
- package/src/analyzers/large-project-analyzer.js +766 -0
- package/src/analyzers/repository-map.js +83 -80
- package/src/analyzers/security-analyzer.js +19 -11
- package/src/analyzers/stuck-detector.js +19 -17
- package/src/converters/index.js +78 -57
- package/src/converters/ir/types.js +12 -12
- package/src/converters/parsers/musubi-parser.js +134 -126
- package/src/converters/parsers/openapi-parser.js +70 -53
- package/src/converters/parsers/speckit-parser.js +239 -175
- package/src/converters/writers/musubi-writer.js +123 -118
- package/src/converters/writers/speckit-writer.js +124 -113
- package/src/generators/rust-migration-generator.js +512 -0
- package/src/gui/public/index.html +1365 -1211
- package/src/gui/server.js +41 -40
- package/src/gui/services/file-watcher.js +23 -8
- package/src/gui/services/project-scanner.js +26 -20
- package/src/gui/services/replanning-service.js +27 -23
- package/src/gui/services/traceability-service.js +8 -8
- package/src/gui/services/workflow-service.js +14 -7
- package/src/index.js +151 -0
- package/src/integrations/cicd.js +90 -104
- package/src/integrations/codegraph-mcp.js +643 -0
- package/src/integrations/documentation.js +142 -103
- package/src/integrations/examples.js +95 -80
- package/src/integrations/github-client.js +17 -17
- package/src/integrations/index.js +5 -5
- package/src/integrations/mcp/index.js +21 -21
- package/src/integrations/mcp/mcp-context-provider.js +76 -78
- package/src/integrations/mcp/mcp-discovery.js +74 -72
- package/src/integrations/mcp/mcp-tool-registry.js +99 -94
- package/src/integrations/mcp-connector.js +70 -66
- package/src/integrations/platforms.js +50 -49
- package/src/integrations/tool-discovery.js +37 -31
- package/src/llm-providers/anthropic-provider.js +11 -11
- package/src/llm-providers/base-provider.js +16 -18
- package/src/llm-providers/copilot-provider.js +22 -19
- package/src/llm-providers/index.js +26 -25
- package/src/llm-providers/ollama-provider.js +11 -11
- package/src/llm-providers/openai-provider.js +12 -12
- package/src/managers/agent-memory.js +36 -24
- package/src/managers/checkpoint-manager.js +4 -8
- package/src/managers/delta-spec.js +19 -19
- package/src/managers/index.js +13 -4
- package/src/managers/memory-condenser.js +35 -45
- package/src/managers/repo-skill-manager.js +57 -31
- package/src/managers/skill-loader.js +25 -22
- package/src/managers/skill-tools.js +36 -72
- package/src/managers/workflow.js +30 -22
- package/src/monitoring/cost-tracker.js +53 -44
- package/src/monitoring/incident-manager.js +123 -103
- package/src/monitoring/index.js +144 -134
- package/src/monitoring/observability.js +82 -59
- package/src/monitoring/quality-dashboard.js +51 -39
- package/src/monitoring/release-manager.js +70 -50
- package/src/orchestration/agent-skill-binding.js +39 -47
- package/src/orchestration/error-handler.js +65 -107
- package/src/orchestration/guardrails/base-guardrail.js +26 -24
- package/src/orchestration/guardrails/guardrail-rules.js +50 -64
- package/src/orchestration/guardrails/index.js +5 -5
- package/src/orchestration/guardrails/input-guardrail.js +58 -45
- package/src/orchestration/guardrails/output-guardrail.js +104 -81
- package/src/orchestration/guardrails/safety-check.js +79 -79
- package/src/orchestration/index.js +38 -55
- package/src/orchestration/mcp-tool-adapters.js +96 -99
- package/src/orchestration/orchestration-engine.js +21 -21
- package/src/orchestration/pattern-registry.js +60 -45
- package/src/orchestration/patterns/auto.js +34 -47
- package/src/orchestration/patterns/group-chat.js +59 -65
- package/src/orchestration/patterns/handoff.js +67 -65
- package/src/orchestration/patterns/human-in-loop.js +51 -72
- package/src/orchestration/patterns/nested.js +25 -40
- package/src/orchestration/patterns/sequential.js +35 -34
- package/src/orchestration/patterns/swarm.js +63 -56
- package/src/orchestration/patterns/triage.js +150 -109
- package/src/orchestration/reasoning/index.js +9 -9
- package/src/orchestration/reasoning/planning-engine.js +143 -140
- package/src/orchestration/reasoning/reasoning-engine.js +206 -144
- package/src/orchestration/reasoning/self-correction.js +121 -128
- package/src/orchestration/replanning/adaptive-goal-modifier.js +107 -112
- package/src/orchestration/replanning/alternative-generator.js +37 -42
- package/src/orchestration/replanning/config.js +63 -59
- package/src/orchestration/replanning/goal-progress-tracker.js +98 -100
- package/src/orchestration/replanning/index.js +24 -20
- package/src/orchestration/replanning/plan-evaluator.js +49 -50
- package/src/orchestration/replanning/plan-monitor.js +32 -28
- package/src/orchestration/replanning/proactive-path-optimizer.js +175 -178
- package/src/orchestration/replanning/replan-history.js +33 -26
- package/src/orchestration/replanning/replanning-engine.js +106 -108
- package/src/orchestration/skill-executor.js +107 -109
- package/src/orchestration/skill-registry.js +85 -89
- package/src/orchestration/workflow-examples.js +228 -231
- package/src/orchestration/workflow-executor.js +65 -68
- package/src/orchestration/workflow-orchestrator.js +72 -73
- package/src/phase4-integration.js +47 -40
- package/src/phase5-integration.js +89 -30
- package/src/reporters/coverage-report.js +82 -30
- package/src/reporters/hierarchical-reporter.js +498 -0
- package/src/reporters/traceability-matrix-report.js +29 -20
- package/src/resolvers/issue-resolver.js +43 -31
- package/src/steering/advanced-validation.js +133 -124
- package/src/steering/auto-updater.js +60 -73
- package/src/steering/index.js +6 -6
- package/src/steering/quality-metrics.js +41 -35
- package/src/steering/steering-auto-update.js +83 -86
- package/src/steering/steering-validator.js +98 -106
- package/src/steering/template-constraints.js +53 -54
- package/src/templates/agents/claude-code/CLAUDE.md +32 -32
- package/src/templates/agents/claude-code/skills/agent-assistant/SKILL.md +13 -5
- package/src/templates/agents/claude-code/skills/ai-ml-engineer/mlops-guide.md +23 -23
- package/src/templates/agents/claude-code/skills/ai-ml-engineer/model-card-template.md +60 -41
- package/src/templates/agents/claude-code/skills/api-designer/api-patterns.md +27 -19
- package/src/templates/agents/claude-code/skills/api-designer/openapi-template.md +11 -7
- package/src/templates/agents/claude-code/skills/bug-hunter/SKILL.md +4 -3
- package/src/templates/agents/claude-code/skills/bug-hunter/root-cause-analysis.md +37 -15
- package/src/templates/agents/claude-code/skills/change-impact-analyzer/dependency-graph-patterns.md +36 -42
- package/src/templates/agents/claude-code/skills/change-impact-analyzer/impact-analysis-template.md +69 -60
- package/src/templates/agents/claude-code/skills/cloud-architect/aws-patterns.md +31 -38
- package/src/templates/agents/claude-code/skills/cloud-architect/azure-patterns.md +28 -23
- package/src/templates/agents/claude-code/skills/code-reviewer/SKILL.md +61 -0
- package/src/templates/agents/claude-code/skills/code-reviewer/best-practices.md +27 -0
- package/src/templates/agents/claude-code/skills/code-reviewer/review-checklist.md +29 -10
- package/src/templates/agents/claude-code/skills/code-reviewer/review-standards.md +29 -24
- package/src/templates/agents/claude-code/skills/constitution-enforcer/SKILL.md +8 -6
- package/src/templates/agents/claude-code/skills/constitution-enforcer/constitutional-articles.md +62 -26
- package/src/templates/agents/claude-code/skills/constitution-enforcer/phase-minus-one-gates.md +35 -16
- package/src/templates/agents/claude-code/skills/database-administrator/backup-recovery.md +27 -17
- package/src/templates/agents/claude-code/skills/database-administrator/tuning-guide.md +25 -20
- package/src/templates/agents/claude-code/skills/database-schema-designer/schema-patterns.md +39 -22
- package/src/templates/agents/claude-code/skills/devops-engineer/ci-cd-templates.md +25 -22
- package/src/templates/agents/claude-code/skills/issue-resolver/SKILL.md +24 -21
- package/src/templates/agents/claude-code/skills/orchestrator/SKILL.md +148 -63
- package/src/templates/agents/claude-code/skills/orchestrator/patterns.md +35 -16
- package/src/templates/agents/claude-code/skills/orchestrator/selection-matrix.md +69 -64
- package/src/templates/agents/claude-code/skills/performance-engineer/optimization-playbook.md +47 -47
- package/src/templates/agents/claude-code/skills/performance-optimizer/SKILL.md +69 -0
- package/src/templates/agents/claude-code/skills/performance-optimizer/benchmark-template.md +63 -45
- package/src/templates/agents/claude-code/skills/performance-optimizer/optimization-patterns.md +33 -35
- package/src/templates/agents/claude-code/skills/project-manager/SKILL.md +7 -6
- package/src/templates/agents/claude-code/skills/project-manager/agile-ceremonies.md +47 -28
- package/src/templates/agents/claude-code/skills/project-manager/project-templates.md +94 -78
- package/src/templates/agents/claude-code/skills/quality-assurance/SKILL.md +20 -17
- package/src/templates/agents/claude-code/skills/quality-assurance/qa-plan-template.md +63 -49
- package/src/templates/agents/claude-code/skills/release-coordinator/SKILL.md +5 -5
- package/src/templates/agents/claude-code/skills/release-coordinator/feature-flag-guide.md +30 -26
- package/src/templates/agents/claude-code/skills/release-coordinator/release-plan-template.md +67 -35
- package/src/templates/agents/claude-code/skills/requirements-analyst/ears-format.md +54 -42
- package/src/templates/agents/claude-code/skills/requirements-analyst/validation-rules.md +36 -33
- package/src/templates/agents/claude-code/skills/security-auditor/SKILL.md +77 -19
- package/src/templates/agents/claude-code/skills/security-auditor/audit-checklists.md +24 -24
- package/src/templates/agents/claude-code/skills/security-auditor/owasp-top-10.md +61 -20
- package/src/templates/agents/claude-code/skills/security-auditor/vulnerability-patterns.md +43 -11
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/SKILL.md +1 -0
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/incident-response-template.md +55 -25
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/observability-patterns.md +78 -68
- package/src/templates/agents/claude-code/skills/site-reliability-engineer/slo-sli-guide.md +73 -53
- package/src/templates/agents/claude-code/skills/software-developer/solid-principles.md +83 -37
- package/src/templates/agents/claude-code/skills/software-developer/test-first-workflow.md +38 -31
- package/src/templates/agents/claude-code/skills/steering/SKILL.md +1 -0
- package/src/templates/agents/claude-code/skills/steering/auto-update-rules.md +31 -0
- package/src/templates/agents/claude-code/skills/system-architect/adr-template.md +25 -7
- package/src/templates/agents/claude-code/skills/system-architect/c4-model-guide.md +74 -61
- package/src/templates/agents/claude-code/skills/technical-writer/doc-templates/documentation-templates.md +70 -52
- package/src/templates/agents/claude-code/skills/test-engineer/SKILL.md +2 -0
- package/src/templates/agents/claude-code/skills/test-engineer/ears-test-mapping.md +75 -71
- package/src/templates/agents/claude-code/skills/test-engineer/test-types.md +85 -63
- package/src/templates/agents/claude-code/skills/traceability-auditor/coverage-matrix-template.md +39 -36
- package/src/templates/agents/claude-code/skills/traceability-auditor/gap-detection-rules.md +22 -17
- package/src/templates/agents/claude-code/skills/ui-ux-designer/SKILL.md +1 -0
- package/src/templates/agents/claude-code/skills/ui-ux-designer/accessibility-guidelines.md +49 -75
- package/src/templates/agents/claude-code/skills/ui-ux-designer/design-system-components.md +71 -59
- package/src/templates/agents/codex/AGENTS.md +74 -42
- package/src/templates/agents/cursor/AGENTS.md +74 -42
- package/src/templates/agents/gemini-cli/GEMINI.md +74 -42
- package/src/templates/agents/github-copilot/AGENTS.md +83 -51
- package/src/templates/agents/qwen-code/QWEN.md +74 -42
- package/src/templates/agents/windsurf/AGENTS.md +74 -42
- package/src/templates/architectures/README.md +41 -0
- package/src/templates/architectures/clean-architecture/README.md +113 -0
- package/src/templates/architectures/event-driven/README.md +162 -0
- package/src/templates/architectures/hexagonal/README.md +130 -0
- package/src/templates/index.js +6 -1
- package/src/templates/locale-manager.js +16 -16
- package/src/templates/shared/delta-spec-template.md +20 -13
- package/src/templates/shared/github-actions/musubi-issue-resolver.yml +5 -5
- package/src/templates/shared/github-actions/musubi-security-check.yml +3 -3
- package/src/templates/shared/github-actions/musubi-validate.yml +4 -4
- package/src/templates/shared/steering/structure.md +95 -0
- package/src/templates/skills/browser-agent.md +21 -16
- package/src/templates/skills/web-gui.md +8 -0
- package/src/templates/template-constraints.js +50 -53
- package/src/validators/advanced-validation.js +30 -36
- package/src/validators/constitutional-validator.js +77 -73
- package/src/validators/critic-system.js +49 -59
- package/src/validators/delta-format.js +59 -55
- 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
|
|
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
|
-
|
|
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 -
|
|
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:
|
|
206
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
83
|
-
|
|
84
|
-
'
|
|
85
|
-
|
|
86
|
-
|
|
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':
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
|
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 ?
|
|
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 ?
|
|
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 ?
|
|
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 ?
|
|
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(/([
|
|
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(
|
|
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,
|
|
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}`,
|