docs: plan browser inbox text file attachments
This commit is contained in:
parent
bd7558d2f9
commit
5be14d5ec0
|
|
@ -160,6 +160,8 @@ case.selected
|
||||||
browser.capture.page
|
browser.capture.page
|
||||||
browser.capture.selection
|
browser.capture.selection
|
||||||
browser.capture.link
|
browser.capture.link
|
||||||
|
browser.capture.file
|
||||||
|
browser.capture.converted
|
||||||
```
|
```
|
||||||
|
|
||||||
Текущий статус: базовый `verstak.activity` implemented as both a global sidebar
|
Текущий статус: базовый `verstak.activity` implemented as both a global sidebar
|
||||||
|
|
@ -255,8 +257,9 @@ exact domain match into the bound workspace queue. Its first conversion workflow
|
||||||
creates ordinary Markdown notes through the public Files API and publishes a
|
creates ordinary Markdown notes through the public Files API and publishes a
|
||||||
`browser.capture.converted` event, which Activity records through its public
|
`browser.capture.converted` event, which Activity records through its public
|
||||||
provider subscription. Browser Inbox also creates human-readable `.url` link
|
provider subscription. Browser Inbox also creates human-readable `.url` link
|
||||||
files through the public Files API. File attachment capture/conversion is still
|
files through the public Files API. It now accepts selected text files from the
|
||||||
future work.
|
browser extension and creates ordinary workspace files through the public Files
|
||||||
|
API. Binary attachment capture/conversion remains future work.
|
||||||
|
|
||||||
## 9. `official.search`
|
## 9. `official.search`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,8 +57,9 @@ Known remaining gaps:
|
||||||
- Browser extension repository has protocol, queue, and Chromium/Firefox build
|
- Browser extension repository has protocol, queue, and Chromium/Firefox build
|
||||||
scaffold; desktop has a local receiver and mounted-view inbox plugin; receiver
|
scaffold; desktop has a local receiver and mounted-view inbox plugin; receiver
|
||||||
pairing, basic Browser Inbox domain binding, create-note conversion, and
|
pairing, basic Browser Inbox domain binding, create-note conversion, and
|
||||||
create-link conversion are implemented, and Activity records conversions.
|
create-link conversion are implemented, text file attachment conversion is
|
||||||
File attachment capture/conversion remains future work.
|
implemented, and Activity records conversions. Binary attachment
|
||||||
|
capture/conversion remains future work.
|
||||||
- Packaging/update/release workflow is not product-grade yet.
|
- Packaging/update/release workflow is not product-grade yet.
|
||||||
|
|
||||||
## 4. Implementation Phases
|
## 4. Implementation Phases
|
||||||
|
|
@ -169,7 +170,8 @@ Tasks:
|
||||||
- [x] convert inbox entries into notes through public plugin APIs;
|
- [x] convert inbox entries into notes through public plugin APIs;
|
||||||
- [x] record converted inbox entries in Activity through public plugin events;
|
- [x] record converted inbox entries in Activity through public plugin events;
|
||||||
- [x] convert inbox entries into link files through public plugin APIs;
|
- [x] convert inbox entries into link files through public plugin APIs;
|
||||||
- convert captured file attachments through public
|
- [x] convert captured text file attachments through public plugin APIs;
|
||||||
|
- convert captured binary attachments through public
|
||||||
plugin APIs.
|
plugin APIs.
|
||||||
|
|
||||||
Verification:
|
Verification:
|
||||||
|
|
@ -240,7 +242,7 @@ Verification:
|
||||||
4. [x] Notes trash/delete UX in `verstak-official-plugins`.
|
4. [x] Notes trash/delete UX in `verstak-official-plugins`.
|
||||||
5. [x] Sync hardening pass with expanded real two-vault smoke.
|
5. [x] Sync hardening pass with expanded real two-vault smoke.
|
||||||
6. [~] Browser inbox protocol design, extension scaffold, local receiver, and
|
6. [~] Browser inbox protocol design, extension scaffold, local receiver, and
|
||||||
minimal inbox plugin are implemented; file attachment conversion remains.
|
minimal inbox plugin are implemented; binary attachment conversion remains.
|
||||||
|
|
||||||
This order finishes generic platform surfaces before building product features
|
This order finishes generic platform surfaces before building product features
|
||||||
that depend on them.
|
that depend on them.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,171 @@
|
||||||
|
# Browser Inbox Text File Attachment Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** Add end-to-end text file attachment capture and conversion through Browser Inbox.
|
||||||
|
|
||||||
|
**Architecture:** The browser extension remains a protocol producer and does not know workspace internals. Desktop receiver validates and republishes `browser.capture.file`; Browser Inbox stores the capture and writes the final text file through the public Files API.
|
||||||
|
|
||||||
|
**Tech Stack:** Plain JavaScript WebExtension code, Go receiver tests, official plugin JavaScript smoke harness, Markdown docs.
|
||||||
|
|
||||||
|
## Global Constraints
|
||||||
|
|
||||||
|
- Do not add private `.verstak/inbox` staging in this slice.
|
||||||
|
- Do not add binary file writes in this slice.
|
||||||
|
- Use only existing public plugin APIs for conversion: `api.files.writeText` and `api.events.publish`.
|
||||||
|
- Keep the extension offline queue behavior unchanged.
|
||||||
|
- Use TDD for each behavior change.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 1: Extension Text File Capture Protocol
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `/home/mirivlad/git/verstak2/verstak-browser-extension/shared/protocol.js`
|
||||||
|
- Modify: `/home/mirivlad/git/verstak2/verstak-browser-extension/shared/background.js`
|
||||||
|
- Modify: `/home/mirivlad/git/verstak2/verstak-browser-extension/shared/popup/popup.html`
|
||||||
|
- Modify: `/home/mirivlad/git/verstak2/verstak-browser-extension/shared/popup/popup.css`
|
||||||
|
- Modify: `/home/mirivlad/git/verstak2/verstak-browser-extension/shared/popup/popup.js`
|
||||||
|
- Modify: `/home/mirivlad/git/verstak2/verstak-browser-extension/scripts/test-protocol.js`
|
||||||
|
- Modify: `/home/mirivlad/git/verstak2/verstak-browser-extension/README.md`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Produces `kind: "file"` capture payloads with `file.name`, `file.mime`,
|
||||||
|
`file.size`, and `file.text`.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Write RED protocol assertions**
|
||||||
|
|
||||||
|
Add a test that builds a file capture and asserts `validateCapture` accepts it,
|
||||||
|
then add a validation rejection for missing `file.text`.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Run RED**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/mirivlad/git/verstak2/verstak-browser-extension
|
||||||
|
PATH=/tmp/verstak2-tools:/home/mirivlad/.lmstudio/.internal/utils:$PATH npm test
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: failure mentioning unsupported `kind` or missing file validation.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Implement protocol and popup capture**
|
||||||
|
|
||||||
|
Add `file` payload support in `buildCapture` / `validateCapture`. Add a popup
|
||||||
|
file input and `Send File` button that reads one selected file as text and sends
|
||||||
|
`{ type: "verstak.capture", kind: "file", fileName, fileMime, fileSize, fileText }`.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Run GREEN**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PATH=/tmp/verstak2-tools:/home/mirivlad/.lmstudio/.internal/utils:$PATH npm test
|
||||||
|
PATH=/tmp/verstak2-tools:/home/mirivlad/.lmstudio/.internal/utils:$PATH npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: protocol tests pass and extension dist builds.
|
||||||
|
|
||||||
|
### Task 2: Desktop Receiver File Event
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `/home/mirivlad/git/verstak2/verstak-desktop-current/internal/core/browserreceiver/receiver.go`
|
||||||
|
- Modify: `/home/mirivlad/git/verstak2/verstak-desktop-current/internal/core/browserreceiver/receiver_test.go`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes extension `kind: "file"` payloads.
|
||||||
|
- Produces `browser.capture.file` events with flattened `fileName`,
|
||||||
|
`fileMime`, `fileSize`, and `fileText`.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Write RED receiver test**
|
||||||
|
|
||||||
|
Add a test that subscribes to `browser.capture.file`, posts a file capture, and
|
||||||
|
asserts the flattened event payload.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Run RED**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/mirivlad/git/verstak2/verstak-desktop-current
|
||||||
|
go test ./internal/core/browserreceiver -run TestReceiverAcceptsFileCaptureAndPublishesEvent -count=1
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: failure with unsupported kind.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Implement receiver support**
|
||||||
|
|
||||||
|
Add a `CaptureFile` struct, `File *CaptureFile` field, file validation, and
|
||||||
|
file payload flattening in `EventPayload`.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Run GREEN**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go test ./internal/core/browserreceiver
|
||||||
|
./scripts/test.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: receiver package and desktop script pass.
|
||||||
|
|
||||||
|
### Task 3: Browser Inbox Create File Conversion
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `/home/mirivlad/git/verstak2/verstak-official-plugins/plugins/browser-inbox/frontend/src/index.js`
|
||||||
|
- Modify: `/home/mirivlad/git/verstak2/verstak-official-plugins/scripts/smoke-browser-inbox-plugin.js`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes `browser.capture.file` events.
|
||||||
|
- Produces `Create File` action and `browser.capture.converted` with
|
||||||
|
`conversionType: "file"`.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Write RED smoke test**
|
||||||
|
|
||||||
|
Add success and failure scenarios for a workspace file capture. Assert the write
|
||||||
|
path `Project/Files/notes.txt`, file content, write options, queue removal, and
|
||||||
|
converted event.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Run RED**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/mirivlad/git/verstak2/verstak-official-plugins
|
||||||
|
PATH=/tmp/verstak2-tools:/home/mirivlad/.lmstudio/.internal/utils:$PATH node scripts/smoke-browser-inbox-plugin.js
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: failure because `browser.capture.file` is not subscribed or
|
||||||
|
`Create File` is not rendered.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Implement conversion**
|
||||||
|
|
||||||
|
Preserve `fileName`, `fileMime`, `fileSize`, and `fileText` in storage. Render a
|
||||||
|
`Create File` button for workspace file captures with text content. Write the
|
||||||
|
safe file path through `api.files.writeText`, publish the converted event, and
|
||||||
|
remove the capture on success.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Run GREEN**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PATH=/tmp/verstak2-tools:/home/mirivlad/.lmstudio/.internal/utils:$PATH node scripts/smoke-browser-inbox-plugin.js
|
||||||
|
PATH=/tmp/verstak2-tools/venv/bin:/tmp/verstak2-tools:/home/mirivlad/.lmstudio/.internal/utils:$PATH ./scripts/check.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: browser inbox smoke and official plugin check pass.
|
||||||
|
|
||||||
|
### Task 4: Roadmap Documentation
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `/home/mirivlad/git/verstak2/verstak-docs/05_Official_Plugins.md`
|
||||||
|
- Modify: `/home/mirivlad/git/verstak2/verstak-docs/07_Full_Implementation_Roadmap.md`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes verified file capture/conversion behavior.
|
||||||
|
- Produces roadmap language that marks text file attachment conversion complete
|
||||||
|
while leaving binary attachments for a future public API slice.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Update docs**
|
||||||
|
|
||||||
|
Describe Browser Inbox text file capture and conversion through the public Files
|
||||||
|
API.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Verify docs**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/mirivlad/git/verstak2/verstak-docs
|
||||||
|
git diff --check
|
||||||
|
rg -n "text file attachment|binary attachment|browser.capture.file|Create File" 05_Official_Plugins.md 07_Full_Implementation_Roadmap.md docs/superpowers/specs/2026-06-29-browser-inbox-text-file-attachment-design.md docs/superpowers/plans/2026-06-29-browser-inbox-text-file-attachment.md
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: whitespace check exits 0 and `rg` shows updated status lines.
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
# Browser Inbox Text File Attachment Design
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Browser Inbox needs a first file attachment path that uses the current public
|
||||||
|
plugin API instead of adding a private core inbox or binary write shortcut. This
|
||||||
|
slice supports text file attachments end to end: the browser extension reads a
|
||||||
|
user-selected text file, the local receiver publishes a `browser.capture.file`
|
||||||
|
event, and Browser Inbox converts the capture into an ordinary workspace file
|
||||||
|
through `api.files.writeText`.
|
||||||
|
|
||||||
|
Binary attachments remain out of scope until the platform has an explicit
|
||||||
|
public binary write API.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This slice adds:
|
||||||
|
|
||||||
|
- extension protocol support for `kind: "file"`;
|
||||||
|
- popup file selection for text files;
|
||||||
|
- local receiver validation and event publication for file captures;
|
||||||
|
- Browser Inbox storage/rendering of file metadata and text content;
|
||||||
|
- a `Create File` conversion action for workspace-scoped text file captures.
|
||||||
|
|
||||||
|
It does not add drag-and-drop from web pages, screenshot capture, native download
|
||||||
|
interception, binary files, folders, or a core `.verstak/inbox` staging area.
|
||||||
|
|
||||||
|
## Capture Contract
|
||||||
|
|
||||||
|
The extension sends schema version 1 with a new file object:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"captureId": "generated-id",
|
||||||
|
"capturedAt": "2026-06-29T00:00:00.000Z",
|
||||||
|
"source": "verstak-browser-extension",
|
||||||
|
"kind": "file",
|
||||||
|
"page": {
|
||||||
|
"url": "https://example.com/current-page",
|
||||||
|
"title": "Current page",
|
||||||
|
"domain": "example.com"
|
||||||
|
},
|
||||||
|
"file": {
|
||||||
|
"name": "notes.txt",
|
||||||
|
"mime": "text/plain",
|
||||||
|
"size": 120,
|
||||||
|
"text": "file contents"
|
||||||
|
},
|
||||||
|
"browser": {
|
||||||
|
"name": "Firefox"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`file.name` and `file.text` are required for `kind: "file"`. The extension
|
||||||
|
limits text content to 2 MB so it stays within the current Files API text-read
|
||||||
|
size and avoids turning local receiver events into large binary transport.
|
||||||
|
|
||||||
|
## Receiver Event
|
||||||
|
|
||||||
|
The desktop receiver accepts `kind: "file"` and publishes
|
||||||
|
`browser.capture.file`. The event payload flattens file fields for Browser Inbox:
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
captureId,
|
||||||
|
capturedAt,
|
||||||
|
source,
|
||||||
|
kind: 'file',
|
||||||
|
url,
|
||||||
|
title,
|
||||||
|
domain,
|
||||||
|
fileName,
|
||||||
|
fileMime,
|
||||||
|
fileSize,
|
||||||
|
fileText,
|
||||||
|
browserName
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Current workspace annotation continues to work the same as page, selection, and
|
||||||
|
link captures.
|
||||||
|
|
||||||
|
## Browser Inbox Conversion
|
||||||
|
|
||||||
|
Browser Inbox subscribes to `browser.capture.file` and stores file fields in its
|
||||||
|
plugin-owned queue. In a workspace view, file captures render a `Create File`
|
||||||
|
action.
|
||||||
|
|
||||||
|
On success:
|
||||||
|
|
||||||
|
- write `<workspaceRootPath>/Files/<safe-file-name>` through
|
||||||
|
`api.files.writeText`;
|
||||||
|
- use `{ createIfMissing: true, overwrite: false }`;
|
||||||
|
- publish `browser.capture.converted` with `conversionType: "file"` and
|
||||||
|
`filePath`;
|
||||||
|
- remove the capture from the queue.
|
||||||
|
|
||||||
|
On write failure, Browser Inbox leaves the capture in the queue and renders an
|
||||||
|
error status.
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
Required checks:
|
||||||
|
|
||||||
|
- browser extension protocol test builds and validates `kind: "file"`;
|
||||||
|
- receiver unit test accepts a file capture and publishes
|
||||||
|
`browser.capture.file`;
|
||||||
|
- Browser Inbox smoke test verifies `Create File` write path, content, write
|
||||||
|
options, queue removal, converted event, and failure behavior;
|
||||||
|
- full repo checks continue to pass for touched repositories.
|
||||||
Loading…
Reference in New Issue