taskops-cli 0.5.8__tar.gz → 0.6.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ARCHITECTURE.md +101 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/CHANGELOG.md +66 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/CLAUDE.md +6 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/PKG-INFO +1 -1
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/_version.py +1 -1
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/store/cache.py +13 -2
- taskops_cli-0.6.1/src/taskops/ui/app.js +70 -0
- taskops_cli-0.6.1/src/taskops/verbs/events.py +89 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/tests/test_verbs.py +58 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/editor-page.tsx +10 -0
- taskops_cli-0.6.1/ui/smoke/sections/stream-rail.tsx +378 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/App.tsx +28 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/card/Thread.tsx +44 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/monitor/EventStream.tsx +7 -30
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/monitor/panels.ts +19 -0
- taskops_cli-0.6.1/ui/src/components/stream/Grip.tsx +101 -0
- taskops_cli-0.6.1/ui/src/components/stream/Stream.tsx +522 -0
- taskops_cli-0.6.1/ui/src/components/stream/model.ts +425 -0
- taskops_cli-0.6.1/ui/src/components/stream/useStream.ts +121 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/toasts/model.ts +14 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/pages/Editor.tsx +117 -2
- taskops_cli-0.6.1/ui/src/useEvents.ts +349 -0
- taskops_cli-0.5.8/src/taskops/ui/app.js +0 -70
- taskops_cli-0.5.8/src/taskops/verbs/events.py +0 -60
- taskops_cli-0.5.8/ui/src/useEvents.ts +0 -160
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/.claude/settings.json +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/.gitattributes +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/.github/workflows/ci.yml +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/.github/workflows/workflow.yml +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/.gitignore +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/.mcp.json +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/.taskops/board/cache.sqlite +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/.taskops/board/cache.sqlite-shm +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/.taskops/board/cache.sqlite-wal +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/.taskops/board/events.jsonl +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/.taskops/board/live.sqlite +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/.taskops/board/live.sqlite-shm +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/.taskops/board/live.sqlite-wal +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/.taskops/board.json +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/.taskops/reports/lifecycle-chapter.html +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/.taskops/reports/reports-chapter.html +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/.taskops/ui.lock +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/README.md +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/pyproject.toml +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/smoke.sh +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/__init__.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/_clock.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/_errors.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/_ids.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/_json.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/_locate.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/_wire.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/board.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/__init__.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/__main__.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/admin.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/claude.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/commands.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/enrol.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/github.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/gitremote.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/grants.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/hooks.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/main.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/operate.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/paging.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/parser.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/pull.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/push.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/remote.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/rm.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/serving.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/team.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/watch.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/window.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/cli/wording.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/core/__init__.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/core/actors.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/core/challenge.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/core/chapters.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/core/event.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/core/forge.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/core/graph.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/core/holding.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/core/hours.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/core/kinds.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/core/machine.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/core/mentions.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/core/replay.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/core/reports.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/core/review.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/core/scope.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/core/seams.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/core/types.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/gitwork/__init__.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/gitwork/bare.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/gitwork/bind.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/gitwork/catchup.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/gitwork/claudefiles.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/gitwork/diff.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/gitwork/inhabited.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/gitwork/install.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/gitwork/landing.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/gitwork/onward.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/gitwork/patch.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/gitwork/reading.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/gitwork/remote.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/gitwork/run.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/gitwork/scan.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/gitwork/sig.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/gitwork/trailer.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/gitwork/trees.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/__init__.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/admin.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/auth.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/editor.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/feed.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/gitbody.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/gitdoor.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/gitpack.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/grants.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/handler.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/health.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/ingest.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/listing.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/login.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/members.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/mounts.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/page.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/removal.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/repos.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/routes.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/rpc.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/scoped.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/server.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/stale.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/static.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/treewatch.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/upstream.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/http/watcher.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/identity.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/mcp/__init__.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/mcp/__main__.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/mcp/activity.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/mcp/before.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/mcp/boards.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/mcp/boardview.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/mcp/brief.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/mcp/chapter.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/mcp/dossier.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/mcp/fields.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/mcp/gitmoves.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/mcp/hello.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/mcp/integrate.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/mcp/orders.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/mcp/render.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/mcp/schema.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/mcp/server.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/mcp/thread.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/mcp/tools.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/py.typed +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/session.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/store/__init__.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/store/creds.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/store/handover.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/store/live.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/store/log.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/store/mirroring.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/store/pubkeys.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/store/reviews.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/store/server.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/store/stores.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/ui/index.html +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/ui/style.css +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/__init__.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/_args.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/_cards.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/_chapter.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/_context.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/_facts.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/_mentions.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/_rows.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/_stories.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/_waiting.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/_windows.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/activity.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/assign.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/card.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/filed.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/plan.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/project.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/pulse.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/record.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/report.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/review.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/take.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/src/taskops/verbs/update.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/tests/__init__.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/tests/conftest.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/tests/test_architecture.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/tests/test_claude.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/tests/test_core.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/tests/test_editor.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/tests/test_git.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/tests/test_mcp.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/tests/test_mirror.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/tests/test_report.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/tests/test_store.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/tests/test_topology.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/tests/test_ui.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/tests/test_window.py +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/tests/ui_harness.js +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/build.mjs +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/index.html +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/package-lock.json +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/package.json +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/fixture.json +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/main.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/run.mjs +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/actors-window-filter.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/actors.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/all-chapters-scope.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/board-columns.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/board-flip-abandoned-play.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/board-flow-view.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/board-motion-and-avatars.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/board-root-mount.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/card-diff-range.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/card-progress.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/chapter-completion-derivation.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/chapter-landed.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/chapter-story-grid.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/chapters-open.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/comment-box.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/comment-toasts-model.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/comment-toasts-stack.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/daysheet-midnight-spill.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/diff-page.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/dossier.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/event-stream.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/feed-reconnect.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/forge-links.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/forge-opens-the-board.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/git-diff.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/hosted-window.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/monitor-panes.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/overlay-escape.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/report-markdown.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/report-sandbox.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/reviewing-skew.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/section.ts +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/swarm-topology.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/thread-closing-note.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/worktree-page-range.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections/worktrees-index.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/smoke/sections.mjs +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/client.ts +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/completed.ts +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/actors/Daysheet.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/actors/DevPanel.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/board/CardTile.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/board/Column.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/board/ViewToggle.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/board/flip.ts +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/board/useFlip.ts +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/card/CommentBox.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/card/Drawer.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/card/Patch.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/card/Sections.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/card/split.ts +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/card/tokens.ts +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/chrome/AvatarStack.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/chrome/Header.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/chrome/KpiRail.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/chrome/MilestonePicker.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/chrome/TabNav.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/editor/CodeView.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/editor/FileTree.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/editor/Icon.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/editor/QuickOpen.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/editor/Tabs.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/editor/fuzzy.ts +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/editor/highlight.ts +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/editor/icons.ts +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/editor/tree.ts +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/editor/useWorktree.ts +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/flow/FlowView.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/flow/layout.ts +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/monitor/Chapter.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/monitor/DependencyChain.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/monitor/EditSurface.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/monitor/LeaseHealth.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/monitor/LiveLeases.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/monitor/Mentions.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/monitor/Pane.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/monitor/Swarm.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/monitor/Throughput.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/reports/ReportFrame.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/shared/Avatar.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/shared/Markdown.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/shared/Overlay.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/shared/Segmented.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/shared/overlayStack.ts +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/story/ChapterStory.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/story/stats.ts +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/toasts/ToastStack.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/components/toasts/useToasts.ts +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/format.ts +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/hoursWindow.ts +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/links.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/main.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/markdown.ts +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/pages/Actors.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/pages/Board.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/pages/Monitor.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/pages/Reports.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/pages/WorktreeDiff.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/pages/Worktrees.tsx +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/theme/theme.ts +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/theme/tokens.css +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/types.ts +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/src/useBoard.ts +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/styles/index.css +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/ui/tsconfig.json +0 -0
- {taskops_cli-0.5.8 → taskops_cli-0.6.1}/uv.lock +0 -0
|
@@ -3112,3 +3112,104 @@ or highlight.js with the eleven grammars): keyword, string, comment, number,
|
|
|
3112
3112
|
tag, attribute — enough to read by, in six `--code-*` tokens that live in
|
|
3113
3113
|
`theme/tokens.css` beside the palette rather than borrowing its status colours.
|
|
3114
3114
|
The bundle grew 288 307 → 313 294 bytes for the whole feature.
|
|
3115
|
+
|
|
3116
|
+
## 23. The Stream — the log beside the code, live (2026-09-08)
|
|
3117
|
+
|
|
3118
|
+
Berna asked for "un streaming de comentarios en tiempo real … cada progress,
|
|
3119
|
+
cada comment, se muestra, se highlitean los nuevos, se puede ver el card tipo
|
|
3120
|
+
popup … al lado del editor … con una excelente organización y agrupación". It
|
|
3121
|
+
is a third column inside the Editor (`ui/src/components/stream/`), shut by
|
|
3122
|
+
default, opened from the one bar that page has.
|
|
3123
|
+
|
|
3124
|
+
**The socket did not change, and that is the whole design.** `http/feed.py`
|
|
3125
|
+
publishes `{"type":"change","verb","seq"}` and nothing else, because that is
|
|
3126
|
+
what lets a PUBLIC board's feed open with no credential: a watcher learns only
|
|
3127
|
+
THAT the board moved and re-reads through `/rpc`, where the anonymous gate
|
|
3128
|
+
applies again in full. A live comment column is exactly the feature that would
|
|
3129
|
+
have tempted a payload onto that frame, and the day a message carries a card
|
|
3130
|
+
that door has to close with it. So: the socket pokes, the page reads.
|
|
3131
|
+
|
|
3132
|
+
**What DID change is the direction the log can be read in.** `events` used to
|
|
3133
|
+
answer backwards only — newest-first pages on a `before=` cursor — so "what
|
|
3134
|
+
arrived since I looked" was a thing the client had to DERIVE: `head - lastHead`
|
|
3135
|
+
rows off page one, plus a set of already-seen ids as the safety net for a burst
|
|
3136
|
+
larger than a page (`ui/src/components/toasts/model.ts` is the post-mortem of
|
|
3137
|
+
that arithmetic, and it is exact only until it is not).
|
|
3138
|
+
|
|
3139
|
+
```
|
|
3140
|
+
events → the newest page next = the older cursor
|
|
3141
|
+
events before=<seq> → further back next = the older cursor
|
|
3142
|
+
events after=<seq> → what arrived since, next = carry on from here
|
|
3143
|
+
OLDEST first (a full page means more)
|
|
3144
|
+
```
|
|
3145
|
+
|
|
3146
|
+
`next` means the same thing in both directions — the cursor for the page you
|
|
3147
|
+
have not read yet, in the direction you are reading — and the two cannot be
|
|
3148
|
+
asked at once, which is two questions and is refused as one. The SQL is
|
|
3149
|
+
`store/cache.py::since`, which replay already used, given a `limit`: a
|
|
3150
|
+
catch-up is capped on the OLDEST end, which is the one thing a descending
|
|
3151
|
+
`page()` cannot do.
|
|
3152
|
+
|
|
3153
|
+
**The cursor a live reader carries is `head`, not a seq per row.** The rowid is
|
|
3154
|
+
still dropped on the way out (`verbs/events.py:53` was and remains the shape).
|
|
3155
|
+
A reader keeps the `head` of the answer it read and asks `after=<that head>`;
|
|
3156
|
+
what comes back IS the news, by construction — no arithmetic, no dedupe, and no
|
|
3157
|
+
way to be wrong when six hundred events landed while the tab was asleep, because
|
|
3158
|
+
then it pages forward on `next` and, past `CATCH_UP_PAGES`, starts over on page
|
|
3159
|
+
one rather than drawing a list with a hole in the middle.
|
|
3160
|
+
|
|
3161
|
+
**Still ONE read of the log.** `useEvents` is called in `App`, once, and three
|
|
3162
|
+
surfaces are handed the result — the Monitor's Event stream, the comment toasts,
|
|
3163
|
+
and this rail. The change is that it CATCHES UP instead of starting over: new
|
|
3164
|
+
rows are prepended, the reader's scrollback survives, and a quiet board answers
|
|
3165
|
+
with an empty list instead of fifty rows on every poke.
|
|
3166
|
+
|
|
3167
|
+
**What arrived is stamped in the CLIENT's clock**, never in `Event.ts`. A
|
|
3168
|
+
comment written three minutes ago that reaches this tab now is new HERE, and a
|
|
3169
|
+
rail that highlighted by `ts` would show it already faded — `toasts/model.ts::
|
|
3170
|
+
Toast.shown` decided the same thing first, for the same reason. The stamps are
|
|
3171
|
+
pruned to a minute, so the map is bounded by what arrived, not by how long the
|
|
3172
|
+
tab has been open. Nothing is stored: there are no read-receipts on this board
|
|
3173
|
+
and there is no mark-as-read verb, by design (§11), so "new" is arithmetic that
|
|
3174
|
+
dies with the tab.
|
|
3175
|
+
|
|
3176
|
+
**The organisation is a MOMENT, not a row.** The Monitor's pane draws one row
|
|
3177
|
+
per event and is right to: it answers "what happened, in order, ever". A 320px
|
|
3178
|
+
column beside the code answers "what are the workers doing right now", and at
|
|
3179
|
+
that question one row per event is noise — a `taskops_plan` of nine cards is
|
|
3180
|
+
nine identical rows. So consecutive events by the same actor on the same card
|
|
3181
|
+
within `MOMENT_GAP_S` (120s) fold into one entry, counted, sized and ended with
|
|
3182
|
+
the worker's own number: `2 commits · 2 files · +41 −7 · progress → 68`. The
|
|
3183
|
+
fold is on (actor, task) because a worker moving between cards is the change a
|
|
3184
|
+
reader wants to see, and it is CONSECUTIVE-only, so an entry can never be
|
|
3185
|
+
hoisted above events that happened after it. Files are counted per PATH across
|
|
3186
|
+
the run — one file touched in three commits is one file — through
|
|
3187
|
+
`Thread.tsx::changed`, which is the Event stream's own numstat fold given a
|
|
3188
|
+
list; a second definition of "how much changed" is the drift `format.ts` is the
|
|
3189
|
+
post-mortem of.
|
|
3190
|
+
|
|
3191
|
+
**Three ways to narrow, none of them a fetch:** five families (`talk` `work`
|
|
3192
|
+
`code` `review` `chapter`, every kind in `core/kinds.py` in exactly one), one
|
|
3193
|
+
card followed by clicking its id, and `older` for history. `progress` needs no
|
|
3194
|
+
branch anywhere — it is an `edited` event (`verbs/update.py::_progress` argues
|
|
3195
|
+
why it is not a kind of its own) and the roll-up reads it off the body.
|
|
3196
|
+
|
|
3197
|
+
**The reader's place is never taken.** New entries land on top; a reader who has
|
|
3198
|
+
scrolled down into history does not have the list move under them, and a pill
|
|
3199
|
+
says how many are waiting above. The card popup is `openCard` — App's one door
|
|
3200
|
+
into the Drawer, which is mounted once over whichever page is on — so the rail
|
|
3201
|
+
draws no dossier of its own and the same card opens identically from the Board,
|
|
3202
|
+
the Monitor and here.
|
|
3203
|
+
|
|
3204
|
+
**What the headless harness does and does not pin**
|
|
3205
|
+
(`ui/smoke/sections/stream-rail.tsx`): the fold, the roll-up, the numstat, the
|
|
3206
|
+
freshness tiers, the merge, the arrival stamps, the narrowing, the entry markup,
|
|
3207
|
+
the three empty states and the Editor's third column — all pure functions or
|
|
3208
|
+
`Stream`, which renders under `react-dom/server` with no client, no socket and
|
|
3209
|
+
no timer. Not pinned, and said rather than faked with a jsdom: the scroll
|
|
3210
|
+
position, the one interval, and the catch-up walk. The `after=` half is pinned
|
|
3211
|
+
on the server, where it is decided (`tests/test_verbs.py`), including the
|
|
3212
|
+
burst-larger-than-a-page case the client arithmetic could not survive.
|
|
3213
|
+
|
|
3214
|
+
The bundle grew 330 231 → 341 411 bytes for the whole feature: the model, the
|
|
3215
|
+
rail and the Editor's third column, no dependency added.
|
|
@@ -3,6 +3,72 @@
|
|
|
3
3
|
The source of truth for release notes — GitHub Releases are extracted from
|
|
4
4
|
here, never written twice.
|
|
5
5
|
|
|
6
|
+
## 0.6.1 — the Stream earns its column
|
|
7
|
+
|
|
8
|
+
- **Open the files the agents name.** Every entry now wears the paths it
|
|
9
|
+
named, and a click opens that file in the editor beside it — switching to
|
|
10
|
+
the card's own worktree when it has one on this disk. Three sources, in
|
|
11
|
+
descending order of trust: a commit's `numstat` keys (git's own answer), a
|
|
12
|
+
created card's declared `files`, and what the prose names.
|
|
13
|
+
- **The prose half is a guess and is kept one.** Agents write paths to each
|
|
14
|
+
other constantly — "the fix site is `verbs/_facts.py::pending_mentions`" —
|
|
15
|
+
and no structured field carries them. So they are extracted, narrowly:
|
|
16
|
+
backticked or bare, a trailing `::symbol` / `:line` / `:line:col` stripped
|
|
17
|
+
because `events.py:53` names a file and not a file with that name, never a
|
|
18
|
+
URL, never a bare directory, capped. A false negative costs a click; a false
|
|
19
|
+
positive is the rail lying about the disk.
|
|
20
|
+
- **Markdown**, the drawer's own renderer over the same parser, so a fence, a
|
|
21
|
+
list and a `path` read here exactly as they read there. The 96-character cut
|
|
22
|
+
is gone: it landed inside a fence as often as not, and what the reader saw
|
|
23
|
+
was not a shortened comment but a broken one. The clamp is now a HEIGHT,
|
|
24
|
+
undone by expanding the entry — and expansion is a set, not a flag, because
|
|
25
|
+
a reader opens two comments to compare them as often as one.
|
|
26
|
+
- **The rail resizes by hand**: a grip on its edge, 240–760px, double-click to
|
|
27
|
+
reset, and the width is remembered across leaving the tab. The listeners are
|
|
28
|
+
on the document and not the handle — bound to a 6px strip they are lost the
|
|
29
|
+
first time the pointer outruns the render.
|
|
30
|
+
- `useStream` is the container half, extracted so a second mount of the same
|
|
31
|
+
picture cannot come to disagree about what is new or which family is on.
|
|
32
|
+
- Four mutations, one site at a time. Two assertions were born FALSE and found
|
|
33
|
+
by running them: a path cleaner that did not strip backticks, and a "draws
|
|
34
|
+
no chips" claim asserted against a mount that HAD an editor.
|
|
35
|
+
- The bundle grew 341 411 → 345 368 bytes.
|
|
36
|
+
|
|
37
|
+
## 0.6.0 — the Stream, beside the code
|
|
38
|
+
|
|
39
|
+
- **A live rail inside the Editor**: every comment, every commit, every
|
|
40
|
+
`progress` a worker reports, as it happens, in a third column you open from
|
|
41
|
+
the page's one bar. Shut by default — the Editor's whole decision is that the
|
|
42
|
+
code gets the window, and a live column appearing unasked would be that
|
|
43
|
+
decision taken back on the reader's behalf.
|
|
44
|
+
- **The socket did not change.** A frame is still `{"type":"change","verb","seq"}`
|
|
45
|
+
and nothing else, which is what lets a public board's feed open with no
|
|
46
|
+
credential. The socket pokes; the page reads.
|
|
47
|
+
- **`events` can be read forwards**: `after=<seq>` answers exactly the rows
|
|
48
|
+
written since the cursor a reader already holds, oldest first, and pages
|
|
49
|
+
forward on `next` when the catch-up is bigger than one page. The cursor is
|
|
50
|
+
`head` — the rowid is still not sent per row. What that replaces is the
|
|
51
|
+
arithmetic the client had to do over page one (`head - lastHead` rows plus a
|
|
52
|
+
seen-set), which was exact only until a burst was larger than a page.
|
|
53
|
+
- **The one log read catches up instead of starting over.** New rows are
|
|
54
|
+
prepended, so a reader's scrollback survives a board that is moving, and a
|
|
55
|
+
quiet board answers with an empty list instead of fifty rows on every poke.
|
|
56
|
+
Three surfaces still share one read: the Monitor's pane, the toasts, the rail.
|
|
57
|
+
- **A run of work is one entry.** Consecutive events by one worker on one card
|
|
58
|
+
within two minutes fold together, counted and sized:
|
|
59
|
+
`2 commits · 2 files · +41 −7 · progress → 68`. Nine rows from one
|
|
60
|
+
`taskops_plan` were the shape this exists to stop drawing.
|
|
61
|
+
- **What arrived is marked and fades by arithmetic** — stamped in the reader's
|
|
62
|
+
own clock, never the event's, so a comment that reaches the tab late is new
|
|
63
|
+
HERE. Nothing is stored: no badge, no counter, no read-receipt.
|
|
64
|
+
- **The reader's place is never taken**: entries land on top, a reader scrolled
|
|
65
|
+
into history is not moved, and a pill says how many are waiting above.
|
|
66
|
+
- Filter by family (talk · work · code · review · chapter), follow one card by
|
|
67
|
+
clicking its id, open its dossier in the popup every other view uses.
|
|
68
|
+
- Five mutations, one site at a time, and one of them found a fixture that was
|
|
69
|
+
not exercising the rule it claimed to pin.
|
|
70
|
+
- The bundle grew 330 231 → 341 411 bytes. No dependency added.
|
|
71
|
+
|
|
6
72
|
## 0.5.8 — the Editor is the whole window
|
|
7
73
|
|
|
8
74
|
- **Nothing is drawn above the Editor any more** — no KPI rail, no header, no
|
|
@@ -270,6 +270,12 @@ what it exists to report, not a fault.
|
|
|
270
270
|
cannot conflict.
|
|
271
271
|
- **Do not run browser/UI demos unless asked.** The UI is tested headlessly
|
|
272
272
|
through `react-dom/server`, no browser and no jsdom.
|
|
273
|
+
- **The Editor carries the Stream rail** — the log, live, in a third column,
|
|
274
|
+
shut by default (ARCHITECTURE §23). It fetches NOTHING: `useEvents` is read
|
|
275
|
+
once in `App` and three surfaces share it, and the socket frame is still a
|
|
276
|
+
signal, never a payload. A run of events by one worker on one card inside two
|
|
277
|
+
minutes is ONE entry; "new" is stamped in the reader's clock and fades by
|
|
278
|
+
arithmetic, because there is no mark-as-read verb and never will be.
|
|
273
279
|
- One card rebuilds the bundle at the end of a wave. N cards rebuilding it is
|
|
274
280
|
N-1 conflicts by construction.
|
|
275
281
|
|
|
@@ -93,8 +93,19 @@ class Cache:
|
|
|
93
93
|
rows = self._query("SELECT kind, COUNT(*) FROM events GROUP BY kind")
|
|
94
94
|
return {str(kind): int(n) for kind, n in rows}
|
|
95
95
|
|
|
96
|
-
def since(self, seq: int) -> list[tuple[int, Event]]:
|
|
97
|
-
|
|
96
|
+
def since(self, seq: int, limit: int | None = None) -> list[tuple[int, Event]]:
|
|
97
|
+
"""Everything after `seq`, OLDEST first — replay's order, and the order
|
|
98
|
+
a live reader catches up in.
|
|
99
|
+
|
|
100
|
+
`limit` is for the second caller only (`verbs/events.py`'s `after=`): a
|
|
101
|
+
page of a CATCH-UP is read forwards, so the cap has to fall on the
|
|
102
|
+
oldest end and not on the newest, which is the one thing a descending
|
|
103
|
+
`page()` cannot do. Replay passes nothing and reads the tail whole —
|
|
104
|
+
that is what makes a cache rebuildable.
|
|
105
|
+
"""
|
|
106
|
+
if limit is None:
|
|
107
|
+
return self._events("WHERE seq > ? ORDER BY seq", (seq,))
|
|
108
|
+
return self._events("WHERE seq > ? ORDER BY seq LIMIT ?", (seq, limit))
|
|
98
109
|
|
|
99
110
|
def page(self, before: int | None, limit: int) -> list[tuple[int, Event]]:
|
|
100
111
|
"""One page of the whole log, NEWEST FIRST, by keyset on `seq`.
|