Skip to content

Fix/electron local file browser - #38

Closed
zxch3n wants to merge 200 commits into
LodyAI:mainfrom
loro-dev:fix/electron-local-file-browser
Closed

zxch3n wants to merge 200 commits into
LodyAI:mainfrom
loro-dev:fix/electron-local-file-browser

Conversation

@zxch3n

@zxch3n zxch3n commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

No description provided.

lodystage Bot and others added 30 commits August 10, 2026 10:36
…um] (#1)

Model: gpt-5

Co-authored-by: Lody Dev <zx@loro.dev>
Model: gpt-5

Co-authored-by: Lody Dev <zx@loro.dev>
* feat(cli): update built-in ACP runtimes [risk:high] (#27)

* feat: update built-in ACP runtimes [risk:high]

Model: GPT-5.6

* chore: refresh public dependency lock [risk:high]

Model: GPT-5.6

* fix: gate provider-neutral goal controls [risk:high]

Validate neutral goal snapshots strictly, normalize limited status for mixed-version history, and keep non-Codex goals read-only until the ACP extension control method is routed through Lody.

Model: GPT-5.6

* fix: separate goal and prompt activity [risk:high]

Treat active goals as persistent session state rather than live turn presence, keep quiescent sessions directly dispatchable, and preserve completion notifications and working indicators around actual prompt activity.

Model: GPT-5.6

* fix: preserve goal activity helper API [risk:high]

Keep a deprecated isSessionGoalWorking alias for external consumers while documenting that it reports persistent goal state rather than live prompt activity.

Model: GPT-5.6

* docs: changelog

* fix(components): close empty session side panel [risk:medium]

Model: gpt-5

---------

Co-authored-by: Zixuan Chen <me@zxch3n.com>
Co-authored-by: Lody Dev <zx@loro.dev>
Model: gpt-5

Co-authored-by: Lody Dev <zx@loro.dev>
Show the sidebar update prompt while the update is still downloading, and
open the changelog in an app dialog instead of a hardcoded lody.ai link.
Release notes render as sanitized Markdown (raw HTML off); the localized
website changelog stays as the no-notes fallback.

Model: claude-opus-5[1m]
Match the agreed updater contract: the changelog text and the fallback
website link both follow i18n.resolvedLanguage instead of the stored
language preference.

Model: claude-opus-5[1m]
Bind embedded localized notes to the exact update version and keep the external changelog fallback limited to missing in-app content.

Model: GPT-5
…um] (#8)

Inviting a member to a paid workspace adds a billed seat, and Stripe
invoices the prorated difference the moment the invitation is accepted.
The dialog only asked for an email, so the payer learned about the charge
from the next invoice.

Redesign the invite dialog as one shared component for the desktop and
mobile account settings, and give it a seat-cost block: how much is
charged on acceptance, the per-seat price and that it is prorated, and
the recurring total from the next renewal. Free workspaces and
gift/enterprise entitlements are not billed per seat and say so (or say
nothing) instead of quoting a number.

Model: claude-opus-5[1m]

Co-authored-by: Lody Dev <zx@loro.dev>
Model: gpt-5

Co-authored-by: Leeeon233 <leeeon233@gmail.com>
Bumps the catalog entry and the pinned CLI runtime dependency from 1.14.0 to
1.14.1.

loro-crdt 1.14.1 makes `importBatch` atomic: the batch now runs in an OpLog
rollback scope, so a blob that decodes but fails state validation returns an
error with the document still attached instead of trapping in WASM and leaving
the document permanently detached. It also drops the quadratic preflight rescan
for out-of-order updates (~3.4s -> ~0.45s for 12000 updates).

The lockfile also picks up the `apps/cli` -> `tsx@^4.23.5` importer entry that
was missing from the public lockfile; no package versions change from it.

Model: claude-opus-5[1m]

Co-authored-by: Zixuan Chen <me@zxch3n.com>
Bumps the catalog entry and the pinned CLI runtime dependency from 1.14.0 to
1.14.1.

loro-crdt 1.14.1 makes `importBatch` atomic: the batch now runs in an OpLog
rollback scope, so a blob that decodes but fails state validation returns an
error with the document still attached instead of trapping in WASM and leaving
the document permanently detached. It also drops the quadratic preflight rescan
for out-of-order updates (~3.4s -> ~0.45s for 12000 updates).

The lockfile also picks up the `apps/cli` -> `tsx@^4.23.5` importer entry that
was missing from the public lockfile; no package versions change from it.

Model: claude-opus-5[1m]

Co-authored-by: Zixuan Chen <me@zxch3n.com>
Keep Grok interaction_mode in the unified run-config selectors instead of consuming it as the legacy standalone mode control.\n\nModel: gpt-5.6-sol
Localize the Lody-owned Grok interaction and permission compatibility selectors while preserving their ACP wire values and upstream labels for other providers.\n\nModel: gpt-5.6-sol
Model: gpt-5.6-sol

Co-authored-by: Lody Dev <zx@loro.dev>
zxch3n and others added 19 commits August 23, 2026 01:03
* feat(components): gate App Store review prompts [risk:medium]

Model: GPT-5

* fix(components): keep App Store review policy shared [risk:medium]

Keep eligibility persistence and policy evaluation in the shared prompt hook, while the mobile app exposes only the StoreKit request bridge.

Model: GPT-5

* fix(components): harden App Store review prompting [risk:medium]

Baseline only after session history sync, exclude canceled and failed turns, and avoid repeated local storage writes during streaming updates.

Model: GPT-5

* fix(components): preserve App Store review idle timer [risk:medium]

Decouple outcome persistence from the prompt timer so identity-only history updates cannot consume and cancel an eligible turn.

Model: GPT-5

---------

Co-authored-by: Leeeon233 <leeeon233@gmail.com>
* fix(cli): keep direct local sessions branchless [risk:medium]

Avoid capturing a branch for direct local-project sessions so delayed dispatches do not attempt a dirty-worktree checkout.\n\nModel: gpt-5.6-sol

* fix(cli): preserve current branch for legacy local sessions [risk:medium]

Treat stored branches on existing direct local sessions as historical metadata when ACP must be initialized again, so dirty worktrees are never checked out.

Model: gpt-5.6-sol
Model: gpt-5.6-sol

Co-authored-by: Lody Dev <62133302+wibus-wee@users.noreply.github.com>
Model: gpt-5

Co-authored-by: Leeeon233 <leeeon233@gmail.com>
Model: gpt-5.6-sol
* docs: add agent role design proposal

Model: gpt-5

* feat: resolve Agent Roles in session creation

Model: gpt-5

* docs: record Agent Role operation invariant

Model: gpt-5

* fix: preserve GitHub context for Role sessions

Model: gpt-5

* feat(components): add Agent Role settings and mentions [risk:medium]

Agent Role V1, UI side only: authoring, sharing, and mentioning a reusable
Session-creation preset. CLI/MCP Session orchestration is a separate task.

Shared contract:
- `AgentRole`, `AgentRoleInvocationSnapshot`, validators, and the visibility,
  availability, and work-context rules every surface must reuse.
- One `agentRole` row family in the existing workspace Flock document, so
  sharing is an ordinary update of `visibility` rather than a move between two
  catalogs.
- `agentRoleInvocations` on the Turn input config, plus the `agent_role`
  message text span.
- A Role stores no secret: `isSensitiveAgentRoleConfigOptionKey` is applied on
  read as well as on write, because a workspace row reaches every member.

Settings → Agent Roles:
- List, create, edit, duplicate, delete, and a default-off workspace share
  toggle; unavailable and saved-but-unsynced states name their exact reason.
- Machine, agent config, model, reasoning, and run options are generated from
  the selected agent's published capabilities; nothing is offered for an agent
  whose capabilities are unknown, and an incompatible saved value is reported
  rather than replaced.

Mentions:
- Agent Roles category, `agent_role` range/span/chip, and draft hydration.
- Candidates pass visibility, executability, then work context: a GitHub
  composer may reach any authorized machine, a local one is pinned to its own.
- Sending freezes the picked Roles into the Turn as `agentRoleInvocations`, from
  the same committed ranges the prompt rewrite uses.

Model: claude-opus-5[1m]

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(shared): declare Agent Role provenance on SessionMeta [risk:low]

The CLI already writes a Session's originating Role, but `SessionMeta` had no
such field, so `session create` carried a local intersection type for it. Move
the two fields into the shared contract that both sides read:

- `SessionMeta.agentRoleId` / `agentRoleRevision`, documented as provenance
  only — execution, recovery, and retry read the already-frozen dispatch config
  and Turn input config, never the mutable Role catalog.
- Cover `agentRoleInvocations` in `normalizeSessionTurnInputConfig`: the CLI
  authorizes an `agentRoleId` solely against that field of the driving Turn, so
  it has to survive the same normalization the Turn does — including dropping a
  secret-shaped option key out of a stored run config.

Model: claude-opus-5[1m]

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* refactor(components): simplify Agent Role authoring and mention copy [risk:medium]

Review feedback on the Agent Role UI, taken before release so no stored Role
has to be migrated.

- One label. The mention token is derived from the name
  (`getAgentRoleMentionSlug`) instead of a second authored "mention name" field,
  so renaming a Role renames its mention and uniqueness is checked on the token
  two names would share. The description field is gone with it.
- A Role carries an optional emoji, shown before its name in the mention menu
  and in the settings row.
- No "Agent default" entry. Selecting an agent config seeds the agent's own
  published defaults into the unset run-config fields, so every control shows a
  concrete value; a stored selection is never overwritten, which is what keeps
  an incompatible one visible instead of silently replaced.
- Duplicating a Role, and the banner for a delete that is durable locally but
  not yet synced, are both removed: the delete syncs on its own and there was
  nothing for the user to act on.
- The message copy button collapses an `agent_role` span back to `@Name`. Its
  rewritten region is an instruction addressed to this agent and means nothing
  pasted elsewhere. Edit-and-resend still reads the expanded text, because a
  token with no committed range would reach the agent as a word.

Model: claude-opus-5[1m]

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(components): pick an Agent Role emoji with a real picker [risk:low]

Typing an emoji into a text field means knowing the OS shortcut, and an empty
slot makes "no emoji" read as an unfinished form. So the field is now a filled
button that opens a picker, the way a Notion page icon works.

- Adds the shadcn `frimousse` emoji picker
  (`npx shadcn@latest add https://frimousse.liveblocks.io/r/emoji-picker`) as
  `ui/emoji-picker.tsx`, minus the `"use client"` banner this repo has no
  boundary for, with its two visible strings on i18n and its locale following
  the product language rather than the host OS.
- The picker is a Popover portalled into the settings dialog content, like
  `option-selector.tsx`: a body-level portal sits outside the dialog's scroll
  lock, and this popover's whole content is a scrolling list.
- `DEFAULT_AGENT_ROLE_EMOJI` is the shared fallback, so the button, the settings
  row, and the mention candidate all show one glyph for a Role whose owner never
  picked one, and choosing is a change rather than a prerequisite.

`pnpm-lock.yaml` and the attribution artifacts carry only the frimousse entries:
regenerating them wholesale in this worktree also swept in unrelated resolution
drift from the acp-extension submodules.

Model: claude-opus-5[1m]

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(components): bundle the emoji dataset with the app [risk:low]

`frimousse` fetches `${emojibaseUrl}/${locale}/{data,messages}.json` from a
public CDN by default, so on a desktop or mobile app with no network the picker
spins forever. Lody is local-first; its emoji list should not need the internet.

- `vite-emojibase-assets.ts` emits `emojibase/{en,zh}/{data,messages}.json` into
  the host build and serves the same paths in dev. It has to be a plugin rather
  than a `?url` import: the library builds those paths at runtime, and a hashed
  asset name cannot satisfy a URL contract.
- The picker reads `getBundledEmojibaseUrl()`, resolved against
  `document.baseURI` because the Electron renderer and the mobile shell both
  load from a scheme where `/…` is not the app root.
- `apps/electron` registers the plugin; a private mobile/web host adds the same
  one line. Locales are limited to the product's own languages — the dataset is
  ~750 KB each.

Verified against a real `electron-vite build --mode oss`: the four files land in
`out/renderer/emojibase/` and `index.html` keeps its relative base.

Model: claude-opus-5[1m]

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(components): serve the bundled emoji data from the app root [risk:low]

The picker failed to open in dev with `Unexpected token '<', "<!doctype "…`:
the dataset URL was resolved against `document.baseURI`, and the router uses
browser history over http, so a deep route asked for
`…/settings/emojibase/en/data.json`. The dev server answered with its SPA
fallback and the picker parsed HTML as JSON.

- Anchor the URL on the Vite base instead. A relative base (the packaged
  Electron renderer) still resolves against the document, which is right there:
  it loads `index.html` over `file:` and switches to hash history, so the
  document path stays the entry file.
- Skip `emitFile` while serving; it is unsupported in that mode and logged a
  "not vite-compatible" warning on every reload.

Settings, same pass:
- The Role's emoji and name are shown as themselves — no "Identity" card, no
  "mentioned as @…" hint under them.
- "Prompt prefix" is now the "Default instruction" and sits above where the
  Role runs, since it is part of what the Role is rather than of its binding.

Model: claude-opus-5[1m]

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(components): group Agent Roles by machine and show their marks [risk:low]

- The list groups by machine, with the machine on a pill above its group. A
  Role binds one machine exactly, so it is what the list is grouped BY rather
  than a fact repeated on every row.
- A row no longer prints `@token`: it is derived from the very name beside it,
  so showing both said one thing twice.
- The second line is now what the Role will RUN — the agent's icon, then model,
  reasoning, and whatever else it pins (`buildAgentRoleRunConfigSummary`). A
  boolean that is off is dropped; an option left at the agent's own default is
  not, because a Role pins concrete values and hiding one would make two
  different Roles read the same.
- The committed mention in the composer carries the Role's own emoji instead of
  the generic glyph. The composer wraps the caller's chip resolver to do it: a
  range carries only the Role id, and only the composer holds the live catalog.

Model: claude-opus-5[1m]

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(components): show an Agent Role by its own emoji everywhere [risk:low]

The Role's mark now stands in for the generic category glyph on all three
surfaces, so one Role looks like one object from the menu to the sent message.

- Menu rows carry `MentionCandidate.iconEmoji` INSTEAD of the category glyph:
  the category header above already says these are Agent Roles, so a second
  generic icon only crowded out the mark. The detail pane has no icon slot, so
  there the mark stays in the title.
- Sent messages read `MessageTextSpan.mark`, frozen with the span at send time
  rather than resolved when the bubble renders. A sent message shows the Role as
  it was, so renaming or re-marking it later cannot repaint history, and
  painting a bubble never waits on the mutable catalog. `sanitizeMessageTextSpans`
  gates it like every other span field: one short glyph or nothing.

Model: claude-opus-5[1m]

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(shared): declare the span mark on the strict send-path schema [risk:medium]

Sending a message that mentioned an Agent Role answered with "Please enter
something to discuss" and dropped the turn.

`MessageTextSpanSchema` is `.strict()`, so the `mark` I added to the span in the
previous commit made `SessionInputBlocksSchema` reject the whole block list.
`normalizeSessionInputBlocks` then fell back to its empty prompt, and the
composer reported an empty message — one unknown key on one span, and the whole
send is refused.

The bar now lives in one place (`MAX_MESSAGE_TEXT_SPAN_MARK_LENGTH`) and both
readers use it. The regression test walks a marked span through the strict
schema AND `normalizeSessionInputBlocks`, which is the pair that has to agree;
it fails against the previous commit.

Model: claude-opus-5[1m]

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(components): close the Agent Role editor on durability, not on upload [risk:medium]

Creating a Role first reported "another role already uses this name", then a
second or two later closed the dialog and showed the Role created.

Both halves came from the same cause: the editor awaited the UPLOAD, not the
write. The local row lands in milliseconds and the catalog room publishes it
immediately, so the still-open create form found the Role it had just written
and failed its own name check — while the dialog waited out the round trip.

- `upsert` now resolves on durability and hands the upload back as `uploaded`.
  The editor closes as soon as the row is durable; a failed upload is reported
  afterwards as a toast — "saved on this device, not yet synced" — never as a
  failed save, and never rolled back.
- `resolveAgentRoleNameCheckExemption` exempts the id an in-flight save claimed,
  the same way an edit's own Role has always been exempt. Claimed BEFORE the
  write, so the row cannot appear while the form still counts it as a stranger.

Model: claude-opus-5[1m]

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(components): stop reporting catalog uploads in settings [risk:medium]

Saving an Agent Role or an MCP server flashed "saved on this device but not yet
synced" and then cleared itself seconds later. The message was neither
actionable nor dismissible, and it described a write that had already succeeded.

Every catalog mutation now resolves on the local Flock write and lets the upload
run on its own:

- No surface waits for the upload, so a dialog closes the moment the row exists
  rather than after a round trip.
- No surface reports it. The row is durable, and the joined catalog room carries
  the document when a one-shot upload cannot; a failed upload is logged.
- What stays forbidden is the opposite — reporting a durable write as failed, or
  rolling one back, because the upload did not go through. The CLI still reports
  its own sync result to the terminal.

The test hangs the upload and asserts the write resolves anyway, which is the
property the editors depend on.

Model: claude-opus-5[1m]

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(components): show the Role instruction, drop the duplicated offline note [risk:low]

- The Settings row no longer repeats "its machine is offline": Roles are grouped
  by machine and the group's pill carries that status, so the sentence was
  printed once per row under it. The pill keeps a screen-reader equivalent now
  that the dot is the whole signal. Reasons about the Role's own binding — a
  deleted agent config, a machine the user cannot reach — still appear.
- The mention detail pane shows the default instruction itself instead of a
  "Prompt" badge saying one exists: what it SAYS is what decides whether this is
  the Role you meant. It renders through a new neutral `MentionCandidateDetail.body`
  field, in its own capped scroll area above the rows, so an instruction of any
  length cannot push machine/agent/model off the pane.
- The Role editor states that memory is not supported: a Role reads like a
  standing assistant, so its owner has to be told that every session it creates
  starts fresh.

Model: claude-opus-5[1m]

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(components): drop the memory icon, mark the instruction optional [risk:low]

- The memory notice is text only. Its glyph decorated a sentence that already
  reads as a note, next to a share row that carries no icon either.
- The instruction section says "(optional)": every other section in the editor
  is required to make a Role run, and this one is the exception. The textarea's
  accessible name stays the plain field name.

Model: claude-opus-5[1m]

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* refactor: reuse shared rules across the Agent Role surfaces [risk:medium]

Quality pass over the Agent Role work. No intended behaviour change.

- The MCP server re-declared what an invocation snapshot is: a local zod schema
  plus a local type shadowing the exported one. The Turn's input config already
  arrives through `normalizeSessionTurnInputConfig`, so the field is typed,
  validated, deduped on `roleId`, and stripped of secret-shaped option keys.
  Reading it directly drops the schema, the `as Record<string, unknown>` cast,
  and an ambiguity branch upstream deduplication made unreachable. The local
  copy was `.passthrough()` — the side that ENFORCES the rule was the one not
  applying it.
- `AGENT_ROLE_MANUAL_OVERRIDE_FIELDS` is derived from
  `SessionRunConfigInputShape` instead of hand-copied. A field added to the
  shape is now a field the mutual-exclusion guard rejects, rather than one the
  schema accepts and `resolveMcpSessionCreate` silently drops.
- Ranking and slug hydration were duplicated verbatim between the session and
  Agent Role mention sources, including the rule that a token a file path
  claims is left alone. Both now share `mention-rank.ts` and
  `hydrateSlugMentionsFromText`, so that precedence has one definition.
- `Section`/`Field` were a third copy of the settings form grammar; they move to
  `settings/form-primitives.tsx`. The Role editor's option-value check reuses
  `isConfigOptionValueValid`, and the copy path's splice loop reuses
  `applyTextRewrites` — whose whole reason to exist is not chaining offset math.
- The Roles editor derives the defaults-filled value at render instead of
  writing it back through an effect whose dep array contained the state it set,
  and an `add` carries its id from the moment the form opens. That deletes
  `savingRoleId` and `resolveAgentRoleNameCheckExemption`: the window they
  covered — the local write landing while the dialog is open — no longer exists.
- Availability selects the loaded-machine KEY SET out of the machine-flock atom
  rather than subscribing to the whole row map, which changed identity on every
  rate-limit or launch-config row of every machine and rebuilt the entire Role
  pipeline each time. Agent config names are indexed once instead of scanned per
  Role, the catalog room reuses a family's array when its rows did not move so a
  Role edit stops invalidating the MCP memos, and the direct create path only
  walks the transcript when a Role is actually involved.
- `frimousse` moves behind a lazy boundary: Settings is reachable from the app
  shell, so a static import parsed the whole picker library at renderer startup
  for a popover that opens inside one editor.
- Dead on arrival, now removed: `getAgentRoleFormMentionSlug`,
  `isValidAgentRoleMentionSlug`, `getWorkspaceAgentRoleCatalog`,
  `WorkspaceFlockRowFamily`, and the availability resolver's unread `context`.
  The emojibase asset directory and bundled-locale list stop being declared in
  both the lib and the Vite plugin, kept in step by a comment and a test.

Model: claude-opus-5[1m]

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Leeeon233 <leeeon233@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Archive, restore, and delete the complete session lifecycle subtree across child tabs and MCP-opened sessions. Preserve the opened-by hierarchy in the archive list while keeping child tabs inside their owner session.

Model: gpt-5.6-sol

Co-authored-by: Leeeon233 <leeeon233@gmail.com>
Model: gpt-5

Co-authored-by: Leeeon233 <leeeon233@gmail.com>
Route same-machine Electron file previews through local IPC only and allow readonly previews outside the workspace.

Model: gpt-5.6
* fix(cli): keep direct local sessions branchless [risk:medium]

Avoid capturing a branch for direct local-project sessions so delayed dispatches do not attempt a dirty-worktree checkout.\n\nModel: gpt-5.6-sol

* fix(cli): preserve current branch for legacy local sessions [risk:medium]

Treat stored branches on existing direct local sessions as historical metadata when ACP must be initialized again, so dirty worktrees are never checked out.

Model: gpt-5.6-sol

* fix(cli): preserve explicit local session branch [risk:medium]

Treat a direct local branch as historical only after ACP session creation proves the session has executed, preserving explicit branches during fresh creation.

Model: gpt-5.6-sol
@zxch3n zxch3n closed this Aug 24, 2026
ladydd added a commit to ladydd/Lody that referenced this pull request Sep 11, 2026
Pin acp-extension-codex to a67f231 (LodyAI/acp-extension-codex#38,
rebased onto current adapter main / 5f0aab0) so compaction waiters
reject when the Codex process exits. Other submodules stay on current
main.

Depends on adapter LodyAI#38. Do not ship a desktop release until that merge.

Closes LodyAI#550
ladydd added a commit to ladydd/Lody that referenced this pull request Sep 11, 2026
Agent Note for pinning acp-extension-codex a67f231 (adapter LodyAI#38) so
/compact does not hang when the process exits after start.
ladydd added a commit to ladydd/Lody that referenced this pull request Sep 12, 2026
Pin acp-extension-codex to a67f231 (LodyAI/acp-extension-codex#38,
rebased onto current adapter main / 5f0aab0) so compaction waiters
reject when the Codex process exits. Other submodules stay on current
main.

Depends on adapter LodyAI#38. Do not ship a desktop release until that merge.

Closes LodyAI#550
ladydd added a commit to ladydd/Lody that referenced this pull request Sep 12, 2026
Agent Note for pinning acp-extension-codex a67f231 (adapter LodyAI#38) so
/compact does not hang when the process exits after start.
ladydd added a commit to ladydd/Lody that referenced this pull request Sep 12, 2026
Pin acp-extension-codex 314b3823 → 31c5ecc (adapter LodyAI#38 rebased onto
adapter main after LodyAI#30).

Model: grok-4.6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants