@echomem/mcp 1.4.20 → 1.4.21
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/dist/crypto.js +4 -0
- package/dist/encryption.js +14 -2
- package/dist/index.js +52 -117
- package/dist/migrate.js +38 -1
- package/dist/setup-page/client-core.js +194 -27
- package/dist/setup-page/client-extraction.js +73 -35
- package/dist/setup-page/client-lifecycle.js +1 -5
- package/dist/setup-page/styles-extraction.js +125 -0
- package/dist/setup-page.js +1 -0
- package/dist/setup-preview.js +127 -38
- package/dist/setup.js +275 -31
- package/dist/v1-contract.js +1 -11
- package/package.json +6 -2
|
@@ -93,30 +93,17 @@ export const SETUP_PAGE_CLIENT_EXTRACTION = String.raw ` /* ---------- dash
|
|
|
93
93
|
'<div class="actions"><button id="logout" class="secondary">Retry sign out</button></div></div>';
|
|
94
94
|
var lo = document.getElementById("logout"); if (lo) lo.onclick = localLogout;
|
|
95
95
|
}
|
|
96
|
-
async function waitForConnection() {
|
|
97
|
-
if (connectionPollStarted) return;
|
|
98
|
-
connectionPollStarted = true;
|
|
99
|
-
try {
|
|
100
|
-
for (;;) {
|
|
101
|
-
if (decisionMade) return;
|
|
102
|
-
try {
|
|
103
|
-
var cfg = await getJson("/config");
|
|
104
|
-
authUrl = cfg.authUrl || authUrl;
|
|
105
|
-
switchAccountUrl = cfg.switchAccountUrl || switchAccountUrl || authUrl;
|
|
106
|
-
if (cfg.connected) { connected = true; closeAuthWindow(); await waitForStats(); return; }
|
|
107
|
-
} catch (_) {}
|
|
108
|
-
await sleep(900);
|
|
109
|
-
}
|
|
110
|
-
} finally { connectionPollStarted = false; }
|
|
111
|
-
}
|
|
112
|
-
function startConnectionPoll() { void waitForConnection(); }
|
|
113
96
|
async function waitForStats() {
|
|
114
97
|
if (statsPollStarted) return;
|
|
115
98
|
statsPollStarted = true;
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
99
|
+
setCityMode(false);
|
|
100
|
+
setExtractMode(false);
|
|
101
|
+
setReadyMode(true);
|
|
102
|
+
setHead("Checking extraction", "Working");
|
|
103
|
+
app.className = "loading-panel";
|
|
104
|
+
app.innerHTML = '<div style="padding:24px"><h2>Checking for active work</h2><p class="helper">Echo is reconnecting to any extraction already running on this machine.</p></div>';
|
|
119
105
|
try {
|
|
106
|
+
if (await resumeExistingExtraction()) return;
|
|
120
107
|
var started = Date.now();
|
|
121
108
|
var lastError = "";
|
|
122
109
|
for (;;) {
|
|
@@ -301,21 +288,74 @@ export const SETUP_PAGE_CLIENT_EXTRACTION = String.raw ` /* ---------- dash
|
|
|
301
288
|
setHead("Extracting", "Starting");
|
|
302
289
|
app.className = "";
|
|
303
290
|
app.innerHTML = '<div class="miniLoad"><h2>Starting extraction</h2><p>Echo is sizing the remaining jobs, then imports automatically. Finished work is saved as it goes.</p><div class="miniBar"><i></i></div></div>';
|
|
291
|
+
var started;
|
|
304
292
|
try {
|
|
305
|
-
|
|
306
|
-
extractMounted = false;
|
|
307
|
-
renderProgress(Object.assign({ status: "starting", completed: 0, failed: 0, extracted: 0 }, started));
|
|
308
|
-
await pollProgress();
|
|
293
|
+
started = await postJson("/migrate", { conversationKeys: selectedKeys });
|
|
309
294
|
} catch (e) {
|
|
310
295
|
decisionMade = false;
|
|
311
296
|
renderDashboard(routeError(e && e.message));
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
extractMounted = false;
|
|
300
|
+
renderProgress(Object.assign({ status: "starting", completed: 0, failed: 0, extracted: 0 }, started));
|
|
301
|
+
await pollProgress();
|
|
302
|
+
}
|
|
303
|
+
async function resumeExistingExtraction() {
|
|
304
|
+
try {
|
|
305
|
+
var existing = await getJson("/progress");
|
|
306
|
+
if (!existing || existing.status === "idle") return false;
|
|
307
|
+
decisionMade = true;
|
|
308
|
+
extractionEnded = false;
|
|
309
|
+
extractMounted = false;
|
|
310
|
+
renderProgress(existing);
|
|
311
|
+
if (existing.status !== "completed" && existing.status !== "failed") {
|
|
312
|
+
void pollProgress();
|
|
313
|
+
}
|
|
314
|
+
return true;
|
|
315
|
+
} catch (_) {
|
|
316
|
+
// Stats cannot prove that no import is running. Stay in the recovery view until
|
|
317
|
+
// the authoritative progress endpoint answers instead of exposing a second start.
|
|
318
|
+
decisionMade = true;
|
|
319
|
+
extractionEnded = false;
|
|
320
|
+
extractMounted = false;
|
|
321
|
+
renderProgress({
|
|
322
|
+
status: "running",
|
|
323
|
+
total: 0,
|
|
324
|
+
completed: 0,
|
|
325
|
+
failed: 0,
|
|
326
|
+
extracted: 0,
|
|
327
|
+
latest: "Reconnecting to the active extraction..."
|
|
328
|
+
});
|
|
329
|
+
void pollProgress();
|
|
330
|
+
return true;
|
|
312
331
|
}
|
|
313
332
|
}
|
|
314
333
|
async function pollProgress() {
|
|
315
334
|
var runId = ++progressPollRunId;
|
|
335
|
+
var failures = 0;
|
|
316
336
|
for (;;) {
|
|
317
337
|
if (extractionEnded || runId !== progressPollRunId) return;
|
|
318
|
-
var progress
|
|
338
|
+
var progress;
|
|
339
|
+
try {
|
|
340
|
+
progress = await getJson("/progress");
|
|
341
|
+
failures = 0;
|
|
342
|
+
} catch (_) {
|
|
343
|
+
failures++;
|
|
344
|
+
var reconnecting = Object.assign({
|
|
345
|
+
status: "running",
|
|
346
|
+
total: 0,
|
|
347
|
+
completed: 0,
|
|
348
|
+
failed: 0,
|
|
349
|
+
extracted: 0
|
|
350
|
+
}, lastExtractionProgress || {});
|
|
351
|
+
reconnecting.status = reconnecting.status === "completed" || reconnecting.status === "failed"
|
|
352
|
+
? "running"
|
|
353
|
+
: reconnecting.status;
|
|
354
|
+
reconnecting.latest = "Connection interrupted. Reconnecting to the active extraction...";
|
|
355
|
+
renderProgress(reconnecting);
|
|
356
|
+
await sleep(Math.min(5000, 500 * Math.pow(2, Math.min(failures - 1, 3))));
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
319
359
|
if (extractionEnded || runId !== progressPollRunId) return;
|
|
320
360
|
renderProgress(progress);
|
|
321
361
|
if (progress.status === "completed" || progress.status === "failed") return;
|
|
@@ -803,7 +843,7 @@ export const SETUP_PAGE_CLIENT_EXTRACTION = String.raw ` /* ---------- dash
|
|
|
803
843
|
}
|
|
804
844
|
async function switchSetupAccount() {
|
|
805
845
|
var button = document.getElementById("changeSetupAccount");
|
|
806
|
-
if (button) { button.disabled = true; button.textContent = "
|
|
846
|
+
if (button) { button.disabled = true; button.textContent = "Signing out..."; }
|
|
807
847
|
try {
|
|
808
848
|
await postJson("/logout", {}, 12000);
|
|
809
849
|
stats = null;
|
|
@@ -811,15 +851,13 @@ export const SETUP_PAGE_CLIENT_EXTRACTION = String.raw ` /* ---------- dash
|
|
|
811
851
|
connected = false;
|
|
812
852
|
selectedSessionKeys = Object.create(null);
|
|
813
853
|
sessionSelectionTouched = false;
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
}
|
|
819
|
-
startConnectionPoll();
|
|
854
|
+
localAuthEmail = "";
|
|
855
|
+
localAuthTermsAccepted = false;
|
|
856
|
+
localAuthAgeConfirmed = false;
|
|
857
|
+
renderLocalLogin("");
|
|
820
858
|
} catch (error) {
|
|
821
859
|
if (button) { button.disabled = false; button.textContent = "Change account"; }
|
|
822
|
-
setSetupPlanStatus(error && error.message ? error.message : "Could not
|
|
860
|
+
setSetupPlanStatus(error && error.message ? error.message : "Could not switch accounts.");
|
|
823
861
|
}
|
|
824
862
|
}
|
|
825
863
|
function paidRecallPlan(plan) {
|
|
@@ -884,7 +922,7 @@ export const SETUP_PAGE_CLIENT_EXTRACTION = String.raw ` /* ---------- dash
|
|
|
884
922
|
'<div class="setupPlanHead"><strong>Pro</strong><span>$40 / month</span></div>' +
|
|
885
923
|
'<p>More recall for serious work.</p>' +
|
|
886
924
|
'<ul><li>' + setupIcon("check") + '<span>250 bulk history imports</span></li><li>' + setupIcon("check") + '<span>200K new-chat tokens each week</span></li><li>' + setupIcon("check") + '<span>100 memory searches each week</span></li><li>' + setupIcon("check") + '<span>No memory-count limit</span></li></ul>' +
|
|
887
|
-
'<button type="button" class="primary" id="chooseProPlan">' + (trialAvailable ? "Start
|
|
925
|
+
'<button type="button" class="primary" id="chooseProPlan">' + (trialAvailable ? "Start 14-day trial" : "Choose Pro") + '</button>' +
|
|
888
926
|
'<small>' + (trialAvailable ? "Card required. Cancel anytime." : "Your trial was already used.") + '</small>' +
|
|
889
927
|
'</article>' +
|
|
890
928
|
'<article class="setupPlanCard">' +
|
|
@@ -892,7 +930,7 @@ export const SETUP_PAGE_CLIENT_EXTRACTION = String.raw ` /* ---------- dash
|
|
|
892
930
|
'<p>Higher limits for people who use Echo every day.</p>' +
|
|
893
931
|
// Future Power feature: API and automation access.
|
|
894
932
|
'<ul><li>' + setupIcon("check") + '<span>500 bulk history imports</span></li><li>' + setupIcon("check") + '<span>750K new-chat tokens each week</span></li><li>' + setupIcon("check") + '<span>250 memory searches each week</span></li><li>' + setupIcon("check") + '<span>No memory-count limit</span></li></ul>' +
|
|
895
|
-
'<button type="button" class="secondary" id="choosePowerPlan">' + (trialAvailable ? "Start
|
|
933
|
+
'<button type="button" class="secondary" id="choosePowerPlan">' + (trialAvailable ? "Start 14-day trial" : "Choose Power") + '</button>' +
|
|
896
934
|
'<small>' + (trialAvailable ? "Card required. Cancel anytime." : "Your trial was already used.") + '</small>' +
|
|
897
935
|
'</article>' +
|
|
898
936
|
'</div>' +
|
|
@@ -137,13 +137,11 @@ export const SETUP_PAGE_CLIENT_LIFECYCLE = String.raw ` /* ---------- scan-
|
|
|
137
137
|
var data = event.data || {};
|
|
138
138
|
if (data.type === "echomem:connected" && data.nonce === nonce) {
|
|
139
139
|
if (!localHistoryConsentGranted) {
|
|
140
|
-
closeAuthWindow();
|
|
141
140
|
renderLocalScanConsent();
|
|
142
141
|
setConsentStatus("Local history access is required before you can connect EchoMem or continue setup.", "required");
|
|
143
142
|
return;
|
|
144
143
|
}
|
|
145
144
|
connected = true;
|
|
146
|
-
closeAuthWindow();
|
|
147
145
|
void waitForStats();
|
|
148
146
|
} else if (data.type === "echomem:city-ready" && data.nonce === nonce) {
|
|
149
147
|
scheduleReportToCity();
|
|
@@ -159,12 +157,10 @@ export const SETUP_PAGE_CLIENT_LIFECYCLE = String.raw ` /* ---------- scan-
|
|
|
159
157
|
var configLoaded = false;
|
|
160
158
|
var consentRequired = true;
|
|
161
159
|
var consentGranted = false;
|
|
162
|
-
// Learn the
|
|
160
|
+
// Learn the connection state and server-side consent gate before routing.
|
|
163
161
|
try {
|
|
164
162
|
var cfg = await getJson("/config");
|
|
165
163
|
configLoaded = true;
|
|
166
|
-
authUrl = cfg.authUrl || authUrl;
|
|
167
|
-
switchAccountUrl = cfg.switchAccountUrl || switchAccountUrl || authUrl;
|
|
168
164
|
connected = !!cfg.connected;
|
|
169
165
|
workspacePath = cfg.workspacePath || workspacePath;
|
|
170
166
|
consentRequired = cfg.consentRequired !== false;
|
|
@@ -139,6 +139,129 @@ export const SETUP_PAGE_STYLES_EXTRACTION = String.raw ` /* ---- dashboard (p
|
|
|
139
139
|
font-size: 12px;
|
|
140
140
|
font-weight: 650;
|
|
141
141
|
}
|
|
142
|
+
.localAuthStage {
|
|
143
|
+
display: grid;
|
|
144
|
+
place-items: center;
|
|
145
|
+
width: min(720px, 100%);
|
|
146
|
+
min-height: min(660px, calc(100vh - 120px));
|
|
147
|
+
margin: 0 auto;
|
|
148
|
+
}
|
|
149
|
+
.localAuthCard {
|
|
150
|
+
width: min(680px, 100%);
|
|
151
|
+
border: 1.5px solid rgba(26,58,143,0.16);
|
|
152
|
+
border-radius: 20px;
|
|
153
|
+
background: rgba(255,255,255,0.88);
|
|
154
|
+
padding: clamp(22px, 4vw, 34px);
|
|
155
|
+
box-shadow: 0 24px 60px -42px rgba(20,36,84,0.48);
|
|
156
|
+
text-align: left;
|
|
157
|
+
}
|
|
158
|
+
.localAuthLead {
|
|
159
|
+
display: grid;
|
|
160
|
+
justify-items: start;
|
|
161
|
+
gap: 10px;
|
|
162
|
+
}
|
|
163
|
+
.localAuthLead img {
|
|
164
|
+
width: 58px;
|
|
165
|
+
height: 58px;
|
|
166
|
+
object-fit: contain;
|
|
167
|
+
filter: drop-shadow(0 10px 16px rgba(26,58,143,0.18));
|
|
168
|
+
}
|
|
169
|
+
.localAuthLead h2 {
|
|
170
|
+
max-width: 610px;
|
|
171
|
+
font-size: clamp(30px, 4vw, 46px);
|
|
172
|
+
line-height: 1;
|
|
173
|
+
}
|
|
174
|
+
.localAuthLead p:not(.consentEyebrow) {
|
|
175
|
+
max-width: 590px;
|
|
176
|
+
margin: 0;
|
|
177
|
+
color: var(--echo-ink-mute);
|
|
178
|
+
font-size: 15px;
|
|
179
|
+
line-height: 1.55;
|
|
180
|
+
}
|
|
181
|
+
.localAuthForm {
|
|
182
|
+
display: grid;
|
|
183
|
+
gap: 14px;
|
|
184
|
+
margin-top: 22px;
|
|
185
|
+
}
|
|
186
|
+
.localAuthField {
|
|
187
|
+
display: grid;
|
|
188
|
+
gap: 7px;
|
|
189
|
+
}
|
|
190
|
+
.localAuthField > span {
|
|
191
|
+
font-family: var(--echo-font-mono);
|
|
192
|
+
color: var(--echo-ink-mute);
|
|
193
|
+
font-size: 11px;
|
|
194
|
+
font-weight: 800;
|
|
195
|
+
letter-spacing: 0.06em;
|
|
196
|
+
text-transform: uppercase;
|
|
197
|
+
}
|
|
198
|
+
.localAuthField input {
|
|
199
|
+
width: 100%;
|
|
200
|
+
min-height: 50px;
|
|
201
|
+
border: 1px solid rgba(26,58,143,0.20);
|
|
202
|
+
border-radius: 10px;
|
|
203
|
+
background: #fff;
|
|
204
|
+
color: var(--echo-ink-text);
|
|
205
|
+
padding: 0 14px;
|
|
206
|
+
font: inherit;
|
|
207
|
+
font-size: 16px;
|
|
208
|
+
outline: none;
|
|
209
|
+
}
|
|
210
|
+
.localAuthField input:focus {
|
|
211
|
+
border-color: var(--echo-ink-primary);
|
|
212
|
+
box-shadow: 0 0 0 3px rgba(26,58,143,0.12);
|
|
213
|
+
}
|
|
214
|
+
.localAuthLegal {
|
|
215
|
+
display: grid;
|
|
216
|
+
gap: 10px;
|
|
217
|
+
border: 1px solid rgba(26,58,143,0.10);
|
|
218
|
+
border-radius: 14px;
|
|
219
|
+
background: rgba(240,239,233,0.56);
|
|
220
|
+
padding: 13px 14px;
|
|
221
|
+
}
|
|
222
|
+
.localAuthLegal label {
|
|
223
|
+
display: grid;
|
|
224
|
+
grid-template-columns: 18px minmax(0, 1fr);
|
|
225
|
+
gap: 10px;
|
|
226
|
+
align-items: start;
|
|
227
|
+
color: var(--echo-ink-mute);
|
|
228
|
+
font-size: 12px;
|
|
229
|
+
line-height: 1.45;
|
|
230
|
+
}
|
|
231
|
+
.localAuthLegal input {
|
|
232
|
+
width: 16px;
|
|
233
|
+
height: 16px;
|
|
234
|
+
margin: 2px 0 0;
|
|
235
|
+
accent-color: var(--echo-ink-primary);
|
|
236
|
+
}
|
|
237
|
+
.localAuthLegal a {
|
|
238
|
+
color: var(--echo-ink-primary);
|
|
239
|
+
font-weight: 750;
|
|
240
|
+
text-decoration: underline;
|
|
241
|
+
text-underline-offset: 2px;
|
|
242
|
+
}
|
|
243
|
+
.localAuthActions {
|
|
244
|
+
display: flex;
|
|
245
|
+
flex-wrap: wrap;
|
|
246
|
+
gap: 10px;
|
|
247
|
+
align-items: center;
|
|
248
|
+
}
|
|
249
|
+
.localAuthStatus {
|
|
250
|
+
min-height: 18px;
|
|
251
|
+
margin: 0;
|
|
252
|
+
color: var(--echo-ink-mute);
|
|
253
|
+
font-size: 13px;
|
|
254
|
+
line-height: 1.45;
|
|
255
|
+
}
|
|
256
|
+
.localAuthStatus:empty { display: none; }
|
|
257
|
+
.localAuthStatus.is-error {
|
|
258
|
+
border: 1px solid rgba(139,44,38,0.22);
|
|
259
|
+
border-radius: 10px;
|
|
260
|
+
background: #fff4ee;
|
|
261
|
+
padding: 9px 11px;
|
|
262
|
+
color: #8b2c26;
|
|
263
|
+
font-weight: 650;
|
|
264
|
+
}
|
|
142
265
|
.track { height: 12px; overflow: hidden; border-radius: 999px; background: #e8e8e1; margin: 16px 0 10px; }
|
|
143
266
|
.fill { height: 100%; width: 0%; background: var(--echo-ink-primary); transition: width 180ms ease; }
|
|
144
267
|
/* indeterminate "we're working on it" bar for the prep phase (before job counts move) */
|
|
@@ -173,6 +296,8 @@ export const SETUP_PAGE_STYLES_EXTRACTION = String.raw ` /* ---- dashboard (p
|
|
|
173
296
|
.explainCta .promiseActions { width: 100%; }
|
|
174
297
|
.explainCta .primary, .explainCta .secondary { width: 100%; }
|
|
175
298
|
.consentActions .primary { width: 100%; }
|
|
299
|
+
.localAuthActions .primary,
|
|
300
|
+
.localAuthForm > .primary { width: 100%; }
|
|
176
301
|
.cityHero { min-height: auto; }
|
|
177
302
|
.cityShell {
|
|
178
303
|
width: 100vw;
|
package/dist/setup-page.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { renderSetupPageDocument } from "./setup-page/document.js";
|
|
2
2
|
import { renderSetupPreviewBootstrap } from "./setup-preview.js";
|
|
3
|
+
export { SETUP_PREVIEW_STATES } from "./setup-preview.js";
|
|
3
4
|
/**
|
|
4
5
|
* Setup page entry point. The implementation is split by product phase under ./setup-page/:
|
|
5
6
|
* core utilities, local report, post-auth extraction, and lifecycle polling.
|
package/dist/setup-preview.js
CHANGED
|
@@ -5,7 +5,18 @@ export const SETUP_PREVIEW_STATES = [
|
|
|
5
5
|
"report",
|
|
6
6
|
"extract-counting",
|
|
7
7
|
"extract-ready",
|
|
8
|
+
"extract-free-selected",
|
|
9
|
+
"extract-free-trial-used",
|
|
8
10
|
"extract-limit",
|
|
11
|
+
"extract-pro-trial",
|
|
12
|
+
"extract-pro-active",
|
|
13
|
+
"extract-power-active",
|
|
14
|
+
"extract-team-active",
|
|
15
|
+
"extract-enterprise-active",
|
|
16
|
+
"extract-unknown",
|
|
17
|
+
"auth-login",
|
|
18
|
+
"auth-unlock",
|
|
19
|
+
"auth-setup",
|
|
9
20
|
"extract-run",
|
|
10
21
|
"extract-overdue",
|
|
11
22
|
"extract-done",
|
|
@@ -202,6 +213,62 @@ function previewWatermarkScript() {
|
|
|
202
213
|
document.body.appendChild(previewWatermark);
|
|
203
214
|
`;
|
|
204
215
|
}
|
|
216
|
+
function extractionPreviewBootstrap(options) {
|
|
217
|
+
const candidateCount = options.candidateCount ?? 520;
|
|
218
|
+
const quotaLimit = options.quotaLimit;
|
|
219
|
+
const quotaRemaining = options.quotaRemaining;
|
|
220
|
+
const historicalConversationQuota = quotaLimit == null || quotaRemaining == null
|
|
221
|
+
? null
|
|
222
|
+
: {
|
|
223
|
+
used: Math.max(0, quotaLimit - quotaRemaining),
|
|
224
|
+
limit: quotaLimit,
|
|
225
|
+
remaining: quotaRemaining,
|
|
226
|
+
};
|
|
227
|
+
const billingStatus = {
|
|
228
|
+
plan: options.plan,
|
|
229
|
+
paid: options.paid,
|
|
230
|
+
trialAvailable: options.trialAvailable,
|
|
231
|
+
trialUsed: options.trialUsed,
|
|
232
|
+
subscriptionStatus: options.subscriptionStatus ?? null,
|
|
233
|
+
trialEndedAt: options.trialEndedAt ?? null,
|
|
234
|
+
pricingUrl: "https://echoknows.com/pricing?source=mcp_onboarding",
|
|
235
|
+
account: {
|
|
236
|
+
displayName: "Preview User",
|
|
237
|
+
email: "preview@example.com",
|
|
238
|
+
avatarUrl: "/hud-assets/echo-face-cutout.png",
|
|
239
|
+
},
|
|
240
|
+
historicalConversationQuota,
|
|
241
|
+
};
|
|
242
|
+
return `
|
|
243
|
+
connected = true;
|
|
244
|
+
billingStatus = ${JSON.stringify(billingStatus)};
|
|
245
|
+
setupPlanChoice = ${JSON.stringify(options.selectFree ? "free" : "")};
|
|
246
|
+
stats = {
|
|
247
|
+
sessions: { total: ${candidateCount}, codex: ${Math.ceil(candidateCount * 0.68)}, claudeCode: ${Math.floor(candidateCount * 0.32)} },
|
|
248
|
+
migratable: {
|
|
249
|
+
pending: ${candidateCount}, pendingTotal: ${candidateCount}, pendingCodex: ${Math.ceil(candidateCount * 0.68)}, pendingClaudeCode: ${Math.floor(candidateCount * 0.32)},
|
|
250
|
+
alreadyMigrated: 108, skippedActive: 0,
|
|
251
|
+
eta: { estimatedLabel: "under 2 minutes" }, estimatedLabel: "under 2 minutes"
|
|
252
|
+
},
|
|
253
|
+
candidateSessions: Array.from({ length: ${candidateCount} }, function (_, index) {
|
|
254
|
+
var codex = index < ${Math.ceil(candidateCount * 0.68)};
|
|
255
|
+
return {
|
|
256
|
+
key: (codex ? "codex:" : "claude-code:") + "preview-" + index,
|
|
257
|
+
source: codex ? "codex" : "claude-code",
|
|
258
|
+
title: ["Plan the onboarding flow", "Repair memory extraction", "Review pricing limits", "Polish the EchoMem HUD"][index % 4] + " · " + (index + 1),
|
|
259
|
+
project: ["EchoMem Chrome", "MCP Server", "Memory Platform"][index % 3],
|
|
260
|
+
date: new Date(Date.UTC(2026, 6, 18 - (index % 12))).toISOString(),
|
|
261
|
+
characters: 42000 + index * 2700,
|
|
262
|
+
approxInputTokens: 10500 + index * 675,
|
|
263
|
+
turns: 18 + index
|
|
264
|
+
};
|
|
265
|
+
}),
|
|
266
|
+
discovery: { phase: "account", exact: false }
|
|
267
|
+
};
|
|
268
|
+
renderDashboard();
|
|
269
|
+
${options.showUnknownStatus ? 'setSetupPlanStatus("Plan check unavailable. Free still works.");' : ""}
|
|
270
|
+
${options.openSessionPicker ? "window.setTimeout(function () { openSessionPicker(); }, 0);" : ""}`;
|
|
271
|
+
}
|
|
205
272
|
export function renderSetupPreviewBootstrap(state) {
|
|
206
273
|
const watermark = previewWatermarkScript();
|
|
207
274
|
if (state === "consent") {
|
|
@@ -236,44 +303,66 @@ export function renderSetupPreviewBootstrap(state) {
|
|
|
236
303
|
stats = null;
|
|
237
304
|
renderDashboard();`;
|
|
238
305
|
}
|
|
239
|
-
if (state === "extract-ready"
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
|
|
306
|
+
if (state === "extract-ready")
|
|
307
|
+
return `${watermark}${extractionPreviewBootstrap({
|
|
308
|
+
plan: "free", paid: false, trialAvailable: true, trialUsed: false,
|
|
309
|
+
quotaLimit: 100, quotaRemaining: 28, candidateCount: 28,
|
|
310
|
+
})}`;
|
|
311
|
+
if (state === "extract-free-selected")
|
|
312
|
+
return `${watermark}${extractionPreviewBootstrap({
|
|
313
|
+
plan: "free", paid: false, trialAvailable: true, trialUsed: false,
|
|
314
|
+
quotaLimit: 100, quotaRemaining: 100, selectFree: true,
|
|
315
|
+
})}`;
|
|
316
|
+
if (state === "extract-free-trial-used")
|
|
317
|
+
return `${watermark}${extractionPreviewBootstrap({
|
|
318
|
+
plan: "free", paid: false, trialAvailable: false, trialUsed: true,
|
|
319
|
+
subscriptionStatus: "expired", trialEndedAt: "2026-07-20T00:00:00.000Z",
|
|
320
|
+
quotaLimit: 100, quotaRemaining: 100,
|
|
321
|
+
})}`;
|
|
322
|
+
if (state === "extract-limit")
|
|
323
|
+
return `${watermark}${extractionPreviewBootstrap({
|
|
324
|
+
plan: "free", paid: false, trialAvailable: false, trialUsed: true,
|
|
325
|
+
quotaLimit: 100, quotaRemaining: 0, selectFree: true, openSessionPicker: true,
|
|
326
|
+
})}`;
|
|
327
|
+
if (state === "extract-pro-trial")
|
|
328
|
+
return `${watermark}${extractionPreviewBootstrap({
|
|
329
|
+
plan: "pro", paid: true, trialAvailable: false, trialUsed: true,
|
|
330
|
+
subscriptionStatus: "trialing", trialEndedAt: "2026-08-04T00:00:00.000Z",
|
|
331
|
+
// The server currently grants trialing users Free's lifetime history allowance,
|
|
332
|
+
// even though recurring processing/search allowances resolve to Pro.
|
|
333
|
+
quotaLimit: 100, quotaRemaining: 100,
|
|
334
|
+
})}`;
|
|
335
|
+
if (state === "extract-pro-active")
|
|
336
|
+
return `${watermark}${extractionPreviewBootstrap({
|
|
337
|
+
plan: "pro", paid: true, trialAvailable: false, trialUsed: true,
|
|
338
|
+
subscriptionStatus: "active", quotaLimit: 250, quotaRemaining: 250,
|
|
339
|
+
})}`;
|
|
340
|
+
if (state === "extract-power-active")
|
|
341
|
+
return `${watermark}${extractionPreviewBootstrap({
|
|
342
|
+
plan: "power", paid: true, trialAvailable: false, trialUsed: true,
|
|
343
|
+
subscriptionStatus: "active", quotaLimit: 500, quotaRemaining: 500,
|
|
344
|
+
})}`;
|
|
345
|
+
if (state === "extract-team-active")
|
|
346
|
+
return `${watermark}${extractionPreviewBootstrap({
|
|
347
|
+
plan: "team", paid: true, trialAvailable: false, trialUsed: true,
|
|
348
|
+
subscriptionStatus: "active", quotaLimit: 250, quotaRemaining: 250,
|
|
349
|
+
})}`;
|
|
350
|
+
if (state === "extract-enterprise-active")
|
|
351
|
+
return `${watermark}${extractionPreviewBootstrap({
|
|
352
|
+
plan: "enterprise", paid: true, trialAvailable: false, trialUsed: true,
|
|
353
|
+
subscriptionStatus: "active", quotaLimit: 500, quotaRemaining: 500,
|
|
354
|
+
})}`;
|
|
355
|
+
if (state === "extract-unknown")
|
|
356
|
+
return `${watermark}${extractionPreviewBootstrap({
|
|
357
|
+
plan: "unknown", paid: false, trialAvailable: true, trialUsed: false,
|
|
358
|
+
showUnknownStatus: true,
|
|
359
|
+
})}`;
|
|
360
|
+
if (state === "auth-login")
|
|
361
|
+
return `${watermark}\n renderLocalLogin("");`;
|
|
362
|
+
if (state === "auth-unlock")
|
|
363
|
+
return `${watermark}\n renderLocalPassphrase("unlock", "preview@example.com");`;
|
|
364
|
+
if (state === "auth-setup")
|
|
365
|
+
return `${watermark}\n renderLocalPassphrase("setup", "preview@example.com");`;
|
|
277
366
|
if (state === "extract-run") {
|
|
278
367
|
return `${watermark}
|
|
279
368
|
renderProgress({ status: "running", total: 28, completed: 4, extracted: 19, failed: 1, latest: "preview session", latestRepo: "Preview Workspace" });`;
|