<feed xmlns='http://www.w3.org/2005/Atom'>
<title>soryu/makima/frontend/src/components/directives/DocumentEditor.tsx, branch master</title>
<subtitle>soryu-co/soryu mirror</subtitle>
<id>http://src.eirin.xyz/soryu/atom?h=master</id>
<link rel='self' href='http://src.eirin.xyz/soryu/atom?h=master'/>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/'/>
<updated>2026-05-16T17:04:17+00:00</updated>
<entry>
<title>fix(directives): tasks folder visibility, circular auto-save timer, unlock-to-edit (#133)</title>
<updated>2026-05-16T17:04:17+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-05-16T17:04:17+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=8e2bbcab1a7b3b9005803d7ce3bfce7fa483a4d7'/>
<id>urn:sha1:8e2bbcab1a7b3b9005803d7ce3bfce7fa483a4d7</id>
<content type='text'>
* feat: soryu - makima: Fix tasks/ folder visibility and rename for multi-contract directives

* feat: soryu - makima: Replace auto-save countdown text/bar with a circular timer

* feat: soryu - makima: Require Unlock before editing a locked contract body</content>
</entry>
<entry>
<title>refactor(frontend): DocumentEditor takes explicit body/title/documentId props (#131)</title>
<updated>2026-05-08T12:43:17+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-05-08T12:43:17+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=e4f1622a0f0ac74707cc1c9810e0b99e948d1319'/>
<id>urn:sha1:e4f1622a0f0ac74707cc1c9810e0b99e948d1319</id>
<content type='text'>
Stops shadowing directive.goal with the contract body via a synthesised
directive object. DocumentEditor now accepts:

  * documentId — scopes the localStorage draft key per contract so
    switching contracts under the same directive doesn't clobber the
    other's unsaved edits.
  * title      — the contract title rendered as the H1.
  * body       — the contract body, used to seed the editor.
  * onUpdateBody (was onUpdateGoal)

The `directive` prop stays for orchestrator state + embedded steps
panel. document-directives.tsx drops the directiveAsDocument synthesis
hack and passes body/title from the contract directly.

This is the prep-work for dropping `directives.goal` from the schema —
once nothing reads it, the column can be dropped in a follow-up
without touching the editor.

Co-authored-by: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>fix(doc-mode): root-walk goal serializer + roundtrip-confirmed draft drop, plus richer context menus (#114)</title>
<updated>2026-04-30T22:26:10+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-04-30T22:26:10+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=6d922307223d12f436b229d4c4b29b8835b93b6c'/>
<id>urn:sha1:6d922307223d12f436b229d4c4b29b8835b93b6c</id>
<content type='text'>
## The data-loss bug

User reported "even after clicking Save now I have lost my doc". Two causes:

1. **GoalChangePlugin only read children[1]** — it captured edits to the
   single goal paragraph but silently dropped any typing that landed in
   the trailing paragraph below the StepsBlock (or in extra paragraphs the
   user had inserted). pendingGoalRef stayed at the persisted value, Save
   now fired empty/stale content, the doc was overwritten.

2. **fireSave dropped localStorage immediately on save success.** If the
   save persisted the wrong/empty content, the draft (which had the real
   content) was already gone — no recovery path.

## Fixes

### Capture all body content
New `serializeGoalFromRoot` walks the entire root, skips only the H1 title
and the StepsBlock decorator, and emits multi-paragraph markdown joined by
blank lines. `GoalChangePlugin` and `fireSave` both call it now. Seed code
splits an existing multi-paragraph goal back into ParagraphNodes on load.

### Read directly from the editor at save time
`fireSave` now reads pendingGoalRef AND consults the live editor state via
`editor.getEditorState().read()`. If anything went wrong with OnChangePlugin
(which is rare, but possible — and was eating typing for many users), the
save still picks up the actual document body.

### Defensive pre-save flush
Before talking to the backend, `fireSave` writes the value to localStorage.
If the network fails, the page closes mid-flight, or anything else goes
sideways, the draft survives.

### Roundtrip-confirmed draft cleanup
We no longer drop the localStorage draft inside `fireSave`. Instead a new
effect watches `directive.goal` and clears the draft only when:
  lastSavedValueRef === directive.goal === pendingGoalRef.current
i.e. only when the polled state confirms our save persisted AND the user
hasn't typed anything new in the meantime.

## Question notifications respect document mode

`SupervisorQuestionNotification` and `PhaseConfirmationToast` now route to
`/directives/&lt;id&gt;?task=&lt;taskId&gt;` (the doc-mode surface) when the user has
documentMode on AND the question carries a directiveId. Falls back to the
old `/exec/:taskId` route for non-doc-mode users.

## Richer directive folder context menu

In addition to start/pause/archive/delete/go-to-PR/new-draft we now expose:
  - Advance DAG
  - Plan orders
  - Clean up
  - Create / Update PR
All optional callbacks; the legacy tabular UI is unaffected.

## Richer task row context menu

In addition to interrupt/complete/fail/skip we now expose:
  - Send message — browser prompt → sendTaskMessage (same wire as the
    inline comment box)
  - Open in task page — navigates to /exec/:taskId for the full task UI
    (worktree diff viewer, checkpoint controls, etc.)

Co-authored-by: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>feat(doc-mode): rename surfaced label "Directive" → "Contract" (#109)</title>
<updated>2026-04-30T16:06:31+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-04-30T16:06:31+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=36f65f294ce33325a9eea9b7a8629706a4def721'/>
<id>urn:sha1:36f65f294ce33325a9eea9b7a8629706a4def721</id>
<content type='text'>
Stage 2: cosmetic UI rename only. Database tables, API paths, hook names,
and CLI commands all stay as 'directive' for now — we'll phase out the
existing standalone /contracts table later.

Surface changes:
- Sidebar header "Documents" → "Contracts"; root folder "directives/" →
  "contracts/"; empty state "No directives yet" → "No contracts yet".
- Editor placeholders, breadcrumb header, "back to document" → "back to
  contract", right-click menu header.
- NavStrip: when documentModeEnabled is on, the "Directives" link renders
  as "Contracts" (href stays /directives so links don't break).
- Save bar message "saving will replan the directive" → "the contract".

No backend changes — directive.goal etc. all still work the same.

Co-authored-by: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>fix(doc-mode): autosave robustness, draft→active flip, save-now, sidebar context menus (#108)</title>
<updated>2026-04-30T14:48:26+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-04-30T14:48:26+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=2dafe938f41edbb8ceb7c6a3655c9533bb50e47d'/>
<id>urn:sha1:2dafe938f41edbb8ceb7c6a3655c9533bb50e47d</id>
<content type='text'>
Stage 1 of the planned doc-mode revamp — bug fixes + UX polish ahead of the
larger contract-revisioning architecture work.

## Backend: 'draft' included in goal-update status flip

repository::update_directive_goal previously flipped only idle/paused → active
on a goal save, leaving 'draft' alone. That meant brand-new directives got
their goal persisted on save but never spawned a planner — exactly the
"orchestrator never runs" report. Extended the CASE clause so 'draft' also
flips to 'active' on save. The status remains visible to users; this just
makes the implicit "first goal save = start" behaviour work end-to-end.

## Autosave robustness (DocumentEditor.tsx)

The synchronous-write fix from the previous PR was correct in principle but
not visible enough for users to confirm it was working, and could still drop
the very last edit on an abrupt tab close. This change:

- Adds beforeunload / pagehide / visibilitychange handlers that synchronously
  flush pendingGoalRef → localStorage (skipping if it matches the persisted
  value). Backed by a persistedGoalRef that tracks directive.goal in real
  time so the handler doesn't capture a stale closure.
- Tracks the timestamp of every successful draft write (draftSavedAt) and
  surfaces it as a "Draft saved Ns ago" stamp in the bar — refreshed on a
  1Hz ticker so users can SEE the autosave is alive.
- Logs a console.warn on localStorage write failure (was silently swallowed)
  so quota / storage-disabled environments are diagnosable.

## Always-visible save bar + Save now button

The bar now renders in every state (was hiding when idle/pending-with-time-
remaining). Idle shows a quiet "Up to date." Pending outside the last 10s
shows "Unsaved changes — auto-save soon." Save now is always present;
disabled only when truly idle.

## EXEC and CONTRACTS hidden in document mode

NavStrip filters Contracts and Exec links when settings.documentModeEnabled
is true. Those areas are subsumed by the directive-document interface; the
nav strip stops surfacing them so document mode users have one canonical
place to work.

## Right-click context menus on sidebar

Right-clicking a directive folder header opens DirectiveContextMenu with
start / pause / archive / delete / Go-to-PR — same component the legacy
list page uses. Right-clicking a task row inside the tasks/ subfolder opens
a smaller TaskContextMenu with Interrupt (for orchestrator/completion/
running steps) and Mark complete / failed / skipped (for step rows).
Step lifecycle calls require the directive_step.id, so FolderTaskRow now
carries stepId alongside taskId.

Co-authored-by: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>feat(document-mode): folder layout v2, glow on pending, inline formatting, autosave fix (#107)</title>
<updated>2026-04-30T11:12:48+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-04-30T11:12:48+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=a2148d4e3117cdda2e1d0a8e3df289bfe04789a3'/>
<id>urn:sha1:a2148d4e3117cdda2e1d0a8e3df289bfe04789a3</id>
<content type='text'>
## Autosave bug fix (top priority)

The 250ms debounce on the localStorage draft write was racing the unmount
cleanup: typing then navigating within 250ms cleared the pending timer
*before* it flushed, which is exactly when we needed the draft saved.
Drafts are now written synchronously on every keystroke. localStorage
.setItem on a small string is sub-millisecond — the debounce was a
premature optimisation.

## Sidebar v2 (document-directives.tsx)

- Tasks now live in a `tasks/` subfolder inside each directive folder
  (orchestrator, completion, and started step tasks). The pinned `.md`
  document remains at the top of the directive folder.
- Status circles moved to the RIGHT side only (previously rendered on
  both sides, which the user found noisy).
- New `StatusDot` component composes the status colour with two optional
  modifiers: a "live" pulse when the orchestrator is running, and a
  GLOW (amber ring + pulse) when there is a pending user question for
  that directive or task. The glow is sourced from the existing
  SupervisorQuestionsContext, indexed by `directiveId` and `taskId`.
- New `TaskIcon` (terminal) and `CompletionIcon` (PR-bracket) so
  orchestrator/step/completion entries look distinct from the .md file.

## Inline formatting in the editor (DocumentEditor.tsx)

- New `MarkdownShortcutPlugin` (scoped to TEXT_FORMAT_TRANSFORMERS only)
  so typing `**foo**`, `*foo*`, `` `foo` ``, `~~foo~~` auto-formats inline.
  Block-level shortcuts (# heading, - list) are intentionally excluded so
  the document shape (H1 / goal / StepsBlock / trailing para) stays intact.
- New `FloatingFormatToolbar` appears above any non-collapsed selection
  inside the goal paragraph, with B / I / U / S / &lt;/&gt; buttons that
  dispatch FORMAT_TEXT_COMMAND. Buttons highlight when the corresponding
  format is active. Standard ⌘B / ⌘I / ⌘U keyboard shortcuts also work
  via the existing RichTextPlugin.
- Round-trip via a small inline-only markdown serializer/parser so
  formatting persists across saves. Supported markers: `\``code\``,
  `***bold-italic***`, `**bold**`, `*italic* / _italic_`, `~~strike~~`.
  Underline survives within the editor session (toolbar / shortcut) but
  has no markdown syntax so it does not round-trip — by design.
- No backend schema change: `directive.goal` is still a TEXT column, it
  just contains inline markdown now.

Co-authored-by: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>feat(document-mode): longer goal save countdown, per-directive folders, live task stream (#103)</title>
<updated>2026-04-30T08:57:07+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-04-30T08:57:07+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=2b695485753d55f956746b73c31c2deba0ed0a29'/>
<id>urn:sha1:2b695485753d55f956746b73c31c2deba0ed0a29</id>
<content type='text'>
Three connected UX changes for the document-mode directive UI.

## Goal save UX (DocumentEditor.tsx)
- Replace the old 3-second countdown with 60s when no orchestrator is running
  and 10s when one is, so editing a goal mid-flight does not feel rushed.
- The countdown bar is hidden until the last 10 seconds; users see "Saved" /
  "Unsaved changes" indicators rather than a constantly-ticking clock.
- Continuously persist work-in-progress to localStorage on every keystroke
  (debounced 250ms). On mount, if a draft for the directive exists in
  localStorage and differs from the persisted goal, restore it and put the
  editor in dirty/pending state — leaving the page no longer loses work.
- localStorage-backed "Live start" toggle in the bar. When off, the editor
  stays in "dirty" instead of auto-firing; user clicks "Save now" to commit.
- Discard button reverts the editor to the persisted goal and clears the draft.

## Sidebar restructure (document-directives.tsx)
- Drop the active/idle/archived top-level grouping; show one folder per
  directive instead. Folders sort by lifecycle (active, paused, idle, draft,
  archived) then alphabetically.
- Each folder header shows a colored status dot on BOTH sides (left as the
  primary status icon, right as a mirror plus a pulse when the orchestrator
  is live), replacing the previous "/active", "/idle" text labels.
- Inside each open folder: the directive's document is pinned at the top
  (with a small star icon), then the orchestrator task (if running), then
  the completion task, then any step tasks that have started.
- The currently-selected directive's folder is auto-opened so deep links
  always land somewhere visible.

## Live document task stream (DocumentTaskStream.tsx, new)
- Selecting a task in a folder navigates to ?task=&lt;id&gt; and replaces the
  Lexical editor with a document-styled live transcript: assistant prose as
  flowing paragraphs, tool calls as marginalia, results as a closing block.
  No log/code box.
- Comment textarea at the bottom calls sendTaskMessage on submit, the same
  wire the existing TaskOutput input bar uses for interrupts. ⌘/Ctrl-Enter
  submits.
- Header breadcrumb gains a "back to document" affordance to return to the
  pinned doc view without reopening the sidebar.

Co-authored-by: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>feat: document-mode directive UI proof of concept (Lexical) (#101)</title>
<updated>2026-04-29T00:10:11+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-04-29T00:10:11+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=4b1d608b839769052634b4facc345b891d468926'/>
<id>urn:sha1:4b1d608b839769052634b4facc345b891d468926</id>
<content type='text'>
* WIP: heartbeat checkpoint

* feat: soryu-co/soryu - makima: Backend: feature flag + goal-edit interrupt messaging

* WIP: heartbeat checkpoint

* WIP: heartbeat checkpoint

* feat: soryu-co/soryu - makima: Frontend: Lexical document editor with step blocks, context menu, countdown</content>
</entry>
</feed>
