tryassay 0.22.0 → 0.22.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/demo/css/style.css +495 -836
- package/demo/index.html +40 -184
- package/demo/js/chat.js +385 -142
- package/demo/js/preview.js +456 -0
- package/demo/js/sse-client.js +262 -135
- package/demo/js/state.js +11 -1
- package/demo/js/timeline.js +57 -371
- package/dist/api/server.d.ts +2 -0
- package/dist/api/server.js +63 -19
- package/dist/api/server.js.map +1 -1
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/assess.d.ts +2 -0
- package/dist/commands/assess.js +132 -164
- package/dist/commands/assess.js.map +1 -1
- package/dist/commands/demo.js +259 -9
- package/dist/commands/demo.js.map +1 -1
- package/dist/lib/__tests__/arithmetic-quick-test.d.ts +6 -0
- package/dist/lib/__tests__/arithmetic-quick-test.js +197 -0
- package/dist/lib/__tests__/arithmetic-quick-test.js.map +1 -0
- package/dist/lib/__tests__/arithmetic-real-llm-test.d.ts +13 -0
- package/dist/lib/__tests__/arithmetic-real-llm-test.js +284 -0
- package/dist/lib/__tests__/arithmetic-real-llm-test.js.map +1 -0
- package/dist/lib/__tests__/arithmetic-value-demo.d.ts +10 -0
- package/dist/lib/__tests__/arithmetic-value-demo.js +193 -0
- package/dist/lib/__tests__/arithmetic-value-demo.js.map +1 -0
- package/dist/lib/__tests__/flow-to-claims.test.d.ts +1 -0
- package/dist/lib/__tests__/flow-to-claims.test.js +91 -0
- package/dist/lib/__tests__/flow-to-claims.test.js.map +1 -0
- package/dist/lib/__tests__/formal-verifier-api-misuse.test.d.ts +9 -0
- package/dist/lib/__tests__/formal-verifier-api-misuse.test.js +391 -0
- package/dist/lib/__tests__/formal-verifier-api-misuse.test.js.map +1 -0
- package/dist/lib/__tests__/formal-verifier-arithmetic.test.d.ts +7 -0
- package/dist/lib/__tests__/formal-verifier-arithmetic.test.js +318 -0
- package/dist/lib/__tests__/formal-verifier-arithmetic.test.js.map +1 -0
- package/dist/lib/__tests__/intent-extractor.test.d.ts +1 -0
- package/dist/lib/__tests__/intent-extractor.test.js +97 -0
- package/dist/lib/__tests__/intent-extractor.test.js.map +1 -0
- package/dist/lib/__tests__/intent-reviewer.test.d.ts +1 -0
- package/dist/lib/__tests__/intent-reviewer.test.js +55 -0
- package/dist/lib/__tests__/intent-reviewer.test.js.map +1 -0
- package/dist/lib/__tests__/mr-gsm8k-benchmark.d.ts +11 -0
- package/dist/lib/__tests__/mr-gsm8k-benchmark.js +224 -0
- package/dist/lib/__tests__/mr-gsm8k-benchmark.js.map +1 -0
- package/dist/lib/anthropic.js +25 -33
- package/dist/lib/anthropic.js.map +1 -1
- package/dist/lib/assessment-reporter.js +9 -13
- package/dist/lib/assessment-reporter.js.map +1 -1
- package/dist/lib/claim-extractor.js +10 -19
- package/dist/lib/claim-extractor.js.map +1 -1
- package/dist/lib/code-verifier.js +16 -36
- package/dist/lib/code-verifier.js.map +1 -1
- package/dist/lib/constraint-engine.js +10 -19
- package/dist/lib/constraint-engine.js.map +1 -1
- package/dist/lib/formal-verifier.d.ts +1 -1
- package/dist/lib/formal-verifier.js +454 -0
- package/dist/lib/formal-verifier.js.map +1 -1
- package/dist/lib/guided-generator.js +19 -37
- package/dist/lib/guided-generator.js.map +1 -1
- package/dist/lib/intent-extractor.d.ts +47 -0
- package/dist/lib/intent-extractor.js +427 -0
- package/dist/lib/intent-extractor.js.map +1 -0
- package/dist/lib/intent-reviewer.d.ts +14 -0
- package/dist/lib/intent-reviewer.js +148 -0
- package/dist/lib/intent-reviewer.js.map +1 -0
- package/dist/lib/intent-types.d.ts +89 -0
- package/dist/lib/intent-types.js +5 -0
- package/dist/lib/intent-types.js.map +1 -0
- package/dist/lib/inventory-extractor.js +9 -22
- package/dist/lib/inventory-extractor.js.map +1 -1
- package/dist/lib/llm-provider.d.ts +23 -0
- package/dist/lib/llm-provider.js +130 -0
- package/dist/lib/llm-provider.js.map +1 -0
- package/dist/lib/remediator.js +20 -28
- package/dist/lib/remediator.js.map +1 -1
- package/dist/lib/requirements-generator.js +14 -19
- package/dist/lib/requirements-generator.js.map +1 -1
- package/dist/lib/spec-synthesizer.js +10 -19
- package/dist/lib/spec-synthesizer.js.map +1 -1
- package/dist/runtime/app-create-orchestrator.d.ts +5 -1
- package/dist/runtime/app-create-orchestrator.js +114 -39
- package/dist/runtime/app-create-orchestrator.js.map +1 -1
- package/dist/runtime/check-catalog.js +5 -3
- package/dist/runtime/check-catalog.js.map +1 -1
- package/dist/runtime/check-definitions.d.ts +10 -0
- package/dist/runtime/check-definitions.js +52 -2
- package/dist/runtime/check-definitions.js.map +1 -1
- package/dist/runtime/composition-verifier.js +8 -12
- package/dist/runtime/composition-verifier.js.map +1 -1
- package/dist/runtime/gap-detector.js +8 -10
- package/dist/runtime/gap-detector.js.map +1 -1
- package/dist/runtime/input-validator.d.ts +7 -0
- package/dist/runtime/input-validator.js +162 -0
- package/dist/runtime/input-validator.js.map +1 -0
- package/dist/runtime/model-router.d.ts +10 -0
- package/dist/runtime/model-router.js +42 -0
- package/dist/runtime/model-router.js.map +1 -0
- package/dist/runtime/pattern-extractor.js +8 -10
- package/dist/runtime/pattern-extractor.js.map +1 -1
- package/dist/runtime/planner.js +11 -16
- package/dist/runtime/planner.js.map +1 -1
- package/dist/runtime/prompt-guard.d.ts +2 -0
- package/dist/runtime/prompt-guard.js +180 -0
- package/dist/runtime/prompt-guard.js.map +1 -0
- package/dist/runtime/prompt-safety-analyzer.js +8 -13
- package/dist/runtime/prompt-safety-analyzer.js.map +1 -1
- package/dist/runtime/reasoner.js +19 -33
- package/dist/runtime/reasoner.js.map +1 -1
- package/dist/runtime/rule-meta-verifier.js +9 -11
- package/dist/runtime/rule-meta-verifier.js.map +1 -1
- package/dist/runtime/safe-executor.d.ts +23 -0
- package/dist/runtime/safe-executor.js +151 -0
- package/dist/runtime/safe-executor.js.map +1 -0
- package/dist/runtime/specialized-agent.js +10 -14
- package/dist/runtime/specialized-agent.js.map +1 -1
- package/dist/runtime/strategy-library.js +8 -10
- package/dist/runtime/strategy-library.js.map +1 -1
- package/dist/runtime/supabase-experience-store.js.map +1 -1
- package/dist/runtime/supabase-provisioner.d.ts +35 -0
- package/dist/runtime/supabase-provisioner.js +192 -0
- package/dist/runtime/supabase-provisioner.js.map +1 -0
- package/dist/runtime/types.d.ts +88 -0
- package/dist/sdk/forward-verify.js +16 -33
- package/dist/sdk/forward-verify.js.map +1 -1
- package/package.json +1 -1
- package/demo/data/demo-events.json +0 -103
- package/demo/js/demo-mode.js +0 -107
- package/demo/js/orb.js +0 -634
- package/demo/js/question-cards.js +0 -207
- package/demo/js/voice.js +0 -154
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
// question-cards.js — Interactive question cards for plan mode
|
|
2
|
-
// Renders in the #plan-overlay when the backend sends plan_questions events
|
|
3
|
-
|
|
4
|
-
const AppState = window.AppState;
|
|
5
|
-
|
|
6
|
-
let currentSessionId = null;
|
|
7
|
-
let currentSelections = {}; // { questionId: [selectedOptionLabels] }
|
|
8
|
-
let currentQuestions = [];
|
|
9
|
-
let sseConfig = { apiBase: '', apiKey: '' };
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Configure API connection (called from sse-client.js)
|
|
13
|
-
*/
|
|
14
|
-
export function configureQuestionCards(apiBase, apiKey) {
|
|
15
|
-
sseConfig.apiBase = apiBase || '';
|
|
16
|
-
sseConfig.apiKey = apiKey || '';
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Show question cards in the plan overlay.
|
|
21
|
-
* Called when a plan_questions SSE event arrives.
|
|
22
|
-
*/
|
|
23
|
-
export function showQuestions({ questions, round, confidence, sessionId }) {
|
|
24
|
-
const overlay = document.getElementById('plan-overlay');
|
|
25
|
-
if (!overlay) return;
|
|
26
|
-
|
|
27
|
-
currentSessionId = sessionId;
|
|
28
|
-
currentQuestions = questions;
|
|
29
|
-
currentSelections = {};
|
|
30
|
-
|
|
31
|
-
// Initialize selections for each question
|
|
32
|
-
for (const q of questions) {
|
|
33
|
-
currentSelections[q.id] = [];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const questionsHTML = questions.map(q => renderQuestion(q)).join('');
|
|
37
|
-
|
|
38
|
-
overlay.innerHTML = `
|
|
39
|
-
<div class="plan-card plan-questions-card">
|
|
40
|
-
<div class="plan-questions-header">
|
|
41
|
-
<div class="plan-header">Refine Requirements</div>
|
|
42
|
-
<div class="plan-round">Round ${round} of 3</div>
|
|
43
|
-
</div>
|
|
44
|
-
<div class="confidence-meter">
|
|
45
|
-
<div class="confidence-bar">
|
|
46
|
-
<div class="confidence-fill" style="width: ${Math.round(confidence * 100)}%"></div>
|
|
47
|
-
</div>
|
|
48
|
-
<div class="confidence-label">Requirements Clarity: ${Math.round(confidence * 100)}%</div>
|
|
49
|
-
</div>
|
|
50
|
-
<div class="plan-questions">${questionsHTML}</div>
|
|
51
|
-
<button class="confirm-selections-btn" id="confirm-selections-btn" disabled>Confirm Selections</button>
|
|
52
|
-
</div>
|
|
53
|
-
`;
|
|
54
|
-
|
|
55
|
-
overlay.classList.add('visible');
|
|
56
|
-
|
|
57
|
-
// Bind option click handlers
|
|
58
|
-
overlay.querySelectorAll('.question-option').forEach(el => {
|
|
59
|
-
el.addEventListener('click', () => handleOptionClick(el));
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
// Bind confirm button
|
|
63
|
-
document.getElementById('confirm-selections-btn')?.addEventListener('click', handleConfirm);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Hide question cards and clear the overlay.
|
|
68
|
-
*/
|
|
69
|
-
export function hideQuestions() {
|
|
70
|
-
const overlay = document.getElementById('plan-overlay');
|
|
71
|
-
if (overlay) {
|
|
72
|
-
overlay.classList.remove('visible');
|
|
73
|
-
setTimeout(() => { overlay.innerHTML = ''; }, 500);
|
|
74
|
-
}
|
|
75
|
-
currentSelections = {};
|
|
76
|
-
currentQuestions = [];
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// ── Internal ──
|
|
80
|
-
|
|
81
|
-
function renderQuestion(q) {
|
|
82
|
-
const hint = q.multiSelect ? 'Select all that apply' : 'Select one';
|
|
83
|
-
const optionsHTML = q.options.map(opt => `
|
|
84
|
-
<div class="question-option"
|
|
85
|
-
data-question-id="${q.id}"
|
|
86
|
-
data-option-label="${escapeAttr(opt.label)}"
|
|
87
|
-
data-multi="${q.multiSelect}">
|
|
88
|
-
<div class="option-label">${escapeHTML(opt.label)}</div>
|
|
89
|
-
<div class="option-description">${escapeHTML(opt.description)}</div>
|
|
90
|
-
</div>
|
|
91
|
-
`).join('');
|
|
92
|
-
|
|
93
|
-
return `
|
|
94
|
-
<div class="question-card" data-question-id="${q.id}">
|
|
95
|
-
<div class="question-header">${escapeHTML(q.header)}</div>
|
|
96
|
-
<div class="question-text">${escapeHTML(q.question)}</div>
|
|
97
|
-
<div class="select-hint">${hint}</div>
|
|
98
|
-
<div class="question-options">${optionsHTML}</div>
|
|
99
|
-
</div>
|
|
100
|
-
`;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function handleOptionClick(el) {
|
|
104
|
-
const questionId = el.dataset.questionId;
|
|
105
|
-
const label = el.dataset.optionLabel;
|
|
106
|
-
const isMulti = el.dataset.multi === 'true';
|
|
107
|
-
|
|
108
|
-
if (isMulti) {
|
|
109
|
-
// Toggle this option
|
|
110
|
-
el.classList.toggle('selected');
|
|
111
|
-
const idx = currentSelections[questionId].indexOf(label);
|
|
112
|
-
if (idx >= 0) {
|
|
113
|
-
currentSelections[questionId].splice(idx, 1);
|
|
114
|
-
} else {
|
|
115
|
-
currentSelections[questionId].push(label);
|
|
116
|
-
}
|
|
117
|
-
} else {
|
|
118
|
-
// Single select — deselect siblings, select this one
|
|
119
|
-
const siblings = document.querySelectorAll(`.question-option[data-question-id="${questionId}"]`);
|
|
120
|
-
siblings.forEach(s => s.classList.remove('selected'));
|
|
121
|
-
el.classList.add('selected');
|
|
122
|
-
currentSelections[questionId] = [label];
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
updateConfirmButton();
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function updateConfirmButton() {
|
|
129
|
-
const btn = document.getElementById('confirm-selections-btn');
|
|
130
|
-
if (!btn) return;
|
|
131
|
-
|
|
132
|
-
// All single-select questions must have exactly one answer
|
|
133
|
-
const allSingleAnswered = currentQuestions
|
|
134
|
-
.filter(q => !q.multiSelect)
|
|
135
|
-
.every(q => currentSelections[q.id]?.length > 0);
|
|
136
|
-
|
|
137
|
-
btn.disabled = !allSingleAnswered;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
async function handleConfirm() {
|
|
141
|
-
const btn = document.getElementById('confirm-selections-btn');
|
|
142
|
-
if (btn) {
|
|
143
|
-
btn.disabled = true;
|
|
144
|
-
btn.textContent = 'Submitting...';
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const answers = Object.entries(currentSelections).map(([questionId, selectedOptions]) => ({
|
|
148
|
-
questionId,
|
|
149
|
-
selectedOptions,
|
|
150
|
-
}));
|
|
151
|
-
|
|
152
|
-
const headers = { 'Content-Type': 'application/json' };
|
|
153
|
-
if (sseConfig.apiKey) headers['Authorization'] = `Bearer ${sseConfig.apiKey}`;
|
|
154
|
-
|
|
155
|
-
const sessionId = currentSessionId || window.__appId;
|
|
156
|
-
|
|
157
|
-
try {
|
|
158
|
-
const res = await fetch(`${sseConfig.apiBase}/api/v1/app/${sessionId}/answers`, {
|
|
159
|
-
method: 'POST',
|
|
160
|
-
headers,
|
|
161
|
-
body: JSON.stringify({ answers }),
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
if (!res.ok) {
|
|
165
|
-
console.error('[QuestionCards] Submit failed:', res.status);
|
|
166
|
-
AppState.addLog({ level: 'error', message: `Failed to submit answers: ${res.status}` });
|
|
167
|
-
if (btn) {
|
|
168
|
-
btn.disabled = false;
|
|
169
|
-
btn.textContent = 'Confirm Selections';
|
|
170
|
-
}
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
} catch (err) {
|
|
174
|
-
console.error('[QuestionCards] Submit error:', err);
|
|
175
|
-
AppState.addLog({ level: 'error', message: `Submit error: ${err.message}` });
|
|
176
|
-
if (btn) {
|
|
177
|
-
btn.disabled = false;
|
|
178
|
-
btn.textContent = 'Confirm Selections';
|
|
179
|
-
}
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Show refining state
|
|
184
|
-
const overlay = document.getElementById('plan-overlay');
|
|
185
|
-
if (overlay) {
|
|
186
|
-
overlay.innerHTML = `
|
|
187
|
-
<div class="plan-card">
|
|
188
|
-
<div class="refining-state">
|
|
189
|
-
<div class="refining-spinner"></div>
|
|
190
|
-
<div>Refining requirements...</div>
|
|
191
|
-
</div>
|
|
192
|
-
</div>
|
|
193
|
-
`;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
AppState.addLog({ level: 'info', message: 'Answers submitted. Refining requirements...' });
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function escapeHTML(str) {
|
|
200
|
-
const div = document.createElement('div');
|
|
201
|
-
div.textContent = str;
|
|
202
|
-
return div.innerHTML;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
function escapeAttr(str) {
|
|
206
|
-
return str.replace(/"/g, '"').replace(/'/g, ''');
|
|
207
|
-
}
|
package/demo/js/voice.js
DELETED
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
// voice.js — ElevenLabs TTS narration
|
|
2
|
-
// High-quality voice synthesis per phase transition
|
|
3
|
-
|
|
4
|
-
const API_URL = 'https://api.elevenlabs.io/v1/text-to-speech';
|
|
5
|
-
const API_KEY = 'sk_80c5021a889afdd474a7f9920cb0b73981ec38c912f9cecf';
|
|
6
|
-
|
|
7
|
-
// Josh — deep young male narrator, fits sci-fi/tech aesthetic
|
|
8
|
-
const VOICE_ID = 'TxGEqnHWrfWFTfGW9XjX';
|
|
9
|
-
|
|
10
|
-
let isMuted = false;
|
|
11
|
-
let currentAudio = null;
|
|
12
|
-
let audioQueue = [];
|
|
13
|
-
let isPlaying = false;
|
|
14
|
-
|
|
15
|
-
const NARRATION = {
|
|
16
|
-
initializing: 'Analyzing your request. Breaking it down into an architecture plan.',
|
|
17
|
-
planning: 'Designing the application structure. Identifying components, routes, and data models.',
|
|
18
|
-
verifying_plan: 'Verifying the architecture. Extracting claims and checking each one against formal rules.',
|
|
19
|
-
requirements_refining: 'Architecture plan generated. Reviewing features, routes, and data models before building.',
|
|
20
|
-
scaffolding: 'Plan approved. Scaffolding the project. Creating the file structure and base configuration.',
|
|
21
|
-
building_feature: null,
|
|
22
|
-
build_verifying: 'Verifying the generated code. Checking for security issues, type errors, and logic bugs.',
|
|
23
|
-
build_repairing: 'Build issues detected. Repairing automatically.',
|
|
24
|
-
integration_verifying: 'Running integration verification. Checking cross-feature consistency.',
|
|
25
|
-
functional_testing: 'Running functional tests. Starting the application and testing every route with real HTTP requests.',
|
|
26
|
-
functional_repairing: 'Functional test failures detected. Feeding errors back to the code agent for repair.',
|
|
27
|
-
cross_verifying: 'Cross-verifying all features together. Checking that routes connect, schemas match, and imports resolve.',
|
|
28
|
-
finalizing: 'Finalizing the application. All verifications passed.',
|
|
29
|
-
completed: null
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
async function synthesize(text) {
|
|
33
|
-
const res = await fetch(`${API_URL}/${VOICE_ID}`, {
|
|
34
|
-
method: 'POST',
|
|
35
|
-
headers: {
|
|
36
|
-
'Content-Type': 'application/json',
|
|
37
|
-
'xi-api-key': API_KEY
|
|
38
|
-
},
|
|
39
|
-
body: JSON.stringify({
|
|
40
|
-
text,
|
|
41
|
-
model_id: 'eleven_multilingual_v2',
|
|
42
|
-
voice_settings: {
|
|
43
|
-
stability: 0.6,
|
|
44
|
-
similarity_boost: 0.8,
|
|
45
|
-
style: 0.3,
|
|
46
|
-
use_speaker_boost: true
|
|
47
|
-
}
|
|
48
|
-
})
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
if (!res.ok) {
|
|
52
|
-
console.error('[Voice] ElevenLabs API error:', res.status, await res.text());
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const blob = await res.blob();
|
|
57
|
-
return URL.createObjectURL(blob);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function playNext() {
|
|
61
|
-
if (isPlaying || audioQueue.length === 0 || isMuted) return;
|
|
62
|
-
|
|
63
|
-
isPlaying = true;
|
|
64
|
-
const audioUrl = audioQueue.shift();
|
|
65
|
-
|
|
66
|
-
currentAudio = new Audio(audioUrl);
|
|
67
|
-
currentAudio.addEventListener('ended', () => {
|
|
68
|
-
URL.revokeObjectURL(audioUrl);
|
|
69
|
-
currentAudio = null;
|
|
70
|
-
isPlaying = false;
|
|
71
|
-
playNext();
|
|
72
|
-
});
|
|
73
|
-
currentAudio.addEventListener('error', () => {
|
|
74
|
-
URL.revokeObjectURL(audioUrl);
|
|
75
|
-
currentAudio = null;
|
|
76
|
-
isPlaying = false;
|
|
77
|
-
playNext();
|
|
78
|
-
});
|
|
79
|
-
currentAudio.play().catch(() => {
|
|
80
|
-
isPlaying = false;
|
|
81
|
-
playNext();
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
async function speak(text) {
|
|
86
|
-
if (isMuted || !text) return;
|
|
87
|
-
|
|
88
|
-
// Synthesize in background, queue when ready
|
|
89
|
-
const audioUrl = await synthesize(text);
|
|
90
|
-
if (audioUrl && !isMuted) {
|
|
91
|
-
audioQueue.push(audioUrl);
|
|
92
|
-
playNext();
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function stopAll() {
|
|
97
|
-
if (currentAudio) {
|
|
98
|
-
currentAudio.pause();
|
|
99
|
-
currentAudio = null;
|
|
100
|
-
}
|
|
101
|
-
// Revoke any queued URLs
|
|
102
|
-
audioQueue.forEach(url => URL.revokeObjectURL(url));
|
|
103
|
-
audioQueue = [];
|
|
104
|
-
isPlaying = false;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function getNarration(phase) {
|
|
108
|
-
const state = window.AppState;
|
|
109
|
-
|
|
110
|
-
if (phase === 'building_feature') {
|
|
111
|
-
const taskName = state.get().currentTask?.name || 'current feature';
|
|
112
|
-
return `Building feature: ${taskName}. Generating the implementation.`;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (phase === 'completed') {
|
|
116
|
-
const m = state.get().metrics;
|
|
117
|
-
return `Application complete. ${m.filesGenerated} files generated. ${m.claimsVerified} claims verified. ${m.claimsFailed} issues caught and fixed.`;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return NARRATION[phase] || null;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function initMuteButton() {
|
|
124
|
-
const btn = document.getElementById('mute-toggle');
|
|
125
|
-
if (!btn) return;
|
|
126
|
-
|
|
127
|
-
btn.addEventListener('click', () => {
|
|
128
|
-
isMuted = !isMuted;
|
|
129
|
-
if (isMuted) {
|
|
130
|
-
btn.textContent = '\uD83D\uDD07';
|
|
131
|
-
btn.classList.add('muted');
|
|
132
|
-
stopAll();
|
|
133
|
-
} else {
|
|
134
|
-
btn.textContent = '\uD83D\uDD0A';
|
|
135
|
-
btn.classList.remove('muted');
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export function initVoice() {
|
|
141
|
-
const state = window.AppState;
|
|
142
|
-
if (!state) return;
|
|
143
|
-
|
|
144
|
-
initMuteButton();
|
|
145
|
-
|
|
146
|
-
state.on('phase_change', ({ to }) => {
|
|
147
|
-
const text = getNarration(to);
|
|
148
|
-
if (text) speak(text);
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
state.on('reset', () => {
|
|
152
|
-
stopAll();
|
|
153
|
-
});
|
|
154
|
-
}
|