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.
- 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 +158 -146
- package/src/analyzers/codegraph-auto-update.js +858 -0
- package/src/analyzers/complexity-analyzer.js +536 -0
- package/src/analyzers/context-optimizer.js +241 -126
- package/src/analyzers/impact-analyzer.js +1 -1
- package/src/analyzers/large-project-analyzer.js +766 -0
- package/src/analyzers/repository-map.js +77 -81
- 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 +48 -46
- package/src/monitoring/incident-manager.js +116 -106
- package/src/monitoring/index.js +144 -134
- package/src/monitoring/observability.js +75 -62
- package/src/monitoring/quality-dashboard.js +45 -41
- package/src/monitoring/release-manager.js +63 -53
- 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
|
@@ -1,895 +1,952 @@
|
|
|
1
|
-
<!
|
|
1
|
+
<!doctype html>
|
|
2
2
|
<html lang="ja">
|
|
3
|
-
<head>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
flex: 1;
|
|
84
|
-
display: grid;
|
|
85
|
-
grid-template-columns: 280px 1fr 320px;
|
|
86
|
-
gap: 1px;
|
|
87
|
-
background: var(--border);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
.sidebar {
|
|
91
|
-
background: var(--bg-card);
|
|
92
|
-
padding: 1.5rem;
|
|
93
|
-
overflow-y: auto;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
.sidebar h2 {
|
|
97
|
-
font-size: 0.75rem;
|
|
98
|
-
font-weight: 600;
|
|
99
|
-
text-transform: uppercase;
|
|
100
|
-
letter-spacing: 0.05em;
|
|
101
|
-
color: var(--text-muted);
|
|
102
|
-
margin-bottom: 1rem;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
.nav-item {
|
|
106
|
-
display: flex;
|
|
107
|
-
align-items: center;
|
|
108
|
-
gap: 0.75rem;
|
|
109
|
-
padding: 0.75rem 1rem;
|
|
110
|
-
border-radius: 0.5rem;
|
|
111
|
-
color: var(--text-muted);
|
|
112
|
-
text-decoration: none;
|
|
113
|
-
margin-bottom: 0.25rem;
|
|
114
|
-
cursor: pointer;
|
|
115
|
-
transition: all 0.2s;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
.nav-item:hover {
|
|
119
|
-
background: rgba(99, 102, 241, 0.1);
|
|
120
|
-
color: var(--text);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
.nav-item.active {
|
|
124
|
-
background: var(--primary);
|
|
125
|
-
color: white;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
.content {
|
|
129
|
-
background: var(--bg);
|
|
130
|
-
padding: 2rem;
|
|
131
|
-
overflow-y: auto;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
.panel {
|
|
135
|
-
background: var(--bg-card);
|
|
136
|
-
padding: 1.5rem;
|
|
137
|
-
overflow-y: auto;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
.panel h3 {
|
|
141
|
-
font-size: 1rem;
|
|
142
|
-
font-weight: 600;
|
|
143
|
-
margin-bottom: 1rem;
|
|
144
|
-
display: flex;
|
|
145
|
-
align-items: center;
|
|
146
|
-
gap: 0.5rem;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
.card {
|
|
150
|
-
background: var(--bg-card);
|
|
151
|
-
border: 1px solid var(--border);
|
|
152
|
-
border-radius: 0.75rem;
|
|
153
|
-
padding: 1.5rem;
|
|
154
|
-
margin-bottom: 1rem;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
.card h3 {
|
|
158
|
-
font-size: 1.125rem;
|
|
159
|
-
font-weight: 600;
|
|
160
|
-
margin-bottom: 1rem;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
.stats-grid {
|
|
164
|
-
display: grid;
|
|
165
|
-
grid-template-columns: repeat(4, 1fr);
|
|
166
|
-
gap: 1rem;
|
|
167
|
-
margin-bottom: 2rem;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
.stat-card {
|
|
171
|
-
background: var(--bg-card);
|
|
172
|
-
border: 1px solid var(--border);
|
|
173
|
-
border-radius: 0.75rem;
|
|
174
|
-
padding: 1.25rem;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
.stat-card .label {
|
|
178
|
-
font-size: 0.875rem;
|
|
179
|
-
color: var(--text-muted);
|
|
180
|
-
margin-bottom: 0.5rem;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
.stat-card .value {
|
|
184
|
-
font-size: 2rem;
|
|
185
|
-
font-weight: 700;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
.stat-card .change {
|
|
189
|
-
font-size: 0.875rem;
|
|
190
|
-
color: var(--success);
|
|
191
|
-
margin-top: 0.25rem;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
.workflow-stage {
|
|
195
|
-
display: flex;
|
|
196
|
-
align-items: center;
|
|
197
|
-
gap: 0.75rem;
|
|
198
|
-
padding: 0.75rem;
|
|
199
|
-
background: rgba(99, 102, 241, 0.1);
|
|
200
|
-
border-radius: 0.5rem;
|
|
201
|
-
margin-bottom: 0.5rem;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
.workflow-stage.completed {
|
|
205
|
-
background: rgba(34, 197, 94, 0.1);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
.workflow-stage.active {
|
|
209
|
-
background: rgba(14, 165, 233, 0.2);
|
|
210
|
-
border: 1px solid var(--secondary);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
.stage-number {
|
|
214
|
-
width: 24px;
|
|
215
|
-
height: 24px;
|
|
216
|
-
border-radius: 50%;
|
|
217
|
-
background: var(--border);
|
|
218
|
-
display: flex;
|
|
219
|
-
align-items: center;
|
|
220
|
-
justify-content: center;
|
|
221
|
-
font-size: 0.75rem;
|
|
222
|
-
font-weight: 600;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
.workflow-stage.completed .stage-number {
|
|
226
|
-
background: var(--success);
|
|
227
|
-
color: white;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
.workflow-stage.active .stage-number {
|
|
231
|
-
background: var(--secondary);
|
|
232
|
-
color: white;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
.progress-bar {
|
|
236
|
-
height: 8px;
|
|
237
|
-
background: var(--border);
|
|
238
|
-
border-radius: 4px;
|
|
239
|
-
overflow: hidden;
|
|
240
|
-
margin-top: 1rem;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
.progress-bar-fill {
|
|
244
|
-
height: 100%;
|
|
245
|
-
background: linear-gradient(90deg, var(--primary), var(--secondary));
|
|
246
|
-
border-radius: 4px;
|
|
247
|
-
transition: width 0.3s ease;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
.requirements-list {
|
|
251
|
-
list-style: none;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
.requirement-item {
|
|
255
|
-
display: flex;
|
|
256
|
-
align-items: flex-start;
|
|
257
|
-
gap: 0.75rem;
|
|
258
|
-
padding: 0.75rem;
|
|
259
|
-
border-bottom: 1px solid var(--border);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
.requirement-item:last-child {
|
|
263
|
-
border-bottom: none;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
.req-id {
|
|
267
|
-
font-family: monospace;
|
|
268
|
-
font-size: 0.75rem;
|
|
269
|
-
background: var(--primary);
|
|
270
|
-
color: white;
|
|
271
|
-
padding: 0.25rem 0.5rem;
|
|
272
|
-
border-radius: 0.25rem;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
.req-title {
|
|
276
|
-
flex: 1;
|
|
277
|
-
font-size: 0.875rem;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
.req-status {
|
|
281
|
-
font-size: 0.75rem;
|
|
282
|
-
padding: 0.25rem 0.5rem;
|
|
283
|
-
border-radius: 0.25rem;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
.req-status.implemented {
|
|
287
|
-
background: rgba(34, 197, 94, 0.2);
|
|
288
|
-
color: var(--success);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
.req-status.designed {
|
|
292
|
-
background: rgba(14, 165, 233, 0.2);
|
|
293
|
-
color: var(--secondary);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
.req-status.unlinked {
|
|
297
|
-
background: rgba(148, 163, 184, 0.2);
|
|
298
|
-
color: var(--text-muted);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
.constitution-article {
|
|
302
|
-
padding: 1rem;
|
|
303
|
-
background: rgba(99, 102, 241, 0.05);
|
|
304
|
-
border-left: 3px solid var(--primary);
|
|
305
|
-
margin-bottom: 0.75rem;
|
|
306
|
-
border-radius: 0 0.5rem 0.5rem 0;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
.article-number {
|
|
310
|
-
font-size: 0.75rem;
|
|
311
|
-
color: var(--primary);
|
|
312
|
-
font-weight: 600;
|
|
313
|
-
margin-bottom: 0.25rem;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
.loading {
|
|
317
|
-
display: flex;
|
|
318
|
-
align-items: center;
|
|
319
|
-
justify-content: center;
|
|
320
|
-
padding: 2rem;
|
|
321
|
-
color: var(--text-muted);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
.loading-spinner {
|
|
325
|
-
width: 24px;
|
|
326
|
-
height: 24px;
|
|
327
|
-
border: 2px solid var(--border);
|
|
328
|
-
border-top-color: var(--primary);
|
|
329
|
-
border-radius: 50%;
|
|
330
|
-
animation: spin 1s linear infinite;
|
|
331
|
-
margin-right: 0.75rem;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
@keyframes spin {
|
|
335
|
-
to { transform: rotate(360deg); }
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
.empty-state {
|
|
339
|
-
text-align: center;
|
|
340
|
-
padding: 3rem;
|
|
341
|
-
color: var(--text-muted);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
.empty-state h4 {
|
|
345
|
-
font-size: 1.25rem;
|
|
346
|
-
margin-bottom: 0.5rem;
|
|
347
|
-
color: var(--text);
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
.btn {
|
|
351
|
-
display: inline-flex;
|
|
352
|
-
align-items: center;
|
|
353
|
-
gap: 0.5rem;
|
|
354
|
-
padding: 0.625rem 1rem;
|
|
355
|
-
border-radius: 0.5rem;
|
|
356
|
-
font-size: 0.875rem;
|
|
357
|
-
font-weight: 500;
|
|
358
|
-
cursor: pointer;
|
|
359
|
-
border: none;
|
|
360
|
-
transition: all 0.2s;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
.btn-primary {
|
|
364
|
-
background: var(--primary);
|
|
365
|
-
color: white;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
.btn-primary:hover {
|
|
369
|
-
background: var(--primary-dark);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
.btn-outline {
|
|
373
|
-
background: transparent;
|
|
374
|
-
border: 1px solid var(--border);
|
|
375
|
-
color: var(--text);
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
.btn-outline:hover {
|
|
379
|
-
background: rgba(255, 255, 255, 0.05);
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
footer {
|
|
383
|
-
background: var(--bg-card);
|
|
384
|
-
border-top: 1px solid var(--border);
|
|
385
|
-
padding: 1rem 2rem;
|
|
386
|
-
text-align: center;
|
|
387
|
-
font-size: 0.875rem;
|
|
388
|
-
color: var(--text-muted);
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
#traceability-graph {
|
|
392
|
-
width: 100%;
|
|
393
|
-
height: 400px;
|
|
394
|
-
background: var(--bg);
|
|
395
|
-
border-radius: 0.5rem;
|
|
396
|
-
border: 1px solid var(--border);
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
/* Modal styles */
|
|
400
|
-
.modal-overlay {
|
|
401
|
-
display: none;
|
|
402
|
-
position: fixed;
|
|
403
|
-
top: 0;
|
|
404
|
-
left: 0;
|
|
405
|
-
right: 0;
|
|
406
|
-
bottom: 0;
|
|
407
|
-
background: rgba(0, 0, 0, 0.7);
|
|
408
|
-
z-index: 1000;
|
|
409
|
-
align-items: center;
|
|
410
|
-
justify-content: center;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
.modal-overlay.active {
|
|
414
|
-
display: flex;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
.modal {
|
|
418
|
-
background: var(--bg-card);
|
|
419
|
-
border: 1px solid var(--border);
|
|
420
|
-
border-radius: 0.75rem;
|
|
421
|
-
padding: 1.5rem;
|
|
422
|
-
width: 100%;
|
|
423
|
-
max-width: 500px;
|
|
424
|
-
max-height: 90vh;
|
|
425
|
-
overflow-y: auto;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
.modal h2 {
|
|
429
|
-
font-size: 1.25rem;
|
|
430
|
-
margin-bottom: 1rem;
|
|
431
|
-
display: flex;
|
|
432
|
-
align-items: center;
|
|
433
|
-
gap: 0.5rem;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
.form-group {
|
|
437
|
-
margin-bottom: 1rem;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
.form-group label {
|
|
441
|
-
display: block;
|
|
442
|
-
font-size: 0.875rem;
|
|
443
|
-
font-weight: 500;
|
|
444
|
-
margin-bottom: 0.5rem;
|
|
445
|
-
color: var(--text-muted);
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
.form-group input,
|
|
449
|
-
.form-group select,
|
|
450
|
-
.form-group textarea {
|
|
451
|
-
width: 100%;
|
|
452
|
-
padding: 0.625rem;
|
|
453
|
-
border: 1px solid var(--border);
|
|
454
|
-
border-radius: 0.5rem;
|
|
455
|
-
background: var(--bg);
|
|
456
|
-
color: var(--text);
|
|
457
|
-
font-size: 0.875rem;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
.form-group input:focus,
|
|
461
|
-
.form-group select:focus,
|
|
462
|
-
.form-group textarea:focus {
|
|
463
|
-
outline: none;
|
|
464
|
-
border-color: var(--primary);
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
.form-group textarea {
|
|
468
|
-
min-height: 100px;
|
|
469
|
-
resize: vertical;
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
.modal-actions {
|
|
473
|
-
display: flex;
|
|
474
|
-
gap: 0.75rem;
|
|
475
|
-
justify-content: flex-end;
|
|
476
|
-
margin-top: 1.5rem;
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
@media (max-width: 1200px) {
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>MUSUBI - SDD Dashboard</title>
|
|
7
|
+
<style>
|
|
8
|
+
* {
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0;
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
:root {
|
|
15
|
+
--primary: #6366f1;
|
|
16
|
+
--primary-dark: #4f46e5;
|
|
17
|
+
--secondary: #0ea5e9;
|
|
18
|
+
--success: #22c55e;
|
|
19
|
+
--warning: #f59e0b;
|
|
20
|
+
--error: #ef4444;
|
|
21
|
+
--bg: #0f172a;
|
|
22
|
+
--bg-card: #1e293b;
|
|
23
|
+
--text: #f8fafc;
|
|
24
|
+
--text-muted: #94a3b8;
|
|
25
|
+
--border: #334155;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
body {
|
|
29
|
+
font-family:
|
|
30
|
+
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
|
|
31
|
+
background: var(--bg);
|
|
32
|
+
color: var(--text);
|
|
33
|
+
min-height: 100vh;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.app {
|
|
37
|
+
display: flex;
|
|
38
|
+
flex-direction: column;
|
|
39
|
+
min-height: 100vh;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
header {
|
|
43
|
+
background: var(--bg-card);
|
|
44
|
+
border-bottom: 1px solid var(--border);
|
|
45
|
+
padding: 1rem 2rem;
|
|
46
|
+
display: flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
justify-content: space-between;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.logo {
|
|
52
|
+
display: flex;
|
|
53
|
+
align-items: center;
|
|
54
|
+
gap: 0.75rem;
|
|
55
|
+
font-size: 1.5rem;
|
|
56
|
+
font-weight: 700;
|
|
57
|
+
color: var(--primary);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.logo-icon {
|
|
61
|
+
font-size: 2rem;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.connection-status {
|
|
65
|
+
display: flex;
|
|
66
|
+
align-items: center;
|
|
67
|
+
gap: 0.5rem;
|
|
68
|
+
font-size: 0.875rem;
|
|
69
|
+
color: var(--text-muted);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.status-dot {
|
|
73
|
+
width: 8px;
|
|
74
|
+
height: 8px;
|
|
75
|
+
border-radius: 50%;
|
|
76
|
+
background: var(--error);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.status-dot.connected {
|
|
80
|
+
background: var(--success);
|
|
81
|
+
}
|
|
82
|
+
|
|
480
83
|
main {
|
|
481
|
-
|
|
84
|
+
flex: 1;
|
|
85
|
+
display: grid;
|
|
86
|
+
grid-template-columns: 280px 1fr 320px;
|
|
87
|
+
gap: 1px;
|
|
88
|
+
background: var(--border);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.sidebar {
|
|
92
|
+
background: var(--bg-card);
|
|
93
|
+
padding: 1.5rem;
|
|
94
|
+
overflow-y: auto;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.sidebar h2 {
|
|
98
|
+
font-size: 0.75rem;
|
|
99
|
+
font-weight: 600;
|
|
100
|
+
text-transform: uppercase;
|
|
101
|
+
letter-spacing: 0.05em;
|
|
102
|
+
color: var(--text-muted);
|
|
103
|
+
margin-bottom: 1rem;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.nav-item {
|
|
107
|
+
display: flex;
|
|
108
|
+
align-items: center;
|
|
109
|
+
gap: 0.75rem;
|
|
110
|
+
padding: 0.75rem 1rem;
|
|
111
|
+
border-radius: 0.5rem;
|
|
112
|
+
color: var(--text-muted);
|
|
113
|
+
text-decoration: none;
|
|
114
|
+
margin-bottom: 0.25rem;
|
|
115
|
+
cursor: pointer;
|
|
116
|
+
transition: all 0.2s;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.nav-item:hover {
|
|
120
|
+
background: rgba(99, 102, 241, 0.1);
|
|
121
|
+
color: var(--text);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.nav-item.active {
|
|
125
|
+
background: var(--primary);
|
|
126
|
+
color: white;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.content {
|
|
130
|
+
background: var(--bg);
|
|
131
|
+
padding: 2rem;
|
|
132
|
+
overflow-y: auto;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.panel {
|
|
136
|
+
background: var(--bg-card);
|
|
137
|
+
padding: 1.5rem;
|
|
138
|
+
overflow-y: auto;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.panel h3 {
|
|
142
|
+
font-size: 1rem;
|
|
143
|
+
font-weight: 600;
|
|
144
|
+
margin-bottom: 1rem;
|
|
145
|
+
display: flex;
|
|
146
|
+
align-items: center;
|
|
147
|
+
gap: 0.5rem;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.card {
|
|
151
|
+
background: var(--bg-card);
|
|
152
|
+
border: 1px solid var(--border);
|
|
153
|
+
border-radius: 0.75rem;
|
|
154
|
+
padding: 1.5rem;
|
|
155
|
+
margin-bottom: 1rem;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.card h3 {
|
|
159
|
+
font-size: 1.125rem;
|
|
160
|
+
font-weight: 600;
|
|
161
|
+
margin-bottom: 1rem;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.stats-grid {
|
|
165
|
+
display: grid;
|
|
166
|
+
grid-template-columns: repeat(4, 1fr);
|
|
167
|
+
gap: 1rem;
|
|
168
|
+
margin-bottom: 2rem;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.stat-card {
|
|
172
|
+
background: var(--bg-card);
|
|
173
|
+
border: 1px solid var(--border);
|
|
174
|
+
border-radius: 0.75rem;
|
|
175
|
+
padding: 1.25rem;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.stat-card .label {
|
|
179
|
+
font-size: 0.875rem;
|
|
180
|
+
color: var(--text-muted);
|
|
181
|
+
margin-bottom: 0.5rem;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.stat-card .value {
|
|
185
|
+
font-size: 2rem;
|
|
186
|
+
font-weight: 700;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.stat-card .change {
|
|
190
|
+
font-size: 0.875rem;
|
|
191
|
+
color: var(--success);
|
|
192
|
+
margin-top: 0.25rem;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.workflow-stage {
|
|
196
|
+
display: flex;
|
|
197
|
+
align-items: center;
|
|
198
|
+
gap: 0.75rem;
|
|
199
|
+
padding: 0.75rem;
|
|
200
|
+
background: rgba(99, 102, 241, 0.1);
|
|
201
|
+
border-radius: 0.5rem;
|
|
202
|
+
margin-bottom: 0.5rem;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.workflow-stage.completed {
|
|
206
|
+
background: rgba(34, 197, 94, 0.1);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.workflow-stage.active {
|
|
210
|
+
background: rgba(14, 165, 233, 0.2);
|
|
211
|
+
border: 1px solid var(--secondary);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.stage-number {
|
|
215
|
+
width: 24px;
|
|
216
|
+
height: 24px;
|
|
217
|
+
border-radius: 50%;
|
|
218
|
+
background: var(--border);
|
|
219
|
+
display: flex;
|
|
220
|
+
align-items: center;
|
|
221
|
+
justify-content: center;
|
|
222
|
+
font-size: 0.75rem;
|
|
223
|
+
font-weight: 600;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.workflow-stage.completed .stage-number {
|
|
227
|
+
background: var(--success);
|
|
228
|
+
color: white;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.workflow-stage.active .stage-number {
|
|
232
|
+
background: var(--secondary);
|
|
233
|
+
color: white;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.progress-bar {
|
|
237
|
+
height: 8px;
|
|
238
|
+
background: var(--border);
|
|
239
|
+
border-radius: 4px;
|
|
240
|
+
overflow: hidden;
|
|
241
|
+
margin-top: 1rem;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.progress-bar-fill {
|
|
245
|
+
height: 100%;
|
|
246
|
+
background: linear-gradient(90deg, var(--primary), var(--secondary));
|
|
247
|
+
border-radius: 4px;
|
|
248
|
+
transition: width 0.3s ease;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.requirements-list {
|
|
252
|
+
list-style: none;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.requirement-item {
|
|
256
|
+
display: flex;
|
|
257
|
+
align-items: flex-start;
|
|
258
|
+
gap: 0.75rem;
|
|
259
|
+
padding: 0.75rem;
|
|
260
|
+
border-bottom: 1px solid var(--border);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.requirement-item:last-child {
|
|
264
|
+
border-bottom: none;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.req-id {
|
|
268
|
+
font-family: monospace;
|
|
269
|
+
font-size: 0.75rem;
|
|
270
|
+
background: var(--primary);
|
|
271
|
+
color: white;
|
|
272
|
+
padding: 0.25rem 0.5rem;
|
|
273
|
+
border-radius: 0.25rem;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.req-title {
|
|
277
|
+
flex: 1;
|
|
278
|
+
font-size: 0.875rem;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.req-status {
|
|
282
|
+
font-size: 0.75rem;
|
|
283
|
+
padding: 0.25rem 0.5rem;
|
|
284
|
+
border-radius: 0.25rem;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.req-status.implemented {
|
|
288
|
+
background: rgba(34, 197, 94, 0.2);
|
|
289
|
+
color: var(--success);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.req-status.designed {
|
|
293
|
+
background: rgba(14, 165, 233, 0.2);
|
|
294
|
+
color: var(--secondary);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.req-status.unlinked {
|
|
298
|
+
background: rgba(148, 163, 184, 0.2);
|
|
299
|
+
color: var(--text-muted);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.constitution-article {
|
|
303
|
+
padding: 1rem;
|
|
304
|
+
background: rgba(99, 102, 241, 0.05);
|
|
305
|
+
border-left: 3px solid var(--primary);
|
|
306
|
+
margin-bottom: 0.75rem;
|
|
307
|
+
border-radius: 0 0.5rem 0.5rem 0;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.article-number {
|
|
311
|
+
font-size: 0.75rem;
|
|
312
|
+
color: var(--primary);
|
|
313
|
+
font-weight: 600;
|
|
314
|
+
margin-bottom: 0.25rem;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.loading {
|
|
318
|
+
display: flex;
|
|
319
|
+
align-items: center;
|
|
320
|
+
justify-content: center;
|
|
321
|
+
padding: 2rem;
|
|
322
|
+
color: var(--text-muted);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.loading-spinner {
|
|
326
|
+
width: 24px;
|
|
327
|
+
height: 24px;
|
|
328
|
+
border: 2px solid var(--border);
|
|
329
|
+
border-top-color: var(--primary);
|
|
330
|
+
border-radius: 50%;
|
|
331
|
+
animation: spin 1s linear infinite;
|
|
332
|
+
margin-right: 0.75rem;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
@keyframes spin {
|
|
336
|
+
to {
|
|
337
|
+
transform: rotate(360deg);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.empty-state {
|
|
342
|
+
text-align: center;
|
|
343
|
+
padding: 3rem;
|
|
344
|
+
color: var(--text-muted);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.empty-state h4 {
|
|
348
|
+
font-size: 1.25rem;
|
|
349
|
+
margin-bottom: 0.5rem;
|
|
350
|
+
color: var(--text);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
.btn {
|
|
354
|
+
display: inline-flex;
|
|
355
|
+
align-items: center;
|
|
356
|
+
gap: 0.5rem;
|
|
357
|
+
padding: 0.625rem 1rem;
|
|
358
|
+
border-radius: 0.5rem;
|
|
359
|
+
font-size: 0.875rem;
|
|
360
|
+
font-weight: 500;
|
|
361
|
+
cursor: pointer;
|
|
362
|
+
border: none;
|
|
363
|
+
transition: all 0.2s;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.btn-primary {
|
|
367
|
+
background: var(--primary);
|
|
368
|
+
color: white;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.btn-primary:hover {
|
|
372
|
+
background: var(--primary-dark);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
.btn-outline {
|
|
376
|
+
background: transparent;
|
|
377
|
+
border: 1px solid var(--border);
|
|
378
|
+
color: var(--text);
|
|
482
379
|
}
|
|
483
|
-
|
|
484
|
-
.
|
|
380
|
+
|
|
381
|
+
.btn-outline:hover {
|
|
382
|
+
background: rgba(255, 255, 255, 0.05);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
footer {
|
|
386
|
+
background: var(--bg-card);
|
|
387
|
+
border-top: 1px solid var(--border);
|
|
388
|
+
padding: 1rem 2rem;
|
|
389
|
+
text-align: center;
|
|
390
|
+
font-size: 0.875rem;
|
|
391
|
+
color: var(--text-muted);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
#traceability-graph {
|
|
395
|
+
width: 100%;
|
|
396
|
+
height: 400px;
|
|
397
|
+
background: var(--bg);
|
|
398
|
+
border-radius: 0.5rem;
|
|
399
|
+
border: 1px solid var(--border);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/* Modal styles */
|
|
403
|
+
.modal-overlay {
|
|
485
404
|
display: none;
|
|
405
|
+
position: fixed;
|
|
406
|
+
top: 0;
|
|
407
|
+
left: 0;
|
|
408
|
+
right: 0;
|
|
409
|
+
bottom: 0;
|
|
410
|
+
background: rgba(0, 0, 0, 0.7);
|
|
411
|
+
z-index: 1000;
|
|
412
|
+
align-items: center;
|
|
413
|
+
justify-content: center;
|
|
486
414
|
}
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
/* Replanning Styles */
|
|
490
|
-
.replan-status {
|
|
491
|
-
display: flex;
|
|
492
|
-
align-items: center;
|
|
493
|
-
gap: 0.5rem;
|
|
494
|
-
padding: 0.75rem 1rem;
|
|
495
|
-
border-radius: 0.5rem;
|
|
496
|
-
margin-bottom: 1rem;
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
.replan-status.idle {
|
|
500
|
-
background: rgba(148, 163, 184, 0.1);
|
|
501
|
-
border: 1px solid var(--text-muted);
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
.replan-status.monitoring {
|
|
505
|
-
background: rgba(14, 165, 233, 0.1);
|
|
506
|
-
border: 1px solid var(--secondary);
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
.replan-status.replanning {
|
|
510
|
-
background: rgba(245, 158, 11, 0.1);
|
|
511
|
-
border: 1px solid var(--warning);
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
.replan-status.optimizing {
|
|
515
|
-
background: rgba(99, 102, 241, 0.1);
|
|
516
|
-
border: 1px solid var(--primary);
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
.status-indicator {
|
|
520
|
-
width: 10px;
|
|
521
|
-
height: 10px;
|
|
522
|
-
border-radius: 50%;
|
|
523
|
-
animation: pulse 2s infinite;
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
.status-indicator.idle { background: var(--text-muted); animation: none; }
|
|
527
|
-
.status-indicator.monitoring { background: var(--secondary); }
|
|
528
|
-
.status-indicator.replanning { background: var(--warning); }
|
|
529
|
-
.status-indicator.optimizing { background: var(--primary); }
|
|
530
|
-
|
|
531
|
-
@keyframes pulse {
|
|
532
|
-
0%, 100% { opacity: 1; }
|
|
533
|
-
50% { opacity: 0.5; }
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
@keyframes slideIn {
|
|
537
|
-
from { transform: translateX(100%); opacity: 0; }
|
|
538
|
-
to { transform: translateX(0); opacity: 1; }
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
@keyframes slideOut {
|
|
542
|
-
from { transform: translateX(0); opacity: 1; }
|
|
543
|
-
to { transform: translateX(100%); opacity: 0; }
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
.goal-progress {
|
|
547
|
-
display: flex;
|
|
548
|
-
flex-direction: column;
|
|
549
|
-
gap: 0.5rem;
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
.goal-item {
|
|
553
|
-
display: flex;
|
|
554
|
-
align-items: center;
|
|
555
|
-
gap: 0.75rem;
|
|
556
|
-
padding: 0.75rem;
|
|
557
|
-
background: rgba(99, 102, 241, 0.05);
|
|
558
|
-
border-radius: 0.5rem;
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
.goal-progress-bar {
|
|
562
|
-
flex: 1;
|
|
563
|
-
height: 8px;
|
|
564
|
-
background: var(--border);
|
|
565
|
-
border-radius: 4px;
|
|
566
|
-
overflow: hidden;
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
.goal-progress-fill {
|
|
570
|
-
height: 100%;
|
|
571
|
-
border-radius: 4px;
|
|
572
|
-
transition: width 0.3s ease;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
.goal-progress-fill.low { background: var(--error); }
|
|
576
|
-
.goal-progress-fill.medium { background: var(--warning); }
|
|
577
|
-
.goal-progress-fill.high { background: var(--success); }
|
|
578
|
-
|
|
579
|
-
.optimization-card {
|
|
580
|
-
display: flex;
|
|
581
|
-
flex-direction: column;
|
|
582
|
-
gap: 0.5rem;
|
|
583
|
-
padding: 1rem;
|
|
584
|
-
background: rgba(99, 102, 241, 0.1);
|
|
585
|
-
border-radius: 0.5rem;
|
|
586
|
-
margin-bottom: 0.75rem;
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
.optimization-suggestion {
|
|
590
|
-
display: flex;
|
|
591
|
-
align-items: flex-start;
|
|
592
|
-
gap: 0.5rem;
|
|
593
|
-
padding: 0.5rem;
|
|
594
|
-
background: rgba(255, 255, 255, 0.05);
|
|
595
|
-
border-radius: 0.25rem;
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
.history-timeline {
|
|
599
|
-
position: relative;
|
|
600
|
-
padding-left: 1.5rem;
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
.history-timeline::before {
|
|
604
|
-
content: '';
|
|
605
|
-
position: absolute;
|
|
606
|
-
left: 0.5rem;
|
|
607
|
-
top: 0;
|
|
608
|
-
bottom: 0;
|
|
609
|
-
width: 2px;
|
|
610
|
-
background: var(--border);
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
.history-item {
|
|
614
|
-
position: relative;
|
|
615
|
-
padding: 0.75rem;
|
|
616
|
-
background: rgba(255, 255, 255, 0.02);
|
|
617
|
-
border-radius: 0.5rem;
|
|
618
|
-
margin-bottom: 0.75rem;
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
.history-item::before {
|
|
622
|
-
content: '';
|
|
623
|
-
position: absolute;
|
|
624
|
-
left: -1.25rem;
|
|
625
|
-
top: 1rem;
|
|
626
|
-
width: 10px;
|
|
627
|
-
height: 10px;
|
|
628
|
-
border-radius: 50%;
|
|
629
|
-
background: var(--primary);
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
.history-item.success::before { background: var(--success); }
|
|
633
|
-
.history-item.warning::before { background: var(--warning); }
|
|
634
|
-
.history-item.error::before { background: var(--error); }
|
|
635
|
-
</style>
|
|
636
|
-
</head>
|
|
637
|
-
<body>
|
|
638
|
-
<div class="app">
|
|
639
|
-
<header>
|
|
640
|
-
<div class="logo">
|
|
641
|
-
<span class="logo-icon">🔮</span>
|
|
642
|
-
MUSUBI
|
|
643
|
-
</div>
|
|
644
|
-
<div class="connection-status">
|
|
645
|
-
<span class="status-dot" id="statusDot"></span>
|
|
646
|
-
<span id="statusText">Connecting...</span>
|
|
647
|
-
</div>
|
|
648
|
-
</header>
|
|
649
415
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
<div class="nav-item active" data-view="dashboard">
|
|
654
|
-
📊 Dashboard
|
|
655
|
-
</div>
|
|
656
|
-
<div class="nav-item" data-view="workflow">
|
|
657
|
-
🔄 Workflow
|
|
658
|
-
</div>
|
|
659
|
-
<div class="nav-item" data-view="requirements">
|
|
660
|
-
📋 Requirements
|
|
661
|
-
</div>
|
|
662
|
-
<div class="nav-item" data-view="traceability">
|
|
663
|
-
🔗 Traceability
|
|
664
|
-
</div>
|
|
665
|
-
<div class="nav-item" data-view="replanning">
|
|
666
|
-
🔄 Replanning
|
|
667
|
-
</div>
|
|
668
|
-
<div class="nav-item" data-view="constitution">
|
|
669
|
-
📜 Constitution
|
|
670
|
-
</div>
|
|
671
|
-
</aside>
|
|
416
|
+
.modal-overlay.active {
|
|
417
|
+
display: flex;
|
|
418
|
+
}
|
|
672
419
|
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
420
|
+
.modal {
|
|
421
|
+
background: var(--bg-card);
|
|
422
|
+
border: 1px solid var(--border);
|
|
423
|
+
border-radius: 0.75rem;
|
|
424
|
+
padding: 1.5rem;
|
|
425
|
+
width: 100%;
|
|
426
|
+
max-width: 500px;
|
|
427
|
+
max-height: 90vh;
|
|
428
|
+
overflow-y: auto;
|
|
429
|
+
}
|
|
679
430
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
431
|
+
.modal h2 {
|
|
432
|
+
font-size: 1.25rem;
|
|
433
|
+
margin-bottom: 1rem;
|
|
434
|
+
display: flex;
|
|
435
|
+
align-items: center;
|
|
436
|
+
gap: 0.5rem;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
.form-group {
|
|
440
|
+
margin-bottom: 1rem;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
.form-group label {
|
|
444
|
+
display: block;
|
|
445
|
+
font-size: 0.875rem;
|
|
446
|
+
font-weight: 500;
|
|
447
|
+
margin-bottom: 0.5rem;
|
|
448
|
+
color: var(--text-muted);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
.form-group input,
|
|
452
|
+
.form-group select,
|
|
453
|
+
.form-group textarea {
|
|
454
|
+
width: 100%;
|
|
455
|
+
padding: 0.625rem;
|
|
456
|
+
border: 1px solid var(--border);
|
|
457
|
+
border-radius: 0.5rem;
|
|
458
|
+
background: var(--bg);
|
|
459
|
+
color: var(--text);
|
|
460
|
+
font-size: 0.875rem;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
.form-group input:focus,
|
|
464
|
+
.form-group select:focus,
|
|
465
|
+
.form-group textarea:focus {
|
|
466
|
+
outline: none;
|
|
467
|
+
border-color: var(--primary);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
.form-group textarea {
|
|
471
|
+
min-height: 100px;
|
|
472
|
+
resize: vertical;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
.modal-actions {
|
|
476
|
+
display: flex;
|
|
477
|
+
gap: 0.75rem;
|
|
478
|
+
justify-content: flex-end;
|
|
479
|
+
margin-top: 1.5rem;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
@media (max-width: 1200px) {
|
|
483
|
+
main {
|
|
484
|
+
grid-template-columns: 1fr;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
.sidebar,
|
|
488
|
+
.panel {
|
|
489
|
+
display: none;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/* Replanning Styles */
|
|
494
|
+
.replan-status {
|
|
495
|
+
display: flex;
|
|
496
|
+
align-items: center;
|
|
497
|
+
gap: 0.5rem;
|
|
498
|
+
padding: 0.75rem 1rem;
|
|
499
|
+
border-radius: 0.5rem;
|
|
500
|
+
margin-bottom: 1rem;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
.replan-status.idle {
|
|
504
|
+
background: rgba(148, 163, 184, 0.1);
|
|
505
|
+
border: 1px solid var(--text-muted);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
.replan-status.monitoring {
|
|
509
|
+
background: rgba(14, 165, 233, 0.1);
|
|
510
|
+
border: 1px solid var(--secondary);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
.replan-status.replanning {
|
|
514
|
+
background: rgba(245, 158, 11, 0.1);
|
|
515
|
+
border: 1px solid var(--warning);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
.replan-status.optimizing {
|
|
519
|
+
background: rgba(99, 102, 241, 0.1);
|
|
520
|
+
border: 1px solid var(--primary);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
.status-indicator {
|
|
524
|
+
width: 10px;
|
|
525
|
+
height: 10px;
|
|
526
|
+
border-radius: 50%;
|
|
527
|
+
animation: pulse 2s infinite;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
.status-indicator.idle {
|
|
531
|
+
background: var(--text-muted);
|
|
532
|
+
animation: none;
|
|
533
|
+
}
|
|
534
|
+
.status-indicator.monitoring {
|
|
535
|
+
background: var(--secondary);
|
|
536
|
+
}
|
|
537
|
+
.status-indicator.replanning {
|
|
538
|
+
background: var(--warning);
|
|
539
|
+
}
|
|
540
|
+
.status-indicator.optimizing {
|
|
541
|
+
background: var(--primary);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
@keyframes pulse {
|
|
545
|
+
0%,
|
|
546
|
+
100% {
|
|
547
|
+
opacity: 1;
|
|
548
|
+
}
|
|
549
|
+
50% {
|
|
550
|
+
opacity: 0.5;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
@keyframes slideIn {
|
|
555
|
+
from {
|
|
556
|
+
transform: translateX(100%);
|
|
557
|
+
opacity: 0;
|
|
558
|
+
}
|
|
559
|
+
to {
|
|
560
|
+
transform: translateX(0);
|
|
561
|
+
opacity: 1;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
@keyframes slideOut {
|
|
566
|
+
from {
|
|
567
|
+
transform: translateX(0);
|
|
568
|
+
opacity: 1;
|
|
569
|
+
}
|
|
570
|
+
to {
|
|
571
|
+
transform: translateX(100%);
|
|
572
|
+
opacity: 0;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
.goal-progress {
|
|
577
|
+
display: flex;
|
|
578
|
+
flex-direction: column;
|
|
579
|
+
gap: 0.5rem;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
.goal-item {
|
|
583
|
+
display: flex;
|
|
584
|
+
align-items: center;
|
|
585
|
+
gap: 0.75rem;
|
|
586
|
+
padding: 0.75rem;
|
|
587
|
+
background: rgba(99, 102, 241, 0.05);
|
|
588
|
+
border-radius: 0.5rem;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
.goal-progress-bar {
|
|
592
|
+
flex: 1;
|
|
593
|
+
height: 8px;
|
|
594
|
+
background: var(--border);
|
|
595
|
+
border-radius: 4px;
|
|
596
|
+
overflow: hidden;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
.goal-progress-fill {
|
|
600
|
+
height: 100%;
|
|
601
|
+
border-radius: 4px;
|
|
602
|
+
transition: width 0.3s ease;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
.goal-progress-fill.low {
|
|
606
|
+
background: var(--error);
|
|
607
|
+
}
|
|
608
|
+
.goal-progress-fill.medium {
|
|
609
|
+
background: var(--warning);
|
|
610
|
+
}
|
|
611
|
+
.goal-progress-fill.high {
|
|
612
|
+
background: var(--success);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
.optimization-card {
|
|
616
|
+
display: flex;
|
|
617
|
+
flex-direction: column;
|
|
618
|
+
gap: 0.5rem;
|
|
619
|
+
padding: 1rem;
|
|
620
|
+
background: rgba(99, 102, 241, 0.1);
|
|
621
|
+
border-radius: 0.5rem;
|
|
622
|
+
margin-bottom: 0.75rem;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
.optimization-suggestion {
|
|
626
|
+
display: flex;
|
|
627
|
+
align-items: flex-start;
|
|
628
|
+
gap: 0.5rem;
|
|
629
|
+
padding: 0.5rem;
|
|
630
|
+
background: rgba(255, 255, 255, 0.05);
|
|
631
|
+
border-radius: 0.25rem;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
.history-timeline {
|
|
635
|
+
position: relative;
|
|
636
|
+
padding-left: 1.5rem;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
.history-timeline::before {
|
|
640
|
+
content: '';
|
|
641
|
+
position: absolute;
|
|
642
|
+
left: 0.5rem;
|
|
643
|
+
top: 0;
|
|
644
|
+
bottom: 0;
|
|
645
|
+
width: 2px;
|
|
646
|
+
background: var(--border);
|
|
647
|
+
}
|
|
693
648
|
|
|
694
|
-
|
|
695
|
-
|
|
649
|
+
.history-item {
|
|
650
|
+
position: relative;
|
|
651
|
+
padding: 0.75rem;
|
|
652
|
+
background: rgba(255, 255, 255, 0.02);
|
|
653
|
+
border-radius: 0.5rem;
|
|
654
|
+
margin-bottom: 0.75rem;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
.history-item::before {
|
|
658
|
+
content: '';
|
|
659
|
+
position: absolute;
|
|
660
|
+
left: -1.25rem;
|
|
661
|
+
top: 1rem;
|
|
662
|
+
width: 10px;
|
|
663
|
+
height: 10px;
|
|
664
|
+
border-radius: 50%;
|
|
665
|
+
background: var(--primary);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
.history-item.success::before {
|
|
669
|
+
background: var(--success);
|
|
670
|
+
}
|
|
671
|
+
.history-item.warning::before {
|
|
672
|
+
background: var(--warning);
|
|
673
|
+
}
|
|
674
|
+
.history-item.error::before {
|
|
675
|
+
background: var(--error);
|
|
676
|
+
}
|
|
677
|
+
</style>
|
|
678
|
+
</head>
|
|
679
|
+
<body>
|
|
680
|
+
<div class="app">
|
|
681
|
+
<header>
|
|
682
|
+
<div class="logo">
|
|
683
|
+
<span class="logo-icon">🔮</span>
|
|
684
|
+
MUSUBI
|
|
685
|
+
</div>
|
|
686
|
+
<div class="connection-status">
|
|
687
|
+
<span class="status-dot" id="statusDot"></span>
|
|
688
|
+
<span id="statusText">Connecting...</span>
|
|
689
|
+
</div>
|
|
690
|
+
</header>
|
|
691
|
+
|
|
692
|
+
<main>
|
|
693
|
+
<aside class="sidebar">
|
|
694
|
+
<h2>Navigation</h2>
|
|
695
|
+
<div class="nav-item active" data-view="dashboard">📊 Dashboard</div>
|
|
696
|
+
<div class="nav-item" data-view="workflow">🔄 Workflow</div>
|
|
697
|
+
<div class="nav-item" data-view="requirements">📋 Requirements</div>
|
|
698
|
+
<div class="nav-item" data-view="traceability">🔗 Traceability</div>
|
|
699
|
+
<div class="nav-item" data-view="replanning">🔄 Replanning</div>
|
|
700
|
+
<div class="nav-item" data-view="constitution">📜 Constitution</div>
|
|
701
|
+
</aside>
|
|
702
|
+
|
|
703
|
+
<section class="content" id="mainContent">
|
|
696
704
|
<div class="loading">
|
|
697
705
|
<div class="loading-spinner"></div>
|
|
706
|
+
Loading project data...
|
|
698
707
|
</div>
|
|
699
|
-
</
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
708
|
+
</section>
|
|
709
|
+
|
|
710
|
+
<aside class="panel">
|
|
711
|
+
<h3>📌 Quick Actions</h3>
|
|
712
|
+
<div style="margin-bottom: 1rem">
|
|
713
|
+
<button
|
|
714
|
+
class="btn btn-primary"
|
|
715
|
+
style="width: 100%; margin-bottom: 0.5rem"
|
|
716
|
+
onclick="openModal('requirementModal')"
|
|
717
|
+
>
|
|
718
|
+
➕ New Requirement
|
|
719
|
+
</button>
|
|
720
|
+
<button
|
|
721
|
+
class="btn btn-outline"
|
|
722
|
+
style="width: 100%; margin-bottom: 0.5rem"
|
|
723
|
+
onclick="runQuickAction('validate')"
|
|
724
|
+
>
|
|
725
|
+
🔍 Validate Project
|
|
726
|
+
</button>
|
|
727
|
+
<button
|
|
728
|
+
class="btn btn-outline"
|
|
729
|
+
style="width: 100%"
|
|
730
|
+
onclick="runQuickAction('export-report')"
|
|
731
|
+
>
|
|
732
|
+
📤 Export Report
|
|
733
|
+
</button>
|
|
715
734
|
</div>
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
<
|
|
721
|
-
|
|
722
|
-
<option value="interface">Interface</option>
|
|
723
|
-
</select>
|
|
724
|
-
</div>
|
|
725
|
-
<div class="form-group">
|
|
726
|
-
<label for="reqPriority">Priority</label>
|
|
727
|
-
<select id="reqPriority">
|
|
728
|
-
<option value="must">Must</option>
|
|
729
|
-
<option value="should">Should</option>
|
|
730
|
-
<option value="could">Could</option>
|
|
731
|
-
<option value="wont">Won't</option>
|
|
732
|
-
</select>
|
|
733
|
-
</div>
|
|
734
|
-
<div class="form-group">
|
|
735
|
-
<label for="reqDescription">Description (EARS Format)</label>
|
|
736
|
-
<textarea id="reqDescription" placeholder="When [trigger], the system shall [action]..." required></textarea>
|
|
737
|
-
</div>
|
|
738
|
-
<div class="form-group">
|
|
739
|
-
<label for="reqFeature">Feature</label>
|
|
740
|
-
<input type="text" id="reqFeature" placeholder="authentication" required>
|
|
741
|
-
</div>
|
|
742
|
-
<div class="modal-actions">
|
|
743
|
-
<button type="button" class="btn btn-outline" onclick="closeModal('requirementModal')">Cancel</button>
|
|
744
|
-
<button type="submit" class="btn btn-primary">Create Requirement</button>
|
|
735
|
+
|
|
736
|
+
<h3>📈 Coverage</h3>
|
|
737
|
+
<div id="coverageStats">
|
|
738
|
+
<div class="loading">
|
|
739
|
+
<div class="loading-spinner"></div>
|
|
740
|
+
</div>
|
|
745
741
|
</div>
|
|
746
|
-
</
|
|
742
|
+
</aside>
|
|
743
|
+
</main>
|
|
744
|
+
|
|
745
|
+
<!-- New Requirement Modal -->
|
|
746
|
+
<div class="modal-overlay" id="requirementModal">
|
|
747
|
+
<div class="modal">
|
|
748
|
+
<h2>📝 New Requirement</h2>
|
|
749
|
+
<form id="requirementForm" onsubmit="submitRequirement(event)">
|
|
750
|
+
<div class="form-group">
|
|
751
|
+
<label for="reqId">Requirement ID</label>
|
|
752
|
+
<input
|
|
753
|
+
type="text"
|
|
754
|
+
id="reqId"
|
|
755
|
+
placeholder="REQ-001"
|
|
756
|
+
required
|
|
757
|
+
pattern="REQ-\d{3}"
|
|
758
|
+
title="Format: REQ-001"
|
|
759
|
+
/>
|
|
760
|
+
</div>
|
|
761
|
+
<div class="form-group">
|
|
762
|
+
<label for="reqTitle">Title</label>
|
|
763
|
+
<input type="text" id="reqTitle" placeholder="User can login with email" required />
|
|
764
|
+
</div>
|
|
765
|
+
<div class="form-group">
|
|
766
|
+
<label for="reqType">Type</label>
|
|
767
|
+
<select id="reqType">
|
|
768
|
+
<option value="functional">Functional</option>
|
|
769
|
+
<option value="non-functional">Non-Functional</option>
|
|
770
|
+
<option value="constraint">Constraint</option>
|
|
771
|
+
<option value="interface">Interface</option>
|
|
772
|
+
</select>
|
|
773
|
+
</div>
|
|
774
|
+
<div class="form-group">
|
|
775
|
+
<label for="reqPriority">Priority</label>
|
|
776
|
+
<select id="reqPriority">
|
|
777
|
+
<option value="must">Must</option>
|
|
778
|
+
<option value="should">Should</option>
|
|
779
|
+
<option value="could">Could</option>
|
|
780
|
+
<option value="wont">Won't</option>
|
|
781
|
+
</select>
|
|
782
|
+
</div>
|
|
783
|
+
<div class="form-group">
|
|
784
|
+
<label for="reqDescription">Description (EARS Format)</label>
|
|
785
|
+
<textarea
|
|
786
|
+
id="reqDescription"
|
|
787
|
+
placeholder="When [trigger], the system shall [action]..."
|
|
788
|
+
required
|
|
789
|
+
></textarea>
|
|
790
|
+
</div>
|
|
791
|
+
<div class="form-group">
|
|
792
|
+
<label for="reqFeature">Feature</label>
|
|
793
|
+
<input type="text" id="reqFeature" placeholder="authentication" required />
|
|
794
|
+
</div>
|
|
795
|
+
<div class="modal-actions">
|
|
796
|
+
<button
|
|
797
|
+
type="button"
|
|
798
|
+
class="btn btn-outline"
|
|
799
|
+
onclick="closeModal('requirementModal')"
|
|
800
|
+
>
|
|
801
|
+
Cancel
|
|
802
|
+
</button>
|
|
803
|
+
<button type="submit" class="btn btn-primary">Create Requirement</button>
|
|
804
|
+
</div>
|
|
805
|
+
</form>
|
|
806
|
+
</div>
|
|
747
807
|
</div>
|
|
808
|
+
|
|
809
|
+
<footer>MUSUBI SDD - Specification Driven Development Dashboard</footer>
|
|
748
810
|
</div>
|
|
749
811
|
|
|
750
|
-
<
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
<script>
|
|
756
|
-
// State
|
|
757
|
-
let project = null;
|
|
758
|
-
let ws = null;
|
|
759
|
-
let currentView = 'dashboard';
|
|
760
|
-
|
|
761
|
-
// Modal functions
|
|
762
|
-
function openModal(modalId) {
|
|
763
|
-
document.getElementById(modalId).classList.add('active');
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
function closeModal(modalId) {
|
|
767
|
-
document.getElementById(modalId).classList.remove('active');
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
async function submitRequirement(event) {
|
|
771
|
-
event.preventDefault();
|
|
772
|
-
|
|
773
|
-
const requirement = {
|
|
774
|
-
id: document.getElementById('reqId').value,
|
|
775
|
-
title: document.getElementById('reqTitle').value,
|
|
776
|
-
type: document.getElementById('reqType').value,
|
|
777
|
-
priority: document.getElementById('reqPriority').value,
|
|
778
|
-
description: document.getElementById('reqDescription').value,
|
|
779
|
-
feature: document.getElementById('reqFeature').value,
|
|
780
|
-
};
|
|
781
|
-
|
|
782
|
-
try {
|
|
783
|
-
const response = await fetch('/api/requirements', {
|
|
784
|
-
method: 'POST',
|
|
785
|
-
headers: { 'Content-Type': 'application/json' },
|
|
786
|
-
body: JSON.stringify(requirement)
|
|
787
|
-
});
|
|
812
|
+
<script>
|
|
813
|
+
// State
|
|
814
|
+
let project = null;
|
|
815
|
+
let ws = null;
|
|
816
|
+
let currentView = 'dashboard';
|
|
788
817
|
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
818
|
+
// Modal functions
|
|
819
|
+
function openModal(modalId) {
|
|
820
|
+
document.getElementById(modalId).classList.add('active');
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
function closeModal(modalId) {
|
|
824
|
+
document.getElementById(modalId).classList.remove('active');
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
async function submitRequirement(event) {
|
|
828
|
+
event.preventDefault();
|
|
829
|
+
|
|
830
|
+
const requirement = {
|
|
831
|
+
id: document.getElementById('reqId').value,
|
|
832
|
+
title: document.getElementById('reqTitle').value,
|
|
833
|
+
type: document.getElementById('reqType').value,
|
|
834
|
+
priority: document.getElementById('reqPriority').value,
|
|
835
|
+
description: document.getElementById('reqDescription').value,
|
|
836
|
+
feature: document.getElementById('reqFeature').value,
|
|
837
|
+
};
|
|
838
|
+
|
|
839
|
+
try {
|
|
840
|
+
const response = await fetch('/api/requirements', {
|
|
841
|
+
method: 'POST',
|
|
842
|
+
headers: { 'Content-Type': 'application/json' },
|
|
843
|
+
body: JSON.stringify(requirement),
|
|
844
|
+
});
|
|
845
|
+
|
|
846
|
+
const result = await response.json();
|
|
847
|
+
|
|
848
|
+
if (result.success) {
|
|
849
|
+
showToast('✅ Requirement created successfully', 'success');
|
|
850
|
+
closeModal('requirementModal');
|
|
851
|
+
document.getElementById('requirementForm').reset();
|
|
852
|
+
loadProject(); // Refresh project data
|
|
853
|
+
} else {
|
|
854
|
+
showToast(`❌ ${result.error || 'Failed to create requirement'}`, 'error');
|
|
855
|
+
}
|
|
856
|
+
} catch (error) {
|
|
857
|
+
showToast(`❌ Error: ${error.message}`, 'error');
|
|
798
858
|
}
|
|
799
|
-
}
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
// Initialize
|
|
862
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
863
|
+
connectWebSocket();
|
|
864
|
+
loadProject();
|
|
865
|
+
setupNavigation();
|
|
866
|
+
});
|
|
867
|
+
|
|
868
|
+
// WebSocket connection
|
|
869
|
+
function connectWebSocket() {
|
|
870
|
+
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
871
|
+
ws = new WebSocket(`${protocol}//${location.host}`);
|
|
872
|
+
|
|
873
|
+
ws.onopen = () => {
|
|
874
|
+
document.getElementById('statusDot').classList.add('connected');
|
|
875
|
+
document.getElementById('statusText').textContent = 'Connected';
|
|
876
|
+
};
|
|
877
|
+
|
|
878
|
+
ws.onclose = () => {
|
|
879
|
+
document.getElementById('statusDot').classList.remove('connected');
|
|
880
|
+
document.getElementById('statusText').textContent = 'Disconnected';
|
|
881
|
+
setTimeout(connectWebSocket, 3000);
|
|
882
|
+
};
|
|
883
|
+
|
|
884
|
+
ws.onmessage = event => {
|
|
885
|
+
const message = JSON.parse(event.data);
|
|
886
|
+
handleWebSocketMessage(message);
|
|
887
|
+
};
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
function handleWebSocketMessage(message) {
|
|
891
|
+
switch (message.type) {
|
|
892
|
+
case 'project:init':
|
|
893
|
+
case 'file:changed':
|
|
894
|
+
case 'file:added':
|
|
895
|
+
case 'file:removed':
|
|
896
|
+
project = message.data.project || message.data;
|
|
897
|
+
renderCurrentView();
|
|
898
|
+
loadCoverage();
|
|
899
|
+
break;
|
|
900
|
+
case 'replanning:state':
|
|
901
|
+
handleReplanningStateUpdate(message.data);
|
|
902
|
+
break;
|
|
903
|
+
case 'replanning:event':
|
|
904
|
+
handleReplanningEvent(message.data);
|
|
905
|
+
break;
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// Replanning real-time handlers
|
|
910
|
+
function handleReplanningStateUpdate(state) {
|
|
911
|
+
// Update replanning panel if visible
|
|
912
|
+
const replanPanel = document.querySelector('.replan-status');
|
|
913
|
+
if (replanPanel) {
|
|
914
|
+
const statusText = replanPanel.querySelector('.status-text');
|
|
915
|
+
if (statusText) {
|
|
916
|
+
statusText.textContent = state.status.charAt(0).toUpperCase() + state.status.slice(1);
|
|
917
|
+
}
|
|
918
|
+
// Update status indicator class
|
|
919
|
+
replanPanel.className = 'replan-status ' + state.status;
|
|
920
|
+
}
|
|
921
|
+
// Show toast notification for status changes
|
|
922
|
+
if (state.status === 'replanning') {
|
|
923
|
+
showToast('Replanning in progress...', 'warning');
|
|
924
|
+
} else if (state.status === 'optimizing') {
|
|
925
|
+
showToast('Optimizing execution path...', 'info');
|
|
926
|
+
}
|
|
927
|
+
// Refresh replanning view if active
|
|
928
|
+
if (currentView === 'replanning') {
|
|
929
|
+
renderReplanningView();
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
function handleReplanningEvent(event) {
|
|
934
|
+
// Show notification for replan events
|
|
935
|
+
const message = event.success
|
|
936
|
+
? `Replan completed: ${event.reason || 'Optimization applied'}`
|
|
937
|
+
: `Replan failed: ${event.error || 'Unknown error'}`;
|
|
938
|
+
showToast(message, event.success ? 'success' : 'error');
|
|
939
|
+
// Refresh replanning view if active
|
|
940
|
+
if (currentView === 'replanning') {
|
|
941
|
+
renderReplanningView();
|
|
860
942
|
}
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
showToast('Optimizing execution path...', 'info');
|
|
869
|
-
}
|
|
870
|
-
// Refresh replanning view if active
|
|
871
|
-
if (currentView === 'replanning') {
|
|
872
|
-
renderReplanningView();
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
function handleReplanningEvent(event) {
|
|
877
|
-
// Show notification for replan events
|
|
878
|
-
const message = event.success
|
|
879
|
-
? `Replan completed: ${event.reason || 'Optimization applied'}`
|
|
880
|
-
: `Replan failed: ${event.error || 'Unknown error'}`;
|
|
881
|
-
showToast(message, event.success ? 'success' : 'error');
|
|
882
|
-
// Refresh replanning view if active
|
|
883
|
-
if (currentView === 'replanning') {
|
|
884
|
-
renderReplanningView();
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
function showToast(message, type = 'info') {
|
|
889
|
-
const toast = document.createElement('div');
|
|
890
|
-
toast.className = `toast toast-${type}`;
|
|
891
|
-
toast.textContent = message;
|
|
892
|
-
toast.style.cssText = `
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
function showToast(message, type = 'info') {
|
|
946
|
+
const toast = document.createElement('div');
|
|
947
|
+
toast.className = `toast toast-${type}`;
|
|
948
|
+
toast.textContent = message;
|
|
949
|
+
toast.style.cssText = `
|
|
893
950
|
position: fixed;
|
|
894
951
|
bottom: 20px;
|
|
895
952
|
right: 20px;
|
|
@@ -901,161 +958,164 @@
|
|
|
901
958
|
animation: slideIn 0.3s ease;
|
|
902
959
|
background: ${type === 'success' ? 'var(--success)' : type === 'error' ? 'var(--error)' : type === 'warning' ? 'var(--warning)' : 'var(--secondary)'};
|
|
903
960
|
`;
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
961
|
+
document.body.appendChild(toast);
|
|
962
|
+
setTimeout(() => {
|
|
963
|
+
toast.style.animation = 'slideOut 0.3s ease';
|
|
964
|
+
setTimeout(() => toast.remove(), 300);
|
|
965
|
+
}, 3000);
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// API calls
|
|
969
|
+
async function loadProject() {
|
|
970
|
+
try {
|
|
971
|
+
const response = await fetch('/api/project');
|
|
972
|
+
project = await response.json();
|
|
973
|
+
renderCurrentView();
|
|
974
|
+
} catch (error) {
|
|
975
|
+
console.error('Failed to load project:', error);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
async function loadCoverage() {
|
|
980
|
+
try {
|
|
981
|
+
const response = await fetch('/api/coverage');
|
|
982
|
+
const coverage = await response.json();
|
|
983
|
+
renderCoverage(coverage);
|
|
984
|
+
} catch (error) {
|
|
985
|
+
console.error('Failed to load coverage:', error);
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
async function loadTraceability() {
|
|
990
|
+
try {
|
|
991
|
+
const response = await fetch('/api/traceability');
|
|
992
|
+
return await response.json();
|
|
993
|
+
} catch (error) {
|
|
994
|
+
console.error('Failed to load traceability:', error);
|
|
995
|
+
return { requirements: [], traces: [] };
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
async function loadConstitution() {
|
|
1000
|
+
try {
|
|
1001
|
+
const response = await fetch('/api/constitution');
|
|
1002
|
+
return await response.json();
|
|
1003
|
+
} catch (error) {
|
|
1004
|
+
console.error('Failed to load constitution:', error);
|
|
1005
|
+
return null;
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
async function loadWorkflow() {
|
|
1010
|
+
try {
|
|
1011
|
+
const response = await fetch('/api/workflow');
|
|
1012
|
+
return await response.json();
|
|
1013
|
+
} catch (error) {
|
|
1014
|
+
console.error('Failed to load workflow:', error);
|
|
1015
|
+
return null;
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
async function loadReplanning() {
|
|
1020
|
+
try {
|
|
1021
|
+
const response = await fetch('/api/replanning/summary');
|
|
1022
|
+
return await response.json();
|
|
1023
|
+
} catch (error) {
|
|
1024
|
+
console.error('Failed to load replanning:', error);
|
|
1025
|
+
return null;
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
async function loadReplanningGoals() {
|
|
1030
|
+
try {
|
|
1031
|
+
const response = await fetch('/api/replanning/goals');
|
|
1032
|
+
return await response.json();
|
|
1033
|
+
} catch (error) {
|
|
1034
|
+
console.error('Failed to load replanning goals:', error);
|
|
1035
|
+
return { goals: [], overallProgress: 0 };
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
async function loadReplanningHistory() {
|
|
1040
|
+
try {
|
|
1041
|
+
const response = await fetch('/api/replanning/history?limit=10');
|
|
1042
|
+
return await response.json();
|
|
1043
|
+
} catch (error) {
|
|
1044
|
+
console.error('Failed to load replanning history:', error);
|
|
1045
|
+
return [];
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
async function loadReplanningOptimization() {
|
|
1050
|
+
try {
|
|
1051
|
+
const response = await fetch('/api/replanning/optimization');
|
|
1052
|
+
return await response.json();
|
|
1053
|
+
} catch (error) {
|
|
1054
|
+
console.error('Failed to load optimization:', error);
|
|
1055
|
+
return { status: 'idle', suggestions: [] };
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
// Navigation
|
|
1060
|
+
function setupNavigation() {
|
|
1061
|
+
document.querySelectorAll('.nav-item').forEach(item => {
|
|
1062
|
+
item.addEventListener('click', () => {
|
|
1063
|
+
const view = item.dataset.view;
|
|
1064
|
+
setActiveView(view);
|
|
1065
|
+
});
|
|
1008
1066
|
});
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1067
|
+
}
|
|
1011
1068
|
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1069
|
+
function setActiveView(view) {
|
|
1070
|
+
currentView = view;
|
|
1071
|
+
document.querySelectorAll('.nav-item').forEach(item => {
|
|
1072
|
+
item.classList.toggle('active', item.dataset.view === view);
|
|
1073
|
+
});
|
|
1074
|
+
renderCurrentView();
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
// Render functions
|
|
1078
|
+
function renderCurrentView() {
|
|
1079
|
+
const content = document.getElementById('mainContent');
|
|
1080
|
+
|
|
1081
|
+
switch (currentView) {
|
|
1082
|
+
case 'dashboard':
|
|
1083
|
+
renderDashboard(content);
|
|
1084
|
+
break;
|
|
1085
|
+
case 'workflow':
|
|
1086
|
+
renderWorkflow(content);
|
|
1087
|
+
break;
|
|
1088
|
+
case 'requirements':
|
|
1089
|
+
renderRequirements(content);
|
|
1090
|
+
break;
|
|
1091
|
+
case 'traceability':
|
|
1092
|
+
renderTraceability(content);
|
|
1093
|
+
break;
|
|
1094
|
+
case 'replanning':
|
|
1095
|
+
renderReplanning(content);
|
|
1096
|
+
break;
|
|
1097
|
+
case 'constitution':
|
|
1098
|
+
renderConstitution(content);
|
|
1099
|
+
break;
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
function renderDashboard(container) {
|
|
1104
|
+
if (!project) {
|
|
1105
|
+
container.innerHTML =
|
|
1106
|
+
'<div class="loading"><div class="loading-spinner"></div>Loading...</div>';
|
|
1107
|
+
return;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
const specs = project.specs || [];
|
|
1111
|
+
const totalReqs = specs.reduce((sum, s) => sum + (s.requirements?.length || 0), 0);
|
|
1112
|
+
const totalTasks = specs.reduce((sum, s) => sum + (s.tasks?.length || 0), 0);
|
|
1113
|
+
const completedTasks = specs.reduce(
|
|
1114
|
+
(sum, s) => sum + (s.tasks?.filter(t => t.completed)?.length || 0),
|
|
1115
|
+
0
|
|
1116
|
+
);
|
|
1117
|
+
|
|
1118
|
+
container.innerHTML = `
|
|
1059
1119
|
<h2 style="margin-bottom: 1.5rem;">📊 Project Dashboard</h2>
|
|
1060
1120
|
|
|
1061
1121
|
<div class="stats-grid">
|
|
@@ -1074,7 +1134,7 @@
|
|
|
1074
1134
|
<div class="stat-card">
|
|
1075
1135
|
<div class="label">Tasks</div>
|
|
1076
1136
|
<div class="value">${completedTasks}/${totalTasks}</div>
|
|
1077
|
-
<div class="change">${totalTasks > 0 ? Math.round(completedTasks/totalTasks*100) : 0}% complete</div>
|
|
1137
|
+
<div class="change">${totalTasks > 0 ? Math.round((completedTasks / totalTasks) * 100) : 0}% complete</div>
|
|
1078
1138
|
</div>
|
|
1079
1139
|
</div>
|
|
1080
1140
|
|
|
@@ -1084,204 +1144,255 @@
|
|
|
1084
1144
|
${project.hasSteering ? '✅ Steering configured' : '⚠️ No steering directory'}
|
|
1085
1145
|
${project.hasSpecs ? ' • ✅ Specs available' : ' • ⚠️ No specs yet'}
|
|
1086
1146
|
</p>
|
|
1087
|
-
${
|
|
1147
|
+
${
|
|
1148
|
+
project.constitution
|
|
1149
|
+
? `
|
|
1088
1150
|
<p style="color: var(--success);">
|
|
1089
1151
|
📜 Constitution: ${project.constitution.articles?.length || 0} articles
|
|
1090
1152
|
</p>
|
|
1091
|
-
`
|
|
1153
|
+
`
|
|
1154
|
+
: ''
|
|
1155
|
+
}
|
|
1092
1156
|
</div>
|
|
1093
1157
|
|
|
1094
|
-
${
|
|
1158
|
+
${
|
|
1159
|
+
specs.length > 0
|
|
1160
|
+
? `
|
|
1095
1161
|
<div class="card">
|
|
1096
1162
|
<h3>📁 Recent Specifications</h3>
|
|
1097
1163
|
<ul class="requirements-list">
|
|
1098
|
-
${specs
|
|
1164
|
+
${specs
|
|
1165
|
+
.slice(0, 5)
|
|
1166
|
+
.map(
|
|
1167
|
+
spec => `
|
|
1099
1168
|
<li class="requirement-item">
|
|
1100
1169
|
<span class="req-id">${spec.id}</span>
|
|
1101
1170
|
<span class="req-title">${spec.title || spec.id}</span>
|
|
1102
1171
|
<span class="req-status designed">${spec.requirements?.length || 0} reqs</span>
|
|
1103
1172
|
</li>
|
|
1104
|
-
`
|
|
1173
|
+
`
|
|
1174
|
+
)
|
|
1175
|
+
.join('')}
|
|
1105
1176
|
</ul>
|
|
1106
1177
|
</div>
|
|
1107
|
-
`
|
|
1178
|
+
`
|
|
1179
|
+
: ''
|
|
1180
|
+
}
|
|
1108
1181
|
`;
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
async function renderWorkflow(container) {
|
|
1185
|
+
container.innerHTML =
|
|
1186
|
+
'<div class="loading"><div class="loading-spinner"></div>Loading workflow...</div>';
|
|
1187
|
+
|
|
1188
|
+
const workflow = await loadWorkflow();
|
|
1189
|
+
|
|
1190
|
+
if (!workflow || !workflow.stages) {
|
|
1191
|
+
container.innerHTML = `
|
|
1118
1192
|
<h2 style="margin-bottom: 1.5rem;">🔄 Workflow</h2>
|
|
1119
1193
|
<div class="empty-state">
|
|
1120
1194
|
<h4>No workflow defined</h4>
|
|
1121
1195
|
<p>Create a workflow configuration in steering/rules/workflow.md</p>
|
|
1122
1196
|
</div>
|
|
1123
1197
|
`;
|
|
1124
|
-
|
|
1125
|
-
|
|
1198
|
+
return;
|
|
1199
|
+
}
|
|
1126
1200
|
|
|
1127
|
-
|
|
1201
|
+
container.innerHTML = `
|
|
1128
1202
|
<h2 style="margin-bottom: 1.5rem;">🔄 Workflow</h2>
|
|
1129
1203
|
|
|
1130
1204
|
<div class="card">
|
|
1131
1205
|
<h3>SDD Stages</h3>
|
|
1132
|
-
${workflow.stages
|
|
1206
|
+
${workflow.stages
|
|
1207
|
+
.map(
|
|
1208
|
+
(stage, i) => `
|
|
1133
1209
|
<div class="workflow-stage ${stage.status}">
|
|
1134
1210
|
<span class="stage-number">${i + 1}</span>
|
|
1135
1211
|
<span>${stage.name}</span>
|
|
1136
1212
|
</div>
|
|
1137
|
-
`
|
|
1213
|
+
`
|
|
1214
|
+
)
|
|
1215
|
+
.join('')}
|
|
1138
1216
|
</div>
|
|
1139
1217
|
`;
|
|
1140
|
-
}
|
|
1141
|
-
|
|
1142
|
-
async function renderRequirements(container) {
|
|
1143
|
-
if (!project || !project.specs) {
|
|
1144
|
-
container.innerHTML = '<div class="loading"><div class="loading-spinner"></div>Loading...</div>';
|
|
1145
|
-
return;
|
|
1146
1218
|
}
|
|
1147
1219
|
|
|
1148
|
-
|
|
1149
|
-
(
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1220
|
+
async function renderRequirements(container) {
|
|
1221
|
+
if (!project || !project.specs) {
|
|
1222
|
+
container.innerHTML =
|
|
1223
|
+
'<div class="loading"><div class="loading-spinner"></div>Loading...</div>';
|
|
1224
|
+
return;
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
const allReqs = project.specs.flatMap(spec =>
|
|
1228
|
+
(spec.requirements || []).map(req => ({
|
|
1229
|
+
...req,
|
|
1230
|
+
specId: spec.id,
|
|
1231
|
+
}))
|
|
1232
|
+
);
|
|
1154
1233
|
|
|
1155
|
-
|
|
1234
|
+
container.innerHTML = `
|
|
1156
1235
|
<h2 style="margin-bottom: 1.5rem;">📋 Requirements</h2>
|
|
1157
1236
|
|
|
1158
|
-
${
|
|
1237
|
+
${
|
|
1238
|
+
allReqs.length > 0
|
|
1239
|
+
? `
|
|
1159
1240
|
<div class="card">
|
|
1160
1241
|
<h3>All Requirements (${allReqs.length})</h3>
|
|
1161
1242
|
<ul class="requirements-list">
|
|
1162
|
-
${allReqs
|
|
1243
|
+
${allReqs
|
|
1244
|
+
.map(
|
|
1245
|
+
req => `
|
|
1163
1246
|
<li class="requirement-item">
|
|
1164
1247
|
<span class="req-id">${req.id}</span>
|
|
1165
1248
|
<span class="req-title" title="${req.body || ''}">${req.body?.substring(0, 80) || req.id}...</span>
|
|
1166
1249
|
<span class="req-status designed">${req.pattern}</span>
|
|
1167
1250
|
</li>
|
|
1168
|
-
`
|
|
1251
|
+
`
|
|
1252
|
+
)
|
|
1253
|
+
.join('')}
|
|
1169
1254
|
</ul>
|
|
1170
1255
|
</div>
|
|
1171
|
-
`
|
|
1256
|
+
`
|
|
1257
|
+
: `
|
|
1172
1258
|
<div class="empty-state">
|
|
1173
1259
|
<h4>No Requirements</h4>
|
|
1174
1260
|
<p>Create requirements using musubi-requirements command</p>
|
|
1175
1261
|
</div>
|
|
1176
|
-
`
|
|
1262
|
+
`
|
|
1263
|
+
}
|
|
1177
1264
|
`;
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
async function renderTraceability(container) {
|
|
1268
|
+
container.innerHTML =
|
|
1269
|
+
'<div class="loading"><div class="loading-spinner"></div>Loading traceability...</div>';
|
|
1270
|
+
|
|
1271
|
+
const matrix = await loadTraceability();
|
|
1272
|
+
|
|
1273
|
+
container.innerHTML = `
|
|
1186
1274
|
<h2 style="margin-bottom: 1.5rem;">🔗 Traceability Matrix</h2>
|
|
1187
1275
|
|
|
1188
1276
|
<div class="card">
|
|
1189
1277
|
<h3>Requirements → Implementation</h3>
|
|
1190
|
-
${
|
|
1278
|
+
${
|
|
1279
|
+
matrix.requirements?.length > 0
|
|
1280
|
+
? `
|
|
1191
1281
|
<ul class="requirements-list">
|
|
1192
|
-
${matrix.requirements
|
|
1282
|
+
${matrix.requirements
|
|
1283
|
+
.map(
|
|
1284
|
+
req => `
|
|
1193
1285
|
<li class="requirement-item">
|
|
1194
1286
|
<span class="req-id">${req.id}</span>
|
|
1195
1287
|
<span class="req-title">${req.specTitle || ''}</span>
|
|
1196
1288
|
<span class="req-status ${req.status || 'unlinked'}">${req.status || 'unlinked'}</span>
|
|
1197
1289
|
</li>
|
|
1198
|
-
`
|
|
1290
|
+
`
|
|
1291
|
+
)
|
|
1292
|
+
.join('')}
|
|
1199
1293
|
</ul>
|
|
1200
|
-
`
|
|
1294
|
+
`
|
|
1295
|
+
: `
|
|
1201
1296
|
<div class="empty-state">
|
|
1202
1297
|
<p>No requirements to trace</p>
|
|
1203
1298
|
</div>
|
|
1204
|
-
`
|
|
1299
|
+
`
|
|
1300
|
+
}
|
|
1205
1301
|
</div>
|
|
1206
1302
|
|
|
1207
1303
|
<div class="card">
|
|
1208
1304
|
<h3>📊 Trace Links (${matrix.traces?.length || 0})</h3>
|
|
1209
|
-
${
|
|
1305
|
+
${
|
|
1306
|
+
matrix.traces?.length > 0
|
|
1307
|
+
? `
|
|
1210
1308
|
<ul class="requirements-list">
|
|
1211
|
-
${matrix.traces
|
|
1309
|
+
${matrix.traces
|
|
1310
|
+
.slice(0, 10)
|
|
1311
|
+
.map(
|
|
1312
|
+
trace => `
|
|
1212
1313
|
<li class="requirement-item">
|
|
1213
1314
|
<span class="req-id">${trace.from}</span>
|
|
1214
1315
|
<span style="color: var(--text-muted);">→</span>
|
|
1215
1316
|
<span class="req-id" style="background: var(--secondary);">${trace.to}</span>
|
|
1216
1317
|
<span class="req-title">${trace.type}</span>
|
|
1217
1318
|
</li>
|
|
1218
|
-
`
|
|
1319
|
+
`
|
|
1320
|
+
)
|
|
1321
|
+
.join('')}
|
|
1219
1322
|
</ul>
|
|
1220
|
-
`
|
|
1323
|
+
`
|
|
1324
|
+
: '<p style="color: var(--text-muted); padding: 1rem;">No trace links found</p>'
|
|
1325
|
+
}
|
|
1221
1326
|
</div>
|
|
1222
1327
|
`;
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
async function renderConstitution(container) {
|
|
1331
|
+
container.innerHTML =
|
|
1332
|
+
'<div class="loading"><div class="loading-spinner"></div>Loading constitution...</div>';
|
|
1333
|
+
|
|
1334
|
+
const constitution = await loadConstitution();
|
|
1335
|
+
|
|
1336
|
+
if (!constitution || !constitution.articles) {
|
|
1337
|
+
container.innerHTML = `
|
|
1232
1338
|
<h2 style="margin-bottom: 1.5rem;">📜 Constitution</h2>
|
|
1233
1339
|
<div class="empty-state">
|
|
1234
1340
|
<h4>No Constitution</h4>
|
|
1235
1341
|
<p>Create a constitution in steering/rules/constitution.md</p>
|
|
1236
1342
|
</div>
|
|
1237
1343
|
`;
|
|
1238
|
-
|
|
1239
|
-
|
|
1344
|
+
return;
|
|
1345
|
+
}
|
|
1240
1346
|
|
|
1241
|
-
|
|
1347
|
+
container.innerHTML = `
|
|
1242
1348
|
<h2 style="margin-bottom: 1.5rem;">📜 Constitution</h2>
|
|
1243
1349
|
|
|
1244
1350
|
<div class="card">
|
|
1245
1351
|
<h3>Articles (${constitution.articles.length})</h3>
|
|
1246
|
-
${constitution.articles
|
|
1352
|
+
${constitution.articles
|
|
1353
|
+
.map(
|
|
1354
|
+
article => `
|
|
1247
1355
|
<div class="constitution-article">
|
|
1248
1356
|
<div class="article-number">Article ${article.number}</div>
|
|
1249
1357
|
<div>${article.title}</div>
|
|
1250
1358
|
</div>
|
|
1251
|
-
`
|
|
1359
|
+
`
|
|
1360
|
+
)
|
|
1361
|
+
.join('')}
|
|
1252
1362
|
</div>
|
|
1253
1363
|
`;
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
async function renderReplanning(container) {
|
|
1367
|
+
container.innerHTML =
|
|
1368
|
+
'<div class="loading"><div class="loading-spinner"></div>Loading replanning state...</div>';
|
|
1369
|
+
|
|
1370
|
+
const [summary, goals, history, optimization] = await Promise.all([
|
|
1371
|
+
loadReplanning(),
|
|
1372
|
+
loadReplanningGoals(),
|
|
1373
|
+
loadReplanningHistory(),
|
|
1374
|
+
loadReplanningOptimization(),
|
|
1375
|
+
]);
|
|
1376
|
+
|
|
1377
|
+
const statusLabels = {
|
|
1378
|
+
idle: 'Idle',
|
|
1379
|
+
monitoring: 'Monitoring',
|
|
1380
|
+
evaluating: 'Evaluating',
|
|
1381
|
+
replanning: 'Replanning',
|
|
1382
|
+
optimizing: 'Optimizing',
|
|
1383
|
+
};
|
|
1384
|
+
|
|
1385
|
+
const statusIcons = {
|
|
1386
|
+
idle: '⏸️',
|
|
1387
|
+
monitoring: '👁️',
|
|
1388
|
+
evaluating: '🔍',
|
|
1389
|
+
replanning: '🔄',
|
|
1390
|
+
optimizing: '⚡',
|
|
1391
|
+
};
|
|
1392
|
+
|
|
1393
|
+
const status = summary?.status || 'idle';
|
|
1394
|
+
|
|
1395
|
+
container.innerHTML = `
|
|
1285
1396
|
<h2 style="margin-bottom: 1.5rem;">🔄 Replanning Engine</h2>
|
|
1286
1397
|
|
|
1287
1398
|
<!-- Status Card -->
|
|
@@ -1316,10 +1427,14 @@
|
|
|
1316
1427
|
<div class="card">
|
|
1317
1428
|
<h3>🎯 Goal Progress</h3>
|
|
1318
1429
|
<div class="goal-progress">
|
|
1319
|
-
${
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1430
|
+
${
|
|
1431
|
+
goals.goals?.length > 0
|
|
1432
|
+
? goals.goals
|
|
1433
|
+
.slice(0, 5)
|
|
1434
|
+
.map(goal => {
|
|
1435
|
+
const progress = goal.progress || 0;
|
|
1436
|
+
const level = progress < 33 ? 'low' : progress < 66 ? 'medium' : 'high';
|
|
1437
|
+
return `
|
|
1323
1438
|
<div class="goal-item">
|
|
1324
1439
|
<span style="flex-shrink: 0; width: 80px; font-size: 0.875rem;">${goal.id || 'Goal'}</span>
|
|
1325
1440
|
<div class="goal-progress-bar">
|
|
@@ -1328,14 +1443,19 @@
|
|
|
1328
1443
|
<span style="flex-shrink: 0; width: 40px; text-align: right; font-size: 0.875rem;">${progress}%</span>
|
|
1329
1444
|
</div>
|
|
1330
1445
|
`;
|
|
1331
|
-
|
|
1446
|
+
})
|
|
1447
|
+
.join('')
|
|
1448
|
+
: `
|
|
1332
1449
|
<div style="color: var(--text-muted); padding: 1rem; text-align: center;">
|
|
1333
1450
|
<p>No goals registered</p>
|
|
1334
1451
|
<p style="font-size: 0.875rem; margin-top: 0.5rem;">Use <code>npx musubi-orchestrate goal register</code></p>
|
|
1335
1452
|
</div>
|
|
1336
|
-
`
|
|
1453
|
+
`
|
|
1454
|
+
}
|
|
1337
1455
|
</div>
|
|
1338
|
-
${
|
|
1456
|
+
${
|
|
1457
|
+
goals.goals?.length > 0
|
|
1458
|
+
? `
|
|
1339
1459
|
<div class="progress-bar" style="margin-top: 1rem;">
|
|
1340
1460
|
<div class="progress-bar-fill" style="width: ${goals.overallProgress || 0}%"></div>
|
|
1341
1461
|
</div>
|
|
@@ -1343,7 +1463,9 @@
|
|
|
1343
1463
|
<span>Active: ${summary?.goalProgress?.active || 0}</span>
|
|
1344
1464
|
<span>Completed: ${summary?.goalProgress?.completed || 0}</span>
|
|
1345
1465
|
</div>
|
|
1346
|
-
`
|
|
1466
|
+
`
|
|
1467
|
+
: ''
|
|
1468
|
+
}
|
|
1347
1469
|
</div>
|
|
1348
1470
|
|
|
1349
1471
|
<!-- Path Optimization -->
|
|
@@ -1354,24 +1476,37 @@
|
|
|
1354
1476
|
<span class="status-indicator ${optimization.status || 'idle'}"></span>
|
|
1355
1477
|
<span style="font-weight: 500;">${optimization.status === 'active' ? 'Optimization Active' : 'Awaiting Optimization'}</span>
|
|
1356
1478
|
</div>
|
|
1357
|
-
${
|
|
1479
|
+
${
|
|
1480
|
+
optimization.potentialSavings
|
|
1481
|
+
? `
|
|
1358
1482
|
<div style="color: var(--success); font-size: 0.875rem;">
|
|
1359
1483
|
💡 Potential savings: ${optimization.potentialSavings}%
|
|
1360
1484
|
</div>
|
|
1361
|
-
`
|
|
1485
|
+
`
|
|
1486
|
+
: ''
|
|
1487
|
+
}
|
|
1362
1488
|
</div>
|
|
1363
1489
|
|
|
1364
1490
|
<h4 style="font-size: 0.875rem; color: var(--text-muted); margin-bottom: 0.5rem;">Suggestions</h4>
|
|
1365
|
-
${
|
|
1491
|
+
${
|
|
1492
|
+
optimization.suggestions?.length > 0
|
|
1493
|
+
? optimization.suggestions
|
|
1494
|
+
.slice(0, 3)
|
|
1495
|
+
.map(
|
|
1496
|
+
sug => `
|
|
1366
1497
|
<div class="optimization-suggestion">
|
|
1367
1498
|
<span>💡</span>
|
|
1368
1499
|
<span style="font-size: 0.875rem;">${sug.description || sug}</span>
|
|
1369
1500
|
</div>
|
|
1370
|
-
`
|
|
1501
|
+
`
|
|
1502
|
+
)
|
|
1503
|
+
.join('')
|
|
1504
|
+
: `
|
|
1371
1505
|
<div style="color: var(--text-muted); padding: 0.5rem; text-align: center; font-size: 0.875rem;">
|
|
1372
1506
|
No optimization suggestions
|
|
1373
1507
|
</div>
|
|
1374
|
-
`
|
|
1508
|
+
`
|
|
1509
|
+
}
|
|
1375
1510
|
<div style="margin-top: 1rem;">
|
|
1376
1511
|
<code style="font-size: 0.75rem; color: var(--text-muted);">npx musubi-orchestrate optimize run</code>
|
|
1377
1512
|
</div>
|
|
@@ -1381,13 +1516,23 @@
|
|
|
1381
1516
|
<!-- Replan History -->
|
|
1382
1517
|
<div class="card" style="margin-top: 1rem;">
|
|
1383
1518
|
<h3>📜 Recent Replan History</h3>
|
|
1384
|
-
${
|
|
1519
|
+
${
|
|
1520
|
+
history?.length > 0
|
|
1521
|
+
? `
|
|
1385
1522
|
<div class="history-timeline">
|
|
1386
|
-
${history
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1523
|
+
${history
|
|
1524
|
+
.slice(0, 8)
|
|
1525
|
+
.map(event => {
|
|
1526
|
+
const eventClass =
|
|
1527
|
+
event.success === false
|
|
1528
|
+
? 'error'
|
|
1529
|
+
: event.trigger === 'warning'
|
|
1530
|
+
? 'warning'
|
|
1531
|
+
: 'success';
|
|
1532
|
+
const time = event.timestamp
|
|
1533
|
+
? new Date(event.timestamp).toLocaleString('ja-JP')
|
|
1534
|
+
: 'Unknown';
|
|
1535
|
+
return `
|
|
1391
1536
|
<div class="history-item ${eventClass}">
|
|
1392
1537
|
<div style="display: flex; justify-content: space-between; margin-bottom: 0.25rem;">
|
|
1393
1538
|
<span style="font-weight: 500;">${event.trigger || event.type || 'Replan'}</span>
|
|
@@ -1396,21 +1541,28 @@
|
|
|
1396
1541
|
<div style="font-size: 0.875rem; color: var(--text-muted);">
|
|
1397
1542
|
${event.reason || event.description || 'Plan adjusted'}
|
|
1398
1543
|
</div>
|
|
1399
|
-
${
|
|
1544
|
+
${
|
|
1545
|
+
event.confidence
|
|
1546
|
+
? `
|
|
1400
1547
|
<div style="font-size: 0.75rem; color: var(--primary); margin-top: 0.25rem;">
|
|
1401
1548
|
Confidence: ${Math.round(event.confidence * 100)}%
|
|
1402
1549
|
</div>
|
|
1403
|
-
`
|
|
1550
|
+
`
|
|
1551
|
+
: ''
|
|
1552
|
+
}
|
|
1404
1553
|
</div>
|
|
1405
1554
|
`;
|
|
1406
|
-
|
|
1555
|
+
})
|
|
1556
|
+
.join('')}
|
|
1407
1557
|
</div>
|
|
1408
|
-
`
|
|
1558
|
+
`
|
|
1559
|
+
: `
|
|
1409
1560
|
<div style="color: var(--text-muted); padding: 1rem; text-align: center;">
|
|
1410
1561
|
<p>No replan history yet</p>
|
|
1411
1562
|
<p style="font-size: 0.875rem; margin-top: 0.5rem;">Replanning events will appear here</p>
|
|
1412
1563
|
</div>
|
|
1413
|
-
`
|
|
1564
|
+
`
|
|
1565
|
+
}
|
|
1414
1566
|
</div>
|
|
1415
1567
|
|
|
1416
1568
|
<!-- CLI Commands Reference -->
|
|
@@ -1436,12 +1588,12 @@
|
|
|
1436
1588
|
</div>
|
|
1437
1589
|
</div>
|
|
1438
1590
|
`;
|
|
1439
|
-
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
function renderCoverage(coverage) {
|
|
1594
|
+
const container = document.getElementById('coverageStats');
|
|
1440
1595
|
|
|
1441
|
-
|
|
1442
|
-
const container = document.getElementById('coverageStats');
|
|
1443
|
-
|
|
1444
|
-
container.innerHTML = `
|
|
1596
|
+
container.innerHTML = `
|
|
1445
1597
|
<div style="margin-bottom: 1rem;">
|
|
1446
1598
|
<div style="display: flex; justify-content: space-between; margin-bottom: 0.5rem;">
|
|
1447
1599
|
<span>Total</span>
|
|
@@ -1460,64 +1612,66 @@
|
|
|
1460
1612
|
</div>
|
|
1461
1613
|
</div>
|
|
1462
1614
|
`;
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
// Quick Actions
|
|
1466
|
-
async function runQuickAction(action) {
|
|
1467
|
-
const button = event.target;
|
|
1468
|
-
const originalText = button.innerHTML;
|
|
1469
|
-
button.disabled = true;
|
|
1470
|
-
button.innerHTML = '⏳ Processing...';
|
|
1471
|
-
|
|
1472
|
-
try {
|
|
1473
|
-
const response = await fetch(`/api/actions/${action}`, {
|
|
1474
|
-
method: 'POST',
|
|
1475
|
-
headers: { 'Content-Type': 'application/json' }
|
|
1476
|
-
});
|
|
1477
|
-
const result = await response.json();
|
|
1615
|
+
}
|
|
1478
1616
|
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
if (action === '
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
a.click();
|
|
1503
|
-
URL.revokeObjectURL(url);
|
|
1617
|
+
// Quick Actions
|
|
1618
|
+
async function runQuickAction(action) {
|
|
1619
|
+
const button = event.target;
|
|
1620
|
+
const originalText = button.innerHTML;
|
|
1621
|
+
button.disabled = true;
|
|
1622
|
+
button.innerHTML = '⏳ Processing...';
|
|
1623
|
+
|
|
1624
|
+
try {
|
|
1625
|
+
const response = await fetch(`/api/actions/${action}`, {
|
|
1626
|
+
method: 'POST',
|
|
1627
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1628
|
+
});
|
|
1629
|
+
const result = await response.json();
|
|
1630
|
+
|
|
1631
|
+
if (action === 'validate') {
|
|
1632
|
+
if (result.success) {
|
|
1633
|
+
showToast('✅ Validation passed', 'success');
|
|
1634
|
+
} else {
|
|
1635
|
+
showToast('⚠️ Validation completed with issues', 'warning');
|
|
1636
|
+
}
|
|
1637
|
+
// Show output in console and optionally in a modal
|
|
1638
|
+
if (result.output) {
|
|
1639
|
+
console.log('Validation output:', result.output);
|
|
1504
1640
|
}
|
|
1505
|
-
|
|
1506
|
-
|
|
1641
|
+
if (result.errors) {
|
|
1642
|
+
console.log('Validation errors:', result.errors);
|
|
1643
|
+
}
|
|
1644
|
+
} else if (result.success) {
|
|
1645
|
+
if (action === 'export-report') {
|
|
1646
|
+
showToast('📤 Report exported', 'success');
|
|
1647
|
+
if (result.report) {
|
|
1648
|
+
// Download report as JSON
|
|
1649
|
+
const blob = new Blob([JSON.stringify(result.report, null, 2)], {
|
|
1650
|
+
type: 'application/json',
|
|
1651
|
+
});
|
|
1652
|
+
const url = URL.createObjectURL(blob);
|
|
1653
|
+
const a = document.createElement('a');
|
|
1654
|
+
a.href = url;
|
|
1655
|
+
a.download = 'musubi-report.json';
|
|
1656
|
+
a.click();
|
|
1657
|
+
URL.revokeObjectURL(url);
|
|
1658
|
+
}
|
|
1659
|
+
} else if (action === 'new-requirement') {
|
|
1660
|
+
showToast('📝 Requirements wizard started in terminal', 'info');
|
|
1661
|
+
}
|
|
1662
|
+
} else {
|
|
1663
|
+
showToast(`❌ ${result.error || 'Action failed'}`, 'error');
|
|
1507
1664
|
}
|
|
1508
|
-
}
|
|
1509
|
-
showToast(`❌ ${
|
|
1665
|
+
} catch (error) {
|
|
1666
|
+
showToast(`❌ Error: ${error.message}`, 'error');
|
|
1667
|
+
} finally {
|
|
1668
|
+
button.disabled = false;
|
|
1669
|
+
button.innerHTML = originalText;
|
|
1510
1670
|
}
|
|
1511
|
-
}
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
}
|
|
1518
|
-
|
|
1519
|
-
// Initial load
|
|
1520
|
-
loadCoverage();
|
|
1521
|
-
</script>
|
|
1522
|
-
</body>
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
// Initial load
|
|
1674
|
+
loadCoverage();
|
|
1675
|
+
</script>
|
|
1676
|
+
</body>
|
|
1523
1677
|
</html>
|