tryassay 0.22.0 → 0.22.2
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 +432 -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
package/demo/js/sse-client.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// sse-client.js — EventSource to AppState bridge
|
|
2
2
|
// Connects to the Assay API SSE stream and maps events to state updates
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { configureChat, addArchitectMessage, lockChat, unlockChat } from './chat.js';
|
|
5
|
+
import { downloadProject, collectProjectFiles } from './preview.js';
|
|
6
6
|
|
|
7
7
|
const AppState = window.AppState;
|
|
8
8
|
|
|
@@ -20,7 +20,6 @@ function autoApprovePlan(appId) {
|
|
|
20
20
|
}).then(res => {
|
|
21
21
|
if (res.ok) {
|
|
22
22
|
AppState.addLog({ level: 'info', message: 'Plan approved — building...' });
|
|
23
|
-
hidePlanOverlay();
|
|
24
23
|
} else {
|
|
25
24
|
console.warn('[SSE] Auto-approve failed:', res.status);
|
|
26
25
|
}
|
|
@@ -29,64 +28,23 @@ function autoApprovePlan(appId) {
|
|
|
29
28
|
});
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
function showPlanOverlay(summary) {
|
|
33
|
-
let overlay = document.getElementById('plan-overlay');
|
|
34
|
-
if (!overlay) return;
|
|
35
|
-
|
|
36
|
-
const features = (summary.features || []).map(f =>
|
|
37
|
-
`<div class="plan-feature">
|
|
38
|
-
<span class="plan-feature-name">${f.name || f.id}</span>
|
|
39
|
-
<span class="plan-feature-meta">${f.complexity} · ${f.routeCount || 0} routes · ${f.pageCount || 0} pages</span>
|
|
40
|
-
</div>`
|
|
41
|
-
).join('');
|
|
42
|
-
|
|
43
|
-
const warnings = (summary.warnings || []).map(w =>
|
|
44
|
-
`<div class="plan-warning">${w}</div>`
|
|
45
|
-
).join('');
|
|
46
|
-
|
|
47
|
-
overlay.innerHTML = `
|
|
48
|
-
<div class="plan-card">
|
|
49
|
-
<div class="plan-header">Architecture Plan</div>
|
|
50
|
-
<div class="plan-meta">
|
|
51
|
-
<span>${summary.techStack || ''}</span>
|
|
52
|
-
<span>${summary.estimatedComplexity || ''}</span>
|
|
53
|
-
<span>${summary.featureCount || 0} features</span>
|
|
54
|
-
<span>${summary.schemaEntities || 0} entities</span>
|
|
55
|
-
<span>${summary.apiRouteCount || 0} routes</span>
|
|
56
|
-
<span>${summary.pageCount || 0} pages</span>
|
|
57
|
-
</div>
|
|
58
|
-
<div class="plan-features">${features}</div>
|
|
59
|
-
${warnings ? `<div class="plan-warnings">${warnings}</div>` : ''}
|
|
60
|
-
<div class="plan-auto">Auto-approving...</div>
|
|
61
|
-
</div>
|
|
62
|
-
`;
|
|
63
|
-
overlay.classList.add('visible');
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function hidePlanOverlay() {
|
|
67
|
-
const overlay = document.getElementById('plan-overlay');
|
|
68
|
-
if (overlay) {
|
|
69
|
-
overlay.classList.remove('visible');
|
|
70
|
-
setTimeout(() => { overlay.innerHTML = ''; }, 500);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
31
|
function showCompletionOverlay(data) {
|
|
75
32
|
const overlay = document.getElementById('completion-overlay');
|
|
76
33
|
if (!overlay) return;
|
|
77
34
|
|
|
78
35
|
const m = AppState.get().metrics;
|
|
79
36
|
const appName = data.appName || 'Application';
|
|
80
|
-
const
|
|
81
|
-
const
|
|
37
|
+
const isSuccess = data.status === 'completed';
|
|
38
|
+
const status = isSuccess ? 'Build Complete' : 'Build Finished with Issues';
|
|
39
|
+
const statusClass = isSuccess ? 'success' : 'partial';
|
|
82
40
|
|
|
83
|
-
// Grab total elapsed time from the global clock
|
|
84
41
|
const clockVal = document.getElementById('clock-value');
|
|
85
42
|
const totalTime = clockVal ? clockVal.textContent : '';
|
|
86
43
|
|
|
87
44
|
overlay.innerHTML = `
|
|
88
45
|
<div class="completion-card">
|
|
89
|
-
<
|
|
46
|
+
<button class="completion-close-btn" id="completion-close" title="Close">\u00d7</button>
|
|
47
|
+
<div class="completion-icon ${statusClass}">${isSuccess ? '\u2713' : '\u26a0'}</div>
|
|
90
48
|
<div class="completion-header">${status}</div>
|
|
91
49
|
<div class="completion-app-name">${appName}</div>
|
|
92
50
|
<div class="completion-metrics">
|
|
@@ -95,85 +53,217 @@ function showCompletionOverlay(data) {
|
|
|
95
53
|
<span>${m.claimsFailed} caught</span>
|
|
96
54
|
${totalTime ? `<span>${totalTime} total</span>` : ''}
|
|
97
55
|
</div>
|
|
98
|
-
<
|
|
99
|
-
|
|
56
|
+
<div class="completion-actions">
|
|
57
|
+
<button class="completion-action-btn completion-download-btn" id="completion-download">
|
|
58
|
+
<span class="completion-action-icon">\u2913</span>
|
|
59
|
+
Download Project (.zip)
|
|
60
|
+
</button>
|
|
61
|
+
<button class="completion-action-btn completion-github-btn" id="completion-github">
|
|
62
|
+
<span class="completion-action-icon">\u2197</span>
|
|
63
|
+
Push to GitHub
|
|
64
|
+
</button>
|
|
65
|
+
</div>
|
|
66
|
+
<div class="completion-status" id="completion-status"></div>
|
|
100
67
|
</div>
|
|
101
68
|
`;
|
|
102
69
|
overlay.classList.add('visible');
|
|
103
70
|
|
|
104
|
-
|
|
105
|
-
|
|
71
|
+
// Close button — dismisses modal, reveals preview + chat
|
|
72
|
+
document.getElementById('completion-close')?.addEventListener('click', () => {
|
|
73
|
+
overlay.classList.remove('visible');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Download button — calls existing zip download from preview.js
|
|
77
|
+
document.getElementById('completion-download')?.addEventListener('click', () => {
|
|
78
|
+
downloadProject();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// GitHub button — starts GitHub export flow
|
|
82
|
+
document.getElementById('completion-github')?.addEventListener('click', () => {
|
|
83
|
+
startGitHubExport(appName);
|
|
106
84
|
});
|
|
107
85
|
}
|
|
108
86
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
87
|
+
/**
|
|
88
|
+
* GitHub export flow:
|
|
89
|
+
* 1. Check if user is authenticated via GitHub OAuth
|
|
90
|
+
* 2. If not, open OAuth popup
|
|
91
|
+
* 3. Once authenticated, show repo form and push
|
|
92
|
+
*/
|
|
93
|
+
async function startGitHubExport(appName) {
|
|
94
|
+
const statusEl = document.getElementById('completion-status');
|
|
95
|
+
const githubBtn = document.getElementById('completion-github');
|
|
117
96
|
|
|
118
|
-
|
|
119
|
-
|
|
97
|
+
// GitHub auth endpoints live on the UI server (same origin), not the API server
|
|
98
|
+
const uiOrigin = window.location.origin;
|
|
120
99
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
100
|
+
// Check auth status
|
|
101
|
+
if (statusEl) statusEl.textContent = 'Checking GitHub connection...';
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
const res = await fetch(`${uiOrigin}/api/v1/auth/github/status`);
|
|
105
|
+
const authData = await res.json();
|
|
106
|
+
|
|
107
|
+
if (!authData.configured) {
|
|
108
|
+
if (statusEl) statusEl.textContent = 'GitHub not configured. Set GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET env vars, then restart the demo.';
|
|
127
109
|
return;
|
|
128
110
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
111
|
+
|
|
112
|
+
if (authData.authenticated) {
|
|
113
|
+
showGitHubForm(appName, authData.username);
|
|
114
|
+
} else {
|
|
115
|
+
// Open OAuth popup
|
|
116
|
+
if (statusEl) statusEl.textContent = 'Opening GitHub authorization...';
|
|
117
|
+
const popup = window.open(
|
|
118
|
+
`${uiOrigin}/api/v1/auth/github`,
|
|
119
|
+
'github-oauth',
|
|
120
|
+
'width=600,height=700,menubar=no,toolbar=no'
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
// Poll for auth completion
|
|
124
|
+
const pollAuth = setInterval(async () => {
|
|
125
|
+
try {
|
|
126
|
+
if (popup && popup.closed) {
|
|
127
|
+
clearInterval(pollAuth);
|
|
128
|
+
const checkRes = await fetch(`${uiOrigin}/api/v1/auth/github/status`);
|
|
129
|
+
const checkData = await checkRes.json();
|
|
130
|
+
if (checkData.authenticated) {
|
|
131
|
+
showGitHubForm(appName, checkData.username);
|
|
132
|
+
} else {
|
|
133
|
+
if (statusEl) statusEl.textContent = 'GitHub authorization cancelled. You can still download the zip.';
|
|
134
|
+
}
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
} catch { /* keep polling */ }
|
|
138
|
+
}, 1000);
|
|
139
|
+
}
|
|
140
|
+
} catch (err) {
|
|
141
|
+
console.error('[GitHub] Auth check failed:', err);
|
|
142
|
+
if (statusEl) statusEl.textContent = 'GitHub connection unavailable. Download the zip instead.';
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function showGitHubForm(appName, username) {
|
|
147
|
+
const statusEl = document.getElementById('completion-status');
|
|
148
|
+
if (!statusEl) return;
|
|
149
|
+
|
|
150
|
+
const slugName = appName
|
|
151
|
+
.toLowerCase()
|
|
152
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
153
|
+
.replace(/^-|-$/g, '') || 'my-app';
|
|
154
|
+
|
|
155
|
+
statusEl.innerHTML = `
|
|
156
|
+
<div class="github-form">
|
|
157
|
+
<div class="github-form-row">
|
|
158
|
+
<label>Repository</label>
|
|
159
|
+
<input type="text" id="github-repo-name" value="${slugName}" placeholder="repo-name">
|
|
160
|
+
</div>
|
|
161
|
+
<div class="github-form-row">
|
|
162
|
+
<label>Visibility</label>
|
|
163
|
+
<label class="github-toggle">
|
|
164
|
+
<input type="checkbox" id="github-private" checked>
|
|
165
|
+
<span>Private</span>
|
|
166
|
+
</label>
|
|
167
|
+
</div>
|
|
168
|
+
<div class="github-form-row">
|
|
169
|
+
<span class="github-user">Pushing as ${username}</span>
|
|
170
|
+
<button class="completion-action-btn completion-github-push-btn" id="github-push">Create & Push</button>
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
`;
|
|
174
|
+
|
|
175
|
+
document.getElementById('github-push')?.addEventListener('click', () => {
|
|
176
|
+
executeGitHubPush();
|
|
134
177
|
});
|
|
135
178
|
}
|
|
136
179
|
|
|
137
|
-
function
|
|
138
|
-
const
|
|
139
|
-
const
|
|
180
|
+
async function executeGitHubPush() {
|
|
181
|
+
const repoNameEl = document.getElementById('github-repo-name');
|
|
182
|
+
const privateEl = document.getElementById('github-private');
|
|
183
|
+
const pushBtn = document.getElementById('github-push');
|
|
184
|
+
const statusEl = document.getElementById('completion-status');
|
|
140
185
|
|
|
141
|
-
|
|
142
|
-
if (apiKey) headers['Authorization'] = `Bearer ${apiKey}`;
|
|
186
|
+
if (!repoNameEl) return;
|
|
143
187
|
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
188
|
+
const repoName = repoNameEl.value.trim();
|
|
189
|
+
if (!repoName) return;
|
|
190
|
+
|
|
191
|
+
const isPrivate = privateEl?.checked ?? true;
|
|
192
|
+
|
|
193
|
+
if (pushBtn) {
|
|
194
|
+
pushBtn.disabled = true;
|
|
195
|
+
pushBtn.textContent = 'Creating repo...';
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
try {
|
|
199
|
+
// Collect files from WebContainer
|
|
200
|
+
const files = await collectProjectFiles();
|
|
201
|
+
if (files.length === 0) {
|
|
202
|
+
if (statusEl) statusEl.innerHTML = '<span class="github-error">No files found in project.</span>';
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (pushBtn) pushBtn.textContent = `Pushing ${files.length} files...`;
|
|
207
|
+
|
|
208
|
+
// Export endpoint lives on the UI server (same origin)
|
|
209
|
+
const uiOrigin = window.location.origin;
|
|
210
|
+
const res = await fetch(`${uiOrigin}/api/v1/app/${window.__appId}/export/github`, {
|
|
211
|
+
method: 'POST',
|
|
212
|
+
headers: { 'Content-Type': 'application/json' },
|
|
213
|
+
body: JSON.stringify({ repoName, private: isPrivate, files }),
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
const result = await res.json();
|
|
217
|
+
|
|
218
|
+
if (result.success && result.repoUrl) {
|
|
219
|
+
if (statusEl) {
|
|
220
|
+
statusEl.innerHTML = `
|
|
221
|
+
<div class="github-success">
|
|
222
|
+
Pushed to <a href="${result.repoUrl}" target="_blank" class="github-link">${result.repoUrl}</a>
|
|
223
|
+
</div>
|
|
224
|
+
`;
|
|
225
|
+
}
|
|
226
|
+
} else {
|
|
227
|
+
if (statusEl) {
|
|
228
|
+
statusEl.innerHTML = `<span class="github-error">${result.error || 'Push failed. Try downloading the zip instead.'}</span>`;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
} catch (err) {
|
|
232
|
+
console.error('[GitHub] Push failed:', err);
|
|
233
|
+
if (statusEl) {
|
|
234
|
+
statusEl.innerHTML = `<span class="github-error">Push failed: ${err.message}</span>`;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (pushBtn) {
|
|
239
|
+
pushBtn.disabled = false;
|
|
240
|
+
pushBtn.textContent = 'Create & Push';
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Append a compact activity item to the chat messages panel.
|
|
246
|
+
* Used during build to show real-time progress.
|
|
247
|
+
*/
|
|
248
|
+
function appendActivityItem(icon, text, className) {
|
|
249
|
+
const messagesEl = document.getElementById('chat-messages');
|
|
250
|
+
if (!messagesEl) return;
|
|
251
|
+
|
|
252
|
+
const item = document.createElement('div');
|
|
253
|
+
item.className = `activity-item ${className || ''}`;
|
|
254
|
+
|
|
255
|
+
const iconSpan = document.createElement('span');
|
|
256
|
+
iconSpan.className = 'activity-icon';
|
|
257
|
+
iconSpan.textContent = icon;
|
|
258
|
+
item.appendChild(iconSpan);
|
|
259
|
+
|
|
260
|
+
const textSpan = document.createElement('span');
|
|
261
|
+
textSpan.className = 'activity-text';
|
|
262
|
+
textSpan.textContent = text;
|
|
263
|
+
item.appendChild(textSpan);
|
|
264
|
+
|
|
265
|
+
messagesEl.appendChild(item);
|
|
266
|
+
messagesEl.scrollTop = messagesEl.scrollHeight;
|
|
177
267
|
}
|
|
178
268
|
|
|
179
269
|
// Track whether completion overlay has been shown
|
|
@@ -194,6 +284,19 @@ function handleSSEEvent(type, data) {
|
|
|
194
284
|
if (phaseName) {
|
|
195
285
|
AppState.update({ phase: phaseName });
|
|
196
286
|
|
|
287
|
+
// Activity feed: show phase changes
|
|
288
|
+
const featureName = phase.featureName || phase.featureId || data.currentFeature;
|
|
289
|
+
const phaseLabel = phaseName.replace(/_/g, ' ');
|
|
290
|
+
if (phaseName === 'provisioning_supabase') {
|
|
291
|
+
appendActivityItem('\u2601', 'Provisioning Supabase database...', 'activity-phase');
|
|
292
|
+
} else if (phaseName === 'supabase_migrations') {
|
|
293
|
+
appendActivityItem('\u2601', 'Pushing database migrations...', 'activity-phase');
|
|
294
|
+
} else if (featureName) {
|
|
295
|
+
appendActivityItem('\u25b6', `${phaseLabel} \u2014 ${featureName}`, 'activity-phase');
|
|
296
|
+
} else if (!['completed', 'failed'].includes(phaseName)) {
|
|
297
|
+
appendActivityItem('\u25b6', phaseLabel, 'activity-phase');
|
|
298
|
+
}
|
|
299
|
+
|
|
197
300
|
// Extract feature info for voice narration
|
|
198
301
|
if (phase.featureId || phase.featureName || data.currentFeature) {
|
|
199
302
|
AppState.update({
|
|
@@ -220,10 +323,7 @@ function handleSSEEvent(type, data) {
|
|
|
220
323
|
setTimeout(() => {
|
|
221
324
|
if (!completionShown) {
|
|
222
325
|
console.log('[SSE] Showing completion overlay from progress fallback');
|
|
223
|
-
|
|
224
|
-
const btn = document.getElementById('submit-btn');
|
|
225
|
-
if (input) input.disabled = false;
|
|
226
|
-
if (btn) btn.disabled = false;
|
|
326
|
+
unlockChat();
|
|
227
327
|
showCompletionOverlay({
|
|
228
328
|
status: phaseName,
|
|
229
329
|
appName: data.appName || data.currentFeature || 'Application',
|
|
@@ -243,6 +343,12 @@ function handleSSEEvent(type, data) {
|
|
|
243
343
|
} else {
|
|
244
344
|
AppState.addTask(data);
|
|
245
345
|
}
|
|
346
|
+
// Activity feed: show task completion
|
|
347
|
+
if (data.status === 'completed' && data.claims) {
|
|
348
|
+
const passed = data.claims.passed || data.claims.totalClaims - (data.claims.failed || 0) || 0;
|
|
349
|
+
const failed = data.claims.failed || 0;
|
|
350
|
+
appendActivityItem('\u2713', `${data.name || data.id} (${passed} claims, ${failed} failed)`, failed > 0 ? 'activity-warn' : 'activity-success');
|
|
351
|
+
}
|
|
246
352
|
// Extract per-feature claim counts into verification metrics
|
|
247
353
|
if (data.claims) {
|
|
248
354
|
const c = data.claims;
|
|
@@ -258,6 +364,12 @@ function handleSSEEvent(type, data) {
|
|
|
258
364
|
break;
|
|
259
365
|
}
|
|
260
366
|
case 'verification': {
|
|
367
|
+
// Activity feed: show verification results
|
|
368
|
+
if (data.passed_count !== undefined || data.failed_count !== undefined) {
|
|
369
|
+
const p = data.passed_count || 0;
|
|
370
|
+
const f = data.failed_count || 0;
|
|
371
|
+
appendActivityItem('\u2714', `Verification: ${p} passed, ${f} failed`, f > 0 ? 'activity-warn' : 'activity-success');
|
|
372
|
+
}
|
|
261
373
|
// Add the phase-level verification result
|
|
262
374
|
AppState.addVerification({
|
|
263
375
|
claim: data.claim,
|
|
@@ -281,6 +393,12 @@ function handleSSEEvent(type, data) {
|
|
|
281
393
|
language: data.language || 'typescript',
|
|
282
394
|
content: data.content
|
|
283
395
|
});
|
|
396
|
+
// Activity feed: show generated file
|
|
397
|
+
appendActivityItem('+', data.path, 'activity-file');
|
|
398
|
+
const previewPanel = document.getElementById('preview-panel');
|
|
399
|
+
if (previewPanel && !previewPanel.classList.contains('live')) {
|
|
400
|
+
previewPanel.classList.add('live');
|
|
401
|
+
}
|
|
284
402
|
break;
|
|
285
403
|
}
|
|
286
404
|
case 'agent_status': {
|
|
@@ -298,7 +416,7 @@ function handleSSEEvent(type, data) {
|
|
|
298
416
|
case 'plan_questions': {
|
|
299
417
|
AppState.update({ phase: 'plan_questioning' });
|
|
300
418
|
AppState.addLog({ level: 'info', message: `Requirements round ${data.round}: ${data.questions.length} questions (${Math.round(data.confidence * 100)}% confidence)` });
|
|
301
|
-
|
|
419
|
+
// Questions now handled via chat_message events
|
|
302
420
|
break;
|
|
303
421
|
}
|
|
304
422
|
case 'plan_readiness': {
|
|
@@ -323,12 +441,14 @@ function handleSSEEvent(type, data) {
|
|
|
323
441
|
break;
|
|
324
442
|
}
|
|
325
443
|
case 'plan_summary': {
|
|
326
|
-
// Architecture plan arrived — show
|
|
327
|
-
hideQuestions();
|
|
328
|
-
closeChat();
|
|
444
|
+
// Architecture plan arrived — show summary in chat panel
|
|
329
445
|
AppState.update({ planSummary: data });
|
|
446
|
+
appendActivityItem('\u2692', `Architecture: ${data.featureCount} features, ${data.apiRouteCount} routes, ${data.pageCount} pages`, 'activity-phase');
|
|
330
447
|
AppState.addLog({ level: 'info', message: `Architecture: ${data.featureCount} features, ${data.apiRouteCount} routes, ${data.pageCount} pages` });
|
|
331
|
-
|
|
448
|
+
const featureList = (data.features || []).map(f => `${f.name || f.id} (${f.complexity})`).join(', ');
|
|
449
|
+
addArchitectMessage({
|
|
450
|
+
message: `Architecture plan ready: ${data.featureCount} features, ${data.apiRouteCount} routes, ${data.pageCount} pages. ${featureList ? 'Features: ' + featureList + '.' : ''} Auto-approving...`,
|
|
451
|
+
});
|
|
332
452
|
break;
|
|
333
453
|
}
|
|
334
454
|
case 'awaiting_approval': {
|
|
@@ -346,9 +466,12 @@ function handleSSEEvent(type, data) {
|
|
|
346
466
|
const ftPhase = data.phase || 'functional_testing';
|
|
347
467
|
AppState.update({ phase: ftPhase });
|
|
348
468
|
if (data.passedCount !== undefined) {
|
|
349
|
-
|
|
469
|
+
const failed = data.failedCount || 0;
|
|
470
|
+
appendActivityItem('\u2731', `Testing: ${data.passedCount} passed, ${failed} failed`, failed > 0 ? 'activity-warn' : 'activity-success');
|
|
471
|
+
AppState.addLog({ level: 'info', message: `Functional: ${data.passedCount} passed, ${failed} failed` });
|
|
350
472
|
}
|
|
351
473
|
if (data.failureCount) {
|
|
474
|
+
appendActivityItem('\u21bb', `Repairing ${data.failureCount} failures (attempt ${data.attempt})`, 'activity-warn');
|
|
352
475
|
AppState.addLog({ level: 'warn', message: `Repairing ${data.failureCount} test failures (attempt ${data.attempt})` });
|
|
353
476
|
}
|
|
354
477
|
break;
|
|
@@ -356,11 +479,9 @@ function handleSSEEvent(type, data) {
|
|
|
356
479
|
case 'error': {
|
|
357
480
|
AppState.update({ phase: 'failed' });
|
|
358
481
|
AppState.addLog({ level: 'error', message: data.message || data.error || 'Unknown error' });
|
|
482
|
+
appendActivityItem('\u2718', data.message || data.error || 'Build failed', 'activity-error');
|
|
483
|
+
unlockChat();
|
|
359
484
|
if (!completionShown) {
|
|
360
|
-
const input = document.getElementById('prompt-input');
|
|
361
|
-
const btn = document.getElementById('submit-btn');
|
|
362
|
-
if (input) input.disabled = false;
|
|
363
|
-
if (btn) btn.disabled = false;
|
|
364
485
|
showCompletionOverlay({ status: 'failed', appName: 'Application' });
|
|
365
486
|
completionShown = true;
|
|
366
487
|
}
|
|
@@ -372,23 +493,26 @@ function handleSSEEvent(type, data) {
|
|
|
372
493
|
if (data.metrics) {
|
|
373
494
|
AppState.update({ metrics: data.metrics });
|
|
374
495
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
const btn = document.getElementById('submit-btn');
|
|
378
|
-
if (input) input.disabled = false;
|
|
379
|
-
if (btn) btn.disabled = false;
|
|
380
|
-
// Show completion overlay with launch button
|
|
496
|
+
appendActivityItem('\u2713', 'Build complete', 'activity-success');
|
|
497
|
+
unlockChat();
|
|
381
498
|
if (!completionShown) {
|
|
382
499
|
showCompletionOverlay(data);
|
|
383
500
|
completionShown = true;
|
|
384
501
|
}
|
|
385
|
-
// Now safe to disconnect — overlay is rendered
|
|
386
502
|
disconnect();
|
|
387
503
|
break;
|
|
388
504
|
}
|
|
389
505
|
}
|
|
390
506
|
}
|
|
391
507
|
|
|
508
|
+
function updateStatusBar() {
|
|
509
|
+
const state = AppState.get();
|
|
510
|
+
const phaseEl = document.getElementById('status-phase');
|
|
511
|
+
const tasksEl = document.getElementById('status-tasks');
|
|
512
|
+
if (phaseEl) phaseEl.textContent = `phase: ${state.phase}`;
|
|
513
|
+
if (tasksEl) tasksEl.textContent = `tasks: ${state.metrics.tasksComplete}/${state.metrics.totalTasks}`;
|
|
514
|
+
}
|
|
515
|
+
|
|
392
516
|
function connect(appId) {
|
|
393
517
|
if (eventSource) {
|
|
394
518
|
eventSource.close();
|
|
@@ -459,13 +583,16 @@ export function initSSEClient(base, key) {
|
|
|
459
583
|
apiBase = base || '';
|
|
460
584
|
apiKey = key || '';
|
|
461
585
|
|
|
462
|
-
// Share config with
|
|
463
|
-
configureQuestionCards(apiBase, apiKey);
|
|
586
|
+
// Share config with chat module
|
|
464
587
|
configureChat(apiBase, apiKey);
|
|
465
588
|
|
|
466
589
|
// Expose connect for manual invocation from bootstrap
|
|
467
590
|
window.__connectSSE = connect;
|
|
468
591
|
|
|
592
|
+
// Status bar updates
|
|
593
|
+
AppState.on('phase_change', updateStatusBar);
|
|
594
|
+
AppState.on('metric_update', updateStatusBar);
|
|
595
|
+
|
|
469
596
|
// Reset completionShown on new runs
|
|
470
597
|
AppState.on('reset', () => {
|
|
471
598
|
completionShown = false;
|
package/demo/js/state.js
CHANGED
|
@@ -18,7 +18,10 @@ const AppState = (() => {
|
|
|
18
18
|
claimsFailed: 0,
|
|
19
19
|
filesGenerated: 0
|
|
20
20
|
},
|
|
21
|
-
log: []
|
|
21
|
+
log: [],
|
|
22
|
+
containerState: 'cold', // WebContainer lifecycle: cold|warm|building|verifying|done
|
|
23
|
+
previewUrl: null, // iframe URL from WebContainer server-ready event
|
|
24
|
+
fileQueue: [] // files queued before container is ready
|
|
22
25
|
};
|
|
23
26
|
|
|
24
27
|
function on(event, fn) {
|
|
@@ -45,6 +48,7 @@ const AppState = (() => {
|
|
|
45
48
|
|
|
46
49
|
function update(partial) {
|
|
47
50
|
const oldPhase = state.phase;
|
|
51
|
+
const oldContainerState = state.containerState;
|
|
48
52
|
|
|
49
53
|
// Merge top-level primitives and objects
|
|
50
54
|
for (const key of Object.keys(partial)) {
|
|
@@ -61,6 +65,9 @@ const AppState = (() => {
|
|
|
61
65
|
if (partial.phase !== undefined && partial.phase !== oldPhase) {
|
|
62
66
|
emit('phase_change', { from: oldPhase, to: state.phase });
|
|
63
67
|
}
|
|
68
|
+
if (partial.containerState !== undefined && partial.containerState !== oldContainerState) {
|
|
69
|
+
emit('container_state_change', { from: oldContainerState, to: state.containerState });
|
|
70
|
+
}
|
|
64
71
|
if (partial.currentTask !== undefined) {
|
|
65
72
|
emit('task_update', state.currentTask);
|
|
66
73
|
}
|
|
@@ -151,6 +158,9 @@ const AppState = (() => {
|
|
|
151
158
|
state.codeFiles = [];
|
|
152
159
|
state.metrics = { tasksComplete: 0, totalTasks: 0, claimsVerified: 0, claimsFailed: 0, filesGenerated: 0 };
|
|
153
160
|
state.log = [];
|
|
161
|
+
state.containerState = 'cold';
|
|
162
|
+
state.previewUrl = null;
|
|
163
|
+
state.fileQueue = [];
|
|
154
164
|
emit('reset', null);
|
|
155
165
|
}
|
|
156
166
|
|