Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6b51428
feat: add prompt shortcut storage and settings [risk:high]
Leeeon233 Sep 5, 2026
092c559
feat: rework Prompt Shortcut settings and local-first publication [ri…
Leeeon233 Sep 6, 2026
f893905
fix: tighten the Prompt Shortcut editor layout [risk:medium]
Leeeon233 Sep 6, 2026
b1aa3d1
fix: grow a variable default from one row [risk:low]
Leeeon233 Sep 6, 2026
49e4ae4
feat: add Prompt Shortcut invocation and sending [risk:high]
Leeeon233 Sep 6, 2026
e1ee4ff
fix: keep mention menus interactive inside dialogs [risk:medium]
Leeeon233 Sep 6, 2026
d204be5
feat: rework the Shortcut parameter tray and drop expand-and-edit [ri…
Leeeon233 Sep 6, 2026
e128e02
fix: give the Shortcut list and parameter tray a right column [risk:low]
Leeeon233 Sep 6, 2026
201b9ba
feat: give a Prompt Shortcut its own emoji [risk:medium]
Leeeon233 Sep 6, 2026
88dadb4
feat: carry filled values in a Shortcut chip and stay optimistic [ris…
Leeeon233 Sep 7, 2026
df8e150
feat!: remove Prompt Shortcut variables [risk:high]
Sep 10, 2026
24c04c4
feat: gate Prompt Shortcuts behind a developer beta switch [risk:medium]
Leeeon233 Sep 10, 2026
665a216
fix: clear only the accepted landing Shortcut draft [risk:high]
Leeeon233 Sep 10, 2026
e2d7a21
chore: merge main into Prompt Shortcut branch [risk:high]
Leeeon233 Sep 10, 2026
362a08f
chore: format merged landing composer [risk:low]
Leeeon233 Sep 10, 2026
a4e4e11
refactor: remove obsolete Prompt Shortcut paths [risk:high]
Leeeon233 Sep 10, 2026
3aca38b
chore: trim temporary Prompt Shortcut test and story coverage [risk:m…
Leeeon233 Sep 10, 2026
9e33cf4
fix: hide Prompt Shortcut publication warning [risk:low]
Leeeon233 Sep 11, 2026
5d9e150
fix: hide Prompt Shortcut retry button [risk:low]
Leeeon233 Sep 11, 2026
85ef06d
fix: remove Prompt Shortcut author display [risk:low]
Leeeon233 Sep 11, 2026
54a9cdf
chore: remove PR tests and documentation [risk:low]
Leeeon233 Sep 11, 2026
9cc11cc
chore: merge latest main into Prompt Shortcuts [risk:medium]
Leeeon233 Sep 11, 2026
e8a24f8
refactor: insert Shortcut text directly into composer [risk:medium]
Leeeon233 Sep 11, 2026
95dfd48
chore: merge main and preserve both cloud APIs [risk:medium]
Leeeon233 Sep 11, 2026
cf07f3f
fix: keep mention selection callback void [risk:medium]
Leeeon233 Sep 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions .agents/docs/ui-mentions.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ lives in its `README.md`.
expensive one, which is why `getCandidates` must stay lazy and a bare `@` calls
none of them.
3. **Commit.** The candidate's `insertText` is what the user sees in the prompt;
the committed *range* is what carries structured identity (a session id, a Role
the committed _range_ is what carries structured identity (a session id, a Role
id) that no text form could.
4. **Draft persistence and hydration.** Ranges are stored beside the draft, and
rebuilding them from text is only a fallback.
Expand Down Expand Up @@ -52,7 +52,7 @@ every return looking like plain text — and never came back at all if the sourc
never loaded. Hence persistence of the narrow `PersistedMentionRange`: the live
range carries callbacks, which `JSON.stringify` writes as `{}`.

`mergeHydratedMentions` rejects an *overlapping* range, not just an exact
`mergeHydratedMentions` rejects an _overlapping_ range, not just an exact
duplicate, because a session and a path are now the same shape: two sources can
each claim `@fix-ci` at different ends, and only rejecting overlaps keeps the
restored range authoritative.
Expand All @@ -71,8 +71,6 @@ default and reads storage in `onMount`, so latching at mount latches `''` and th

A session mention commits as a plain `@<title-slug>`: the old `session:` marker
was only ever an anchor for the before-send rewrite, and the user had to read it.
It is still the only type whose displayed text differs from what the agent
receives.

Dropping the marker is why hydration has to break a tie:
`hydrateSessionMentionsFromText` skips any token the file source already knows.
Expand Down Expand Up @@ -133,3 +131,16 @@ instruction — so the neutral rows were a second description that had already
drifted (printing stored ids raw, labelling the permission mode "Reasoning"). That
pane is desktop-only: the docked mobile strip is too narrow and has no hover to
preview with.

## Prompt Shortcuts

The Slash menu has separate ACP-command and Shortcut sources. Shortcut discovery
reads the index; selecting a result loads and freezes its body before committing
an inline range. Opaque payload history preserves that snapshot through Undo.
`compileShortcutPrompt` combines ordinary rewrites with `expandShortcut` output
in original coordinates, producing the final text and spans together.

Template editors reuse these primitives with explicit author-selected scope and
exclude Sessions, recursive Shortcuts and ACP commands. Product constraints live
in the [mention rules](../../packages/components/src/components/mentions/AGENTS.md)
and [settings rules](../../packages/components/src/components/settings/AGENTS.md).
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Prompt Shortcut composer integration

Status: implemented
Translation: pending
PR: https://github.com/LodyAI/Lody/pull/575

## Abstract

Prompt Shortcuts add frozen inline invocations to the composer while the main
branch introduces submission ownership and stable textarea hydration. Their
integration keeps the existing submission lifecycle and window owner behavior,
and preserves Shortcut preparation cancellation and identity-scoped recovery.
Accepted submissions must clear only their own Shortcut checkpoint, including
when completion arrives after switching composers. Live dependency resolution
and gateway end-to-end behavior remain unverified.

## Decisions

- `MainLayout` retains workspace window ownership for singleton background work
and mounts one readiness- and developer-gated Shortcut provider.
- Session submission uses `useComposerSubmission`; Shortcut compilation runs
before the existing accepted-message boundary. Ordinary draft owners remain
responsible for text and ordinary mention persistence.
- Mention preparation keeps a generation ticket, independent of query text.
Main's stable textarea and hydration reset coexist with identity changes that
retire pending Shortcut preparation. Unavailable Role candidates and exact
unavailable Shortcut matches remain disabled with reasons.
- Clearing only the ordinary draft after a retired submission leaves an old
Shortcut checkpoint eligible for empty-composer recovery. Cleanup therefore
needs the submitted checkpoint's ownership, not text equality or an
unconditional deletion that can erase a replacement invocation.

## Ablation findings

The product no longer has variables or expand-and-edit. The old standalone
prototype modeled both and had no product consumers. Removing that prototype,
its dedicated story/model tests, and unused editable-annotation/replacement APIs
preserves the real settings, menu, chip and mobile stories.

`compileShortcutPrompt` is the production composer compiler; the second
`expandShortcutComposer` implementation had only test consumers. Its useful
stale/duplicate-range checks now test the production boundary. Likewise, publication
uses the local store's fresh document, not `fromPublishedState`; runtime tests
exercise private-history exclusion and late acknowledgements directly.

| Experiment | Result |
| -------------------------------------------------------------------- | -------------------------------------------------------------- |
| Remove prototype | 26 product regression tests and component types pass |
| Remove replacement/annotation API | 36 primitive/editing/modal tests and types pass |
| Remove duplicate compiler | 40 real send-path tests and shared snapshot tests pass |
| Remove unused publication helper and constant internal loading state | 35 real storage/sync tests and shared types pass |
| Inline the identical Shortcut range predicate | 44 draft/submission tests and component types pass |
| Disable semantic history temporarily | Undo loses the frozen invocation; one test fails |
| Accept stale preparation temporarily | Edit-away/back and dismissal insert late chips; two tests fail |

The negative controls were restored. Account/workspace fencing, preparation,
semantic history, ordered writes and checkpoint ownership remain required.
Duplicate mention rationale now lives only in the existing mention pipeline
article, and Settings rules have one scoped owner.

## Verification limits

Checks use the outer dependency installation with test environment variables
isolated. Its affected-check wrapper remains blocked by the existing indexed OSS
revision mismatch; the standalone public E2E package is not in that dependency
graph. Production mobile bundling previously exhausted the Node heap. Live
dependency resolution, full production builds and gateway E2E remain unverified.
72 changes: 68 additions & 4 deletions locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -3821,7 +3821,7 @@
"mention.category.issue.label": "Issues",
"mention.category.pr.label": "Pull Requests",
"mention.category.skill.label": "Skills",
"mention.category.command.label": "Commands",
"mention.category.command.label": "Agent Commands",
"mention.menu.back": "Back",
"mention.menu.noResults": "No results",
"mention.menu.loading": "Loading…",
Expand Down Expand Up @@ -3927,11 +3927,9 @@
"settings.agentRoles.issues.modelUnsupported": "model “{{value}}”",
"settings.agentRoles.issues.optionUnsupported": "option “{{option}}”",
"settings.agentRoles.issues.optionValueUnsupported": "option “{{option}}” value “{{value}}”",
"settings.agentRoles.form.emoji": "Emoji",
"settings.agentRoles.errors.nameTaken": "Another role already uses this name.",
"emojiPicker.empty": "No emoji found.",
"emojiPicker.placeholder": "Select an emoji…",
"settings.agentRoles.form.emojiReset": "Reset to {{emoji}}",
"settings.agentRoles.form.memory": "Memory",
"settings.agentRoles.form.memoryHint": "Not supported yet. Every session this role creates starts fresh — it remembers nothing from earlier ones.",
"sessions.fileViewer.pathCopyFailed": "Failed to copy file path",
Expand Down Expand Up @@ -3963,5 +3961,71 @@
"sessions.fileViewer.pageUnavailable": "File changed or is unavailable. Reopen the preview.",
"sessions.copyContextMarkdown": "Copy context as Markdown",
"sessions.copyContextMarkdownHint": "Copy the conversation through this message",
"sessions.copyContextIncomplete": "The last response was still generating when copied."
"sessions.copyContextIncomplete": "The last response was still generating when copied.",
"settings.promptShortcuts.intro": "Saved Prompts you can call with a slash command. Each one says where it applies; a Shortcut with nothing set works anywhere in this workspace. Private until you share it.",
"settings.promptShortcuts.new": "New Prompt Shortcut",
"settings.promptShortcuts.empty": "No Prompt Shortcuts yet. Save a Prompt you retype often and call it with /.",
"settings.promptShortcuts.private": "Private",
"settings.promptShortcuts.shared": "Shared",
"settings.promptShortcuts.readOnly": "Read-only",
"settings.promptShortcuts.workspaceScope": "Workspace",
"settings.promptShortcuts.needsAttention": "A reference is outside this scope",
"settings.promptShortcuts.retryHelp": "Some changes could not be loaded or published. Your local saves are kept, and you can keep editing.",
"settings.promptShortcuts.delete": "Delete shortcut",
"settings.promptShortcuts.deleteTitle": "Delete Prompt Shortcut",
"settings.promptShortcuts.deleteHelp": "Delete “{{name}}”? Prompts already inserted into drafts or sent messages are unchanged.",
"settings.promptShortcuts.edit": "Edit Prompt Shortcut",
"settings.promptShortcuts.view": "Prompt Shortcut",
"settings.promptShortcuts.editorHelp": "Saved to this workspace and sent as one message.",
"settings.promptShortcuts.readOnlyHelp": "Shared by another member. Only its author can change it.",
"settings.promptShortcuts.name": "Name",
"settings.promptShortcuts.command": "Slash command",
"settings.promptShortcuts.commandPlaceholder": "review-pr",
"settings.promptShortcuts.description": "Description (optional)",
"settings.promptShortcuts.descriptionPlaceholder": "Description — shown in the / menu",
"settings.promptShortcuts.scope": "Applies to",
"settings.promptShortcuts.project": "Project",
"settings.promptShortcuts.machine": "Machine",
"settings.promptShortcuts.agent": "Agent",
"settings.promptShortcuts.none": "None",
"settings.promptShortcuts.thisMachine": "Limit to this machine",
"settings.promptShortcuts.mentionScope": "Not available for the scope set in “Applies to”.",
"settings.promptShortcuts.mentionScopeMissing": "Set {{axes}} in “Applies to” first.",
"settings.promptShortcuts.prompt": "Prompt",
"settings.promptShortcuts.promptHelp": "One message. @ mentions a file or Role, $ a skill, # an issue. The selectors below say where this Shortcut can be called and what @ completes against — None on every axis means anywhere in this workspace.",
"settings.promptShortcuts.promptPlaceholder": "Write the prompt you would otherwise retype.",
"settings.promptShortcuts.repairScope": "Restore the matching scope or remove these mentions before saving.",
"settings.promptShortcuts.requiredAxes": "Requires matching {{axes}}",
"settings.promptShortcuts.share": "Share with workspace",
"settings.promptShortcuts.shareHint": "Off by default. Sharing is separate from where the Shortcut applies.",
"settings.promptShortcuts.shareWarning": "Workspace members can read and copy this Prompt and its reference labels. Making it private later cannot remove copies they already received.",
"settings.promptShortcuts.create": "Create",
"settings.promptShortcuts.invalid": "Could not save. Check the name, command, mention scope and size limits, then try again.",
"settings.tabs.promptShortcuts": "Prompt Shortcuts",
"settings.categories.promptShortcuts.description": "Reusable Prompts and mentions",
"settings.emoji.label": "Emoji",
"settings.emoji.reset": "Reset to {{emoji}}",
"mention.category.promptShortcut.label": "Prompt Shortcuts",
"promptShortcut.unverified": "Dependencies cannot be verified yet.",
"promptShortcut.checking": "Checking availability…",
"promptShortcut.projectMismatch": "Requires a different project.",
"promptShortcut.machineMismatch": "Requires a different machine.",
"promptShortcut.providerMismatch": "Requires a different agent.",
"promptShortcut.machineOffline": "Required machine is offline.",
"promptShortcut.missingScope": "A reference requires an explicit scope.",
"promptShortcut.scopeMismatch": "A reference does not match the saved scope.",
"promptShortcut.permissionDenied": "A required reference is no longer accessible.",
"promptShortcut.dependencyMissing": "A required reference is unavailable.",
"promptShortcut.private": "Private",
"promptShortcut.shared": "Shared",
"promptShortcut.unknownAuthor": "Unknown author",
"promptShortcut.loadingBody": "Loading Shortcut…",
"promptShortcut.versionChanged": "Shortcut changed. Select it again to retry.",
"promptShortcut.bodyOffline": "Body is not available offline. Reconnect and select again.",
"promptShortcut.loadFailed": "Could not load Shortcut. Select it again to retry.",
"promptShortcut.draftSaveFailed": "Could not save this Shortcut draft locally. Keep this composer open and retry your edit.",
"promptShortcut.promptTooLarge": "Expanded prompt exceeds the size limit.",
"promptShortcut.invalidDraft": "This Shortcut draft is incomplete. Remove the affected chip and insert it again.",
"settings.beta.promptShortcutsHelper": "Create reusable prompts and insert them with /. In development — expect rough edges.",
"settings.promptShortcuts.disabled": "Enable Prompt Shortcuts under Developer mode in Settings → About to use this feature."
}
Loading
Loading