Spaces:
Running on Zero
Running on Zero
fix: ignore stale export completions
Browse filesCo-authored-by: Codex <noreply@openai.com>
- static/app.js +28 -1
static/app.js
CHANGED
|
@@ -37,6 +37,7 @@ let profileFields = [];
|
|
| 37 |
let turnWatchdog = null;
|
| 38 |
let sawTurnToken = false;
|
| 39 |
let bootstrapData = null;
|
|
|
|
| 40 |
|
| 41 |
bootstrap().catch(handleBootstrapError);
|
| 42 |
|
|
@@ -103,6 +104,7 @@ ideasEl.addEventListener("click", (event) => {
|
|
| 103 |
});
|
| 104 |
|
| 105 |
async function runTurn(message) {
|
|
|
|
| 106 |
input.value = "";
|
| 107 |
submit.disabled = true;
|
| 108 |
setCommandDisabled(true);
|
|
@@ -189,12 +191,30 @@ function defaultSession(data = bootstrapData) {
|
|
| 189 |
};
|
| 190 |
}
|
| 191 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 192 |
function resetSession() {
|
| 193 |
if (!bootstrapData) return;
|
|
|
|
| 194 |
clearTurnWatchdog();
|
| 195 |
clearSavedSession();
|
| 196 |
session = defaultSession(bootstrapData);
|
| 197 |
currentArtifact = null;
|
|
|
|
|
|
|
| 198 |
input.value = "";
|
| 199 |
ink.textContent = "The book is open. The next page waits for its first line.";
|
| 200 |
ink.classList.remove("thinking", "bleed", "gold");
|
|
@@ -209,6 +229,7 @@ function resetSession() {
|
|
| 209 |
renderPlan([]);
|
| 210 |
renderProjects(bootstrapData.top_projects || []);
|
| 211 |
renderWhitespace(bootstrapData.whitespace || []);
|
|
|
|
| 212 |
exportButton.disabled = true;
|
| 213 |
setButtonDisabled(exportNotesButton, true);
|
| 214 |
setButtonDisabled(exportChapterButton, true);
|
|
@@ -217,6 +238,7 @@ function resetSession() {
|
|
| 217 |
}
|
| 218 |
|
| 219 |
async function loadDemoSession() {
|
|
|
|
| 220 |
submit.disabled = true;
|
| 221 |
setCommandDisabled(true);
|
| 222 |
ink.classList.remove("bleed", "gold");
|
|
@@ -524,6 +546,7 @@ function selectIdea(ideaId) {
|
|
| 524 |
if (!ideaId || !Array.isArray(session.ideas)) return;
|
| 525 |
const idea = session.ideas.find((item) => item.id === ideaId);
|
| 526 |
if (!idea) return;
|
|
|
|
| 527 |
session.current_idea_id = idea.id;
|
| 528 |
if (Array.isArray(idea.targets) && idea.targets.length) {
|
| 529 |
session.targets = targetOptions.filter((option) => idea.targets.includes(option));
|
|
@@ -757,6 +780,7 @@ async function exportChapter() {
|
|
| 757 |
|
| 758 |
async function exportMarkdown({ endpoint, filename, button, busyLabel, pendingLabel, successLabel }) {
|
| 759 |
if (!button || button.disabled) return;
|
|
|
|
| 760 |
const idleLabel = button.textContent;
|
| 761 |
button.disabled = true;
|
| 762 |
button.textContent = busyLabel;
|
|
@@ -771,15 +795,18 @@ async function exportMarkdown({ endpoint, filename, button, busyLabel, pendingLa
|
|
| 771 |
const data = Array.isArray(result.data) ? result.data[0] : result.data;
|
| 772 |
const text = String(data || "");
|
| 773 |
if (!text.trim()) throw new Error("empty export");
|
|
|
|
| 774 |
downloadText(filename, text, "text/markdown;charset=utf-8");
|
| 775 |
session.ui_status = `${successLabel}: ${filename}`;
|
| 776 |
corrections.textContent = session.ui_status;
|
| 777 |
} catch (error) {
|
|
|
|
| 778 |
session.ui_status = `Export failed: ${error.message}`;
|
| 779 |
corrections.textContent = session.ui_status;
|
| 780 |
} finally {
|
| 781 |
-
saveSession();
|
| 782 |
button.textContent = idleLabel;
|
|
|
|
|
|
|
| 783 |
setCommandDisabled(false);
|
| 784 |
}
|
| 785 |
}
|
|
|
|
| 37 |
let turnWatchdog = null;
|
| 38 |
let sawTurnToken = false;
|
| 39 |
let bootstrapData = null;
|
| 40 |
+
let sessionRevision = 0;
|
| 41 |
|
| 42 |
bootstrap().catch(handleBootstrapError);
|
| 43 |
|
|
|
|
| 104 |
});
|
| 105 |
|
| 106 |
async function runTurn(message) {
|
| 107 |
+
bumpSessionRevision();
|
| 108 |
input.value = "";
|
| 109 |
submit.disabled = true;
|
| 110 |
setCommandDisabled(true);
|
|
|
|
| 191 |
};
|
| 192 |
}
|
| 193 |
|
| 194 |
+
function bumpSessionRevision() {
|
| 195 |
+
sessionRevision += 1;
|
| 196 |
+
return sessionRevision;
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
function isCurrentSessionRevision(revision) {
|
| 200 |
+
return revision === sessionRevision;
|
| 201 |
+
}
|
| 202 |
+
|
| 203 |
+
function restoreExportButtonLabels() {
|
| 204 |
+
exportNotesButton.textContent = "Notes";
|
| 205 |
+
exportChapterButton.textContent = "Chapter";
|
| 206 |
+
exportButton.textContent = PNG_EXPORT_LABEL;
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
function resetSession() {
|
| 210 |
if (!bootstrapData) return;
|
| 211 |
+
bumpSessionRevision();
|
| 212 |
clearTurnWatchdog();
|
| 213 |
clearSavedSession();
|
| 214 |
session = defaultSession(bootstrapData);
|
| 215 |
currentArtifact = null;
|
| 216 |
+
submit.disabled = false;
|
| 217 |
+
input.disabled = false;
|
| 218 |
input.value = "";
|
| 219 |
ink.textContent = "The book is open. The next page waits for its first line.";
|
| 220 |
ink.classList.remove("thinking", "bleed", "gold");
|
|
|
|
| 229 |
renderPlan([]);
|
| 230 |
renderProjects(bootstrapData.top_projects || []);
|
| 231 |
renderWhitespace(bootstrapData.whitespace || []);
|
| 232 |
+
restoreExportButtonLabels();
|
| 233 |
exportButton.disabled = true;
|
| 234 |
setButtonDisabled(exportNotesButton, true);
|
| 235 |
setButtonDisabled(exportChapterButton, true);
|
|
|
|
| 238 |
}
|
| 239 |
|
| 240 |
async function loadDemoSession() {
|
| 241 |
+
bumpSessionRevision();
|
| 242 |
submit.disabled = true;
|
| 243 |
setCommandDisabled(true);
|
| 244 |
ink.classList.remove("bleed", "gold");
|
|
|
|
| 546 |
if (!ideaId || !Array.isArray(session.ideas)) return;
|
| 547 |
const idea = session.ideas.find((item) => item.id === ideaId);
|
| 548 |
if (!idea) return;
|
| 549 |
+
bumpSessionRevision();
|
| 550 |
session.current_idea_id = idea.id;
|
| 551 |
if (Array.isArray(idea.targets) && idea.targets.length) {
|
| 552 |
session.targets = targetOptions.filter((option) => idea.targets.includes(option));
|
|
|
|
| 780 |
|
| 781 |
async function exportMarkdown({ endpoint, filename, button, busyLabel, pendingLabel, successLabel }) {
|
| 782 |
if (!button || button.disabled) return;
|
| 783 |
+
const revision = sessionRevision;
|
| 784 |
const idleLabel = button.textContent;
|
| 785 |
button.disabled = true;
|
| 786 |
button.textContent = busyLabel;
|
|
|
|
| 795 |
const data = Array.isArray(result.data) ? result.data[0] : result.data;
|
| 796 |
const text = String(data || "");
|
| 797 |
if (!text.trim()) throw new Error("empty export");
|
| 798 |
+
if (!isCurrentSessionRevision(revision)) return;
|
| 799 |
downloadText(filename, text, "text/markdown;charset=utf-8");
|
| 800 |
session.ui_status = `${successLabel}: ${filename}`;
|
| 801 |
corrections.textContent = session.ui_status;
|
| 802 |
} catch (error) {
|
| 803 |
+
if (!isCurrentSessionRevision(revision)) return;
|
| 804 |
session.ui_status = `Export failed: ${error.message}`;
|
| 805 |
corrections.textContent = session.ui_status;
|
| 806 |
} finally {
|
|
|
|
| 807 |
button.textContent = idleLabel;
|
| 808 |
+
if (!isCurrentSessionRevision(revision)) return;
|
| 809 |
+
saveSession();
|
| 810 |
setCommandDisabled(false);
|
| 811 |
}
|
| 812 |
}
|