improve AI rewrite UX and title quality
**AI button: dynamic tooltip hints** - titleAiBtn and descAiBtn now show "Rewrite with AI" when the field already has user content, "Generate with AI" when empty. - updateAiButtonHints() fires on every title/description input event and whenever syncStepFields() runs to keep hints current. **Stronger rewrite prompt** - When the user has typed a draft title or description, the prompt now shows it explicitly: "User's draft title (rewrite this): '...'" - Rules changed from "improve its wording" to "Your only job is to polish its grammar and phrasing. Do NOT replace it with something different." — prevents the model from ignoring the user's text and generating fresh content from capture context. - The suggested-title hint is suppressed when a draft title exists so the model doesn't silently swap the user's text for the auto-title. **Title quality: generic window title filter** - GENERIC_WINDOW_TITLES Set filters "New Tab", "Untitled", "Loading" etc. from the window-title path so they no longer produce titles like "Open New Tab in Chrome". **Title quality: app name stripping for non-browser apps** - stripBrowserNameSuffix now accepts an optional appName; it strips the app's display name and process name from the window title suffix using the same pattern as browser names. - "Document1.docx - Word" with appName "winword" → "Document1.docx". - buildCaptureTitle passes metadata.appName into the strip call. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
@@ -227,6 +227,21 @@ class GuideEditor {
|
||||
return this.runAiGeneration('block', { blockId: block.id, button });
|
||||
}
|
||||
|
||||
updateAiButtonHints() {
|
||||
const PLACEHOLDER_TITLES = new Set([
|
||||
'', 'screen capture', 'window capture', 'region capture', 'capture',
|
||||
]);
|
||||
if (this.dom.titleAiBtn) {
|
||||
const val = (this.dom.titleInput?.value || '').trim();
|
||||
const hasDraft = Boolean(val) && !PLACEHOLDER_TITLES.has(val.toLowerCase());
|
||||
this.dom.titleAiBtn.title = hasDraft ? 'Rewrite step title with AI' : 'Generate step title with AI';
|
||||
}
|
||||
if (this.dom.descAiBtn) {
|
||||
const hasDesc = Boolean((this.dom.descEditor?.innerText || '').trim());
|
||||
this.dom.descAiBtn.title = hasDesc ? 'Rewrite description with AI' : 'Generate description with AI';
|
||||
}
|
||||
}
|
||||
|
||||
get currentStep() {
|
||||
return this.stepMap.get(this.selectedStepId) || null;
|
||||
}
|
||||
@@ -504,6 +519,7 @@ class GuideEditor {
|
||||
this.saveStepDebounced();
|
||||
this.renderStepList();
|
||||
this.emitMeta();
|
||||
this.updateAiButtonHints();
|
||||
});
|
||||
this.dom.titleAiBtn.addEventListener('click', () => this.generateTitleWithAi(this.dom.titleAiBtn));
|
||||
|
||||
@@ -575,6 +591,7 @@ class GuideEditor {
|
||||
this.saveStepDebounced();
|
||||
this.emitMeta();
|
||||
this.updateToolbarState();
|
||||
this.updateAiButtonHints();
|
||||
});
|
||||
this.dom.descEditor.addEventListener('keyup', () => this.updateToolbarState());
|
||||
this.dom.descEditor.addEventListener('mouseup', () => this.updateToolbarState());
|
||||
@@ -1019,6 +1036,7 @@ class GuideEditor {
|
||||
if (document.activeElement !== this.dom.titleInput) this.dom.titleInput.value = step.title || '';
|
||||
if (document.activeElement !== this.dom.descEditor) this.dom.descEditor.innerHTML = step.descriptionHtml || '';
|
||||
this.dom.statusSelect.value = step.status || 'todo';
|
||||
this.updateAiButtonHints();
|
||||
this.dom.hiddenToggle.querySelector('input').checked = Boolean(step.hidden);
|
||||
this.dom.skippedToggle.querySelector('input').checked = Boolean(step.skipped);
|
||||
this.dom.forceNewPageToggle.querySelector('input').checked = Boolean(step.forceNewPage);
|
||||
|
||||
Reference in New Issue
Block a user