mirror of
https://github.com/jhbruhn/respira.git
synced 2026-01-27 10:23:41 +00:00
Compare commits
No commits in common. "main" and "v0.11.0" have entirely different histories.
13 changed files with 38 additions and 345 deletions
39
.beads/.gitignore
vendored
39
.beads/.gitignore
vendored
|
|
@ -1,39 +0,0 @@
|
|||
# SQLite databases
|
||||
*.db
|
||||
*.db?*
|
||||
*.db-journal
|
||||
*.db-wal
|
||||
*.db-shm
|
||||
|
||||
# Daemon runtime files
|
||||
daemon.lock
|
||||
daemon.log
|
||||
daemon.pid
|
||||
bd.sock
|
||||
sync-state.json
|
||||
last-touched
|
||||
|
||||
# Local version tracking (prevents upgrade notification spam after git ops)
|
||||
.local_version
|
||||
|
||||
# Legacy database files
|
||||
db.sqlite
|
||||
bd.db
|
||||
|
||||
# Worktree redirect file (contains relative path to main repo's .beads/)
|
||||
# Must not be committed as paths would be wrong in other clones
|
||||
redirect
|
||||
|
||||
# Merge artifacts (temporary files from 3-way merge)
|
||||
beads.base.jsonl
|
||||
beads.base.meta.json
|
||||
beads.left.jsonl
|
||||
beads.left.meta.json
|
||||
beads.right.jsonl
|
||||
beads.right.meta.json
|
||||
|
||||
# NOTE: Do NOT add negation patterns (e.g., !issues.jsonl) here.
|
||||
# They would override fork protection in .git/info/exclude, allowing
|
||||
# contributors to accidentally commit upstream issue databases.
|
||||
# The JSONL files (issues.jsonl, interactions.jsonl) and config files
|
||||
# are tracked by git by default since no pattern above ignores them.
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
# Beads - AI-Native Issue Tracking
|
||||
|
||||
Welcome to Beads! This repository uses **Beads** for issue tracking - a modern, AI-native tool designed to live directly in your codebase alongside your code.
|
||||
|
||||
## What is Beads?
|
||||
|
||||
Beads is issue tracking that lives in your repo, making it perfect for AI coding agents and developers who want their issues close to their code. No web UI required - everything works through the CLI and integrates seamlessly with git.
|
||||
|
||||
**Learn more:** [github.com/steveyegge/beads](https://github.com/steveyegge/beads)
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Essential Commands
|
||||
|
||||
```bash
|
||||
# Create new issues
|
||||
bd create "Add user authentication"
|
||||
|
||||
# View all issues
|
||||
bd list
|
||||
|
||||
# View issue details
|
||||
bd show <issue-id>
|
||||
|
||||
# Update issue status
|
||||
bd update <issue-id> --status in_progress
|
||||
bd update <issue-id> --status done
|
||||
|
||||
# Sync with git remote
|
||||
bd sync
|
||||
```
|
||||
|
||||
### Working with Issues
|
||||
|
||||
Issues in Beads are:
|
||||
- **Git-native**: Stored in `.beads/issues.jsonl` and synced like code
|
||||
- **AI-friendly**: CLI-first design works perfectly with AI coding agents
|
||||
- **Branch-aware**: Issues can follow your branch workflow
|
||||
- **Always in sync**: Auto-syncs with your commits
|
||||
|
||||
## Why Beads?
|
||||
|
||||
✨ **AI-Native Design**
|
||||
- Built specifically for AI-assisted development workflows
|
||||
- CLI-first interface works seamlessly with AI coding agents
|
||||
- No context switching to web UIs
|
||||
|
||||
🚀 **Developer Focused**
|
||||
- Issues live in your repo, right next to your code
|
||||
- Works offline, syncs when you push
|
||||
- Fast, lightweight, and stays out of your way
|
||||
|
||||
🔧 **Git Integration**
|
||||
- Automatic sync with git commits
|
||||
- Branch-aware issue tracking
|
||||
- Intelligent JSONL merge resolution
|
||||
|
||||
## Get Started with Beads
|
||||
|
||||
Try Beads in your own projects:
|
||||
|
||||
```bash
|
||||
# Install Beads
|
||||
curl -sSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash
|
||||
|
||||
# Initialize in your repo
|
||||
bd init
|
||||
|
||||
# Create your first issue
|
||||
bd create "Try out Beads"
|
||||
```
|
||||
|
||||
## Learn More
|
||||
|
||||
- **Documentation**: [github.com/steveyegge/beads/docs](https://github.com/steveyegge/beads/tree/main/docs)
|
||||
- **Quick Start Guide**: Run `bd quickstart`
|
||||
- **Examples**: [github.com/steveyegge/beads/examples](https://github.com/steveyegge/beads/tree/main/examples)
|
||||
|
||||
---
|
||||
|
||||
*Beads: Issue tracking that moves at the speed of thought* ⚡
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
# Beads Configuration File
|
||||
# This file configures default behavior for all bd commands in this repository
|
||||
# All settings can also be set via environment variables (BD_* prefix)
|
||||
# or overridden with command-line flags
|
||||
|
||||
# Issue prefix for this repository (used by bd init)
|
||||
# If not set, bd init will auto-detect from directory name
|
||||
# Example: issue-prefix: "myproject" creates issues like "myproject-1", "myproject-2", etc.
|
||||
# issue-prefix: ""
|
||||
|
||||
# Use no-db mode: load from JSONL, no SQLite, write back after each command
|
||||
# When true, bd will use .beads/issues.jsonl as the source of truth
|
||||
# instead of SQLite database
|
||||
# no-db: false
|
||||
|
||||
# Disable daemon for RPC communication (forces direct database access)
|
||||
# no-daemon: false
|
||||
|
||||
# Disable auto-flush of database to JSONL after mutations
|
||||
# no-auto-flush: false
|
||||
|
||||
# Disable auto-import from JSONL when it's newer than database
|
||||
# no-auto-import: false
|
||||
|
||||
# Enable JSON output by default
|
||||
# json: false
|
||||
|
||||
# Default actor for audit trails (overridden by BD_ACTOR or --actor)
|
||||
# actor: ""
|
||||
|
||||
# Path to database (overridden by BEADS_DB or --db)
|
||||
# db: ""
|
||||
|
||||
# Auto-start daemon if not running (can also use BEADS_AUTO_START_DAEMON)
|
||||
# auto-start-daemon: true
|
||||
|
||||
# Debounce interval for auto-flush (can also use BEADS_FLUSH_DEBOUNCE)
|
||||
# flush-debounce: "5s"
|
||||
|
||||
# Git branch for beads commits (bd sync will commit to this branch)
|
||||
# IMPORTANT: Set this for team projects so all clones use the same sync branch.
|
||||
# This setting persists across clones (unlike database config which is gitignored).
|
||||
# Can also use BEADS_SYNC_BRANCH env var for local override.
|
||||
# If not set, bd sync will require you to run 'bd config set sync.branch <branch>'.
|
||||
sync-branch: "beads-sync"
|
||||
|
||||
# Multi-repo configuration (experimental - bd-307)
|
||||
# Allows hydrating from multiple repositories and routing writes to the correct JSONL
|
||||
# repos:
|
||||
# primary: "." # Primary repo (where this database lives)
|
||||
# additional: # Additional repos to hydrate from (read-only)
|
||||
# - ~/beads-planning # Personal planning repo
|
||||
# - ~/work-planning # Work planning repo
|
||||
|
||||
# Integration settings (access with 'bd config get/set')
|
||||
# These are stored in the database, not in this file:
|
||||
# - jira.url
|
||||
# - jira.project
|
||||
# - linear.url
|
||||
# - linear.api-key
|
||||
# - github.org
|
||||
# - github.repo
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"database": "beads.db",
|
||||
"jsonl_export": "issues.jsonl"
|
||||
}
|
||||
3
.gitattributes
vendored
3
.gitattributes
vendored
|
|
@ -1,3 +0,0 @@
|
|||
|
||||
# Use bd merge for beads JSONL files
|
||||
.beads/issues.jsonl merge=beads
|
||||
40
AGENTS.md
40
AGENTS.md
|
|
@ -1,40 +0,0 @@
|
|||
# Agent Instructions
|
||||
|
||||
This project uses **bd** (beads) for issue tracking. Run `bd onboard` to get started.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
```bash
|
||||
bd ready # Find available work
|
||||
bd show <id> # View issue details
|
||||
bd update <id> --status in_progress # Claim work
|
||||
bd close <id> # Complete work
|
||||
bd sync # Sync with git
|
||||
```
|
||||
|
||||
## Landing the Plane (Session Completion)
|
||||
|
||||
**When ending a work session**, you MUST complete ALL steps below. Work is NOT complete until `git push` succeeds.
|
||||
|
||||
**MANDATORY WORKFLOW:**
|
||||
|
||||
1. **File issues for remaining work** - Create issues for anything that needs follow-up
|
||||
2. **Run quality gates** (if code changed) - Tests, linters, builds
|
||||
3. **Update issue status** - Close finished work, update in-progress items
|
||||
4. **PUSH TO REMOTE** - This is MANDATORY:
|
||||
```bash
|
||||
git pull --rebase
|
||||
bd sync
|
||||
git push
|
||||
git status # MUST show "up to date with origin"
|
||||
```
|
||||
5. **Clean up** - Clear stashes, prune remote branches
|
||||
6. **Verify** - All changes committed AND pushed
|
||||
7. **Hand off** - Provide context for next session
|
||||
|
||||
**CRITICAL RULES:**
|
||||
- Work is NOT complete until `git push` succeeds
|
||||
- NEVER stop before pushing - that leaves work stranded locally
|
||||
- NEVER say "ready to push when you are" - YOU must push
|
||||
- If push fails, resolve and retry until it succeeds
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ export const Grid = memo(({ gridSize, bounds, machineInfo }: GridProps) => {
|
|||
const gridColor = canvasColors.grid();
|
||||
|
||||
return (
|
||||
<Group name="grid" listening={false}>
|
||||
<Group name="grid">
|
||||
{lines.verticalLines.map((points, i) => (
|
||||
<Line
|
||||
key={`v-${i}`}
|
||||
|
|
@ -73,7 +73,7 @@ export const Origin = memo(() => {
|
|||
const originColor = canvasColors.origin();
|
||||
|
||||
return (
|
||||
<Group name="origin" listening={false}>
|
||||
<Group name="origin">
|
||||
<Line points={[-10, 0, 10, 0]} stroke={originColor} strokeWidth={2} />
|
||||
<Line points={[0, -10, 0, 10]} stroke={originColor} strokeWidth={2} />
|
||||
</Group>
|
||||
|
|
@ -93,7 +93,7 @@ export const Hoop = memo(({ machineInfo }: HoopProps) => {
|
|||
const hoopColor = canvasColors.hoop();
|
||||
|
||||
return (
|
||||
<Group name="hoop" listening={false}>
|
||||
<Group name="hoop">
|
||||
<Rect
|
||||
x={hoopLeft}
|
||||
y={hoopTop}
|
||||
|
|
|
|||
|
|
@ -74,8 +74,6 @@ export function PatternCanvas() {
|
|||
handleZoomIn,
|
||||
handleZoomOut,
|
||||
handleZoomReset,
|
||||
handleStageDragStart,
|
||||
handleStageDragEnd,
|
||||
} = useCanvasViewport({
|
||||
containerRef,
|
||||
pesData,
|
||||
|
|
@ -167,8 +165,16 @@ export function PatternCanvas() {
|
|||
scaleY={stageScale}
|
||||
draggable
|
||||
onWheel={handleWheel}
|
||||
onDragStart={handleStageDragStart}
|
||||
onDragEnd={handleStageDragEnd}
|
||||
onDragStart={() => {
|
||||
if (stageRef.current) {
|
||||
stageRef.current.container().style.cursor = "grabbing";
|
||||
}
|
||||
}}
|
||||
onDragEnd={() => {
|
||||
if (stageRef.current) {
|
||||
stageRef.current.container().style.cursor = "grab";
|
||||
}
|
||||
}}
|
||||
ref={(node) => {
|
||||
stageRef.current = node;
|
||||
if (node) {
|
||||
|
|
@ -176,8 +182,8 @@ export function PatternCanvas() {
|
|||
}
|
||||
}}
|
||||
>
|
||||
{/* Background layer: grid, origin, hoop - static, no event listening */}
|
||||
<Layer listening={false}>
|
||||
{/* Background layer: grid, origin, hoop */}
|
||||
<Layer>
|
||||
{displayPattern && (
|
||||
<>
|
||||
<Grid
|
||||
|
|
|
|||
|
|
@ -2,16 +2,10 @@
|
|||
* useCanvasViewport Hook
|
||||
*
|
||||
* Manages canvas viewport state including zoom, pan, and container size
|
||||
* Handles wheel zoom, button zoom operations, and stage drag cursor updates
|
||||
* Handles wheel zoom and button zoom operations
|
||||
*/
|
||||
|
||||
import {
|
||||
useState,
|
||||
useEffect,
|
||||
useCallback,
|
||||
useRef,
|
||||
type RefObject,
|
||||
} from "react";
|
||||
import { useState, useEffect, useCallback, type RefObject } from "react";
|
||||
import type Konva from "konva";
|
||||
import type { PesPatternData } from "../../formats/import/pesImporter";
|
||||
import type { MachineInfo } from "../../types/machine";
|
||||
|
|
@ -93,12 +87,7 @@ export function useCanvasViewport({
|
|||
setStagePos({ x: containerSize.width / 2, y: containerSize.height / 2 });
|
||||
}
|
||||
|
||||
// Wheel zoom handler with RAF throttling and delta accumulation
|
||||
const wheelThrottleRef = useRef<number | null>(null);
|
||||
const accumulatedDeltaRef = useRef<number>(0);
|
||||
const lastPointerRef = useRef<{ x: number; y: number } | null>(null);
|
||||
const lastStageRef = useRef<Konva.Stage | null>(null);
|
||||
|
||||
// Wheel zoom handler
|
||||
const handleWheel = useCallback((e: Konva.KonvaEventObject<WheelEvent>) => {
|
||||
e.evt.preventDefault();
|
||||
|
||||
|
|
@ -108,60 +97,24 @@ export function useCanvasViewport({
|
|||
const pointer = stage.getPointerPosition();
|
||||
if (!pointer) return;
|
||||
|
||||
// Accumulate deltaY from all events during throttle period
|
||||
accumulatedDeltaRef.current += e.evt.deltaY;
|
||||
lastPointerRef.current = pointer;
|
||||
lastStageRef.current = stage;
|
||||
const scaleBy = 1.1;
|
||||
const direction = e.evt.deltaY > 0 ? -1 : 1;
|
||||
|
||||
// Skip if throttle already in progress
|
||||
if (wheelThrottleRef.current !== null) {
|
||||
return;
|
||||
}
|
||||
setStageScale((oldScale) => {
|
||||
const newScale = Math.max(
|
||||
0.1,
|
||||
Math.min(direction > 0 ? oldScale * scaleBy : oldScale / scaleBy, 2),
|
||||
);
|
||||
|
||||
// Schedule update on next animation frame (~16ms)
|
||||
wheelThrottleRef.current = requestAnimationFrame(() => {
|
||||
const accumulatedDelta = accumulatedDeltaRef.current;
|
||||
const pointer = lastPointerRef.current;
|
||||
const stage = lastStageRef.current;
|
||||
// Zoom towards pointer
|
||||
setStagePos((prevPos) =>
|
||||
calculateZoomToPoint(oldScale, newScale, pointer, prevPos),
|
||||
);
|
||||
|
||||
if (!pointer || !stage || accumulatedDelta === 0) {
|
||||
wheelThrottleRef.current = null;
|
||||
accumulatedDeltaRef.current = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const scaleBy = 1.1;
|
||||
const direction = accumulatedDelta > 0 ? -1 : 1;
|
||||
|
||||
setStageScale((oldScale) => {
|
||||
const newScale = Math.max(
|
||||
0.1,
|
||||
Math.min(direction > 0 ? oldScale * scaleBy : oldScale / scaleBy, 2),
|
||||
);
|
||||
|
||||
// Zoom towards pointer
|
||||
setStagePos((prevPos) =>
|
||||
calculateZoomToPoint(oldScale, newScale, pointer, prevPos),
|
||||
);
|
||||
|
||||
return newScale;
|
||||
});
|
||||
|
||||
// Reset accumulator and throttle
|
||||
wheelThrottleRef.current = null;
|
||||
accumulatedDeltaRef.current = 0;
|
||||
return newScale;
|
||||
});
|
||||
}, []);
|
||||
|
||||
// Cleanup wheel throttle on unmount
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (wheelThrottleRef.current !== null) {
|
||||
cancelAnimationFrame(wheelThrottleRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Zoom control handlers
|
||||
const handleZoomIn = useCallback(() => {
|
||||
setStageScale((oldScale) => {
|
||||
|
|
@ -202,27 +155,6 @@ export function useCanvasViewport({
|
|||
setStagePos({ x: containerSize.width / 2, y: containerSize.height / 2 });
|
||||
}, [initialScale, containerSize]);
|
||||
|
||||
// Stage drag handlers - cursor updates immediately for better UX
|
||||
const handleStageDragStart = useCallback(
|
||||
(e: Konva.KonvaEventObject<DragEvent>) => {
|
||||
const stage = e.target.getStage();
|
||||
if (stage) {
|
||||
stage.container().style.cursor = "grabbing";
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const handleStageDragEnd = useCallback(
|
||||
(e: Konva.KonvaEventObject<DragEvent>) => {
|
||||
const stage = e.target.getStage();
|
||||
if (stage) {
|
||||
stage.container().style.cursor = "grab";
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
return {
|
||||
// State
|
||||
stagePos,
|
||||
|
|
@ -234,7 +166,5 @@ export function useCanvasViewport({
|
|||
handleZoomIn,
|
||||
handleZoomOut,
|
||||
handleZoomReset,
|
||||
handleStageDragStart,
|
||||
handleStageDragEnd,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,8 +113,7 @@ export function usePatternTransform({
|
|||
setPatternOffset(centerOffset.x, centerOffset.y);
|
||||
}, [pesData, setPatternOffset]);
|
||||
|
||||
// Pattern drag handler - only updates state when drag is complete
|
||||
// Konva handles the visual drag internally, no need to update React state during drag
|
||||
// Pattern drag handlers
|
||||
const handlePatternDragEnd = useCallback(
|
||||
(e: Konva.KonvaEventObject<DragEvent>) => {
|
||||
const newOffset = {
|
||||
|
|
|
|||
|
|
@ -5,9 +5,6 @@ import { onPatternDeleted } from "./storeEvents";
|
|||
import { calculatePatternCenter } from "../components/PatternCanvas/patternCanvasHelpers";
|
||||
import { calculateRotatedBounds } from "../utils/rotationUtils";
|
||||
|
||||
// Conditional logging for development only
|
||||
const isDev = import.meta.env.DEV;
|
||||
|
||||
interface PatternState {
|
||||
// Original pattern (pre-upload)
|
||||
pesData: PesPatternData | null;
|
||||
|
|
@ -82,17 +79,13 @@ export const usePatternStore = create<PatternState>((set) => ({
|
|||
// Update pattern offset (for original pattern only)
|
||||
setPatternOffset: (x: number, y: number) => {
|
||||
set({ patternOffset: { x, y } });
|
||||
if (isDev) {
|
||||
console.log("[PatternStore] Pattern offset changed:", { x, y });
|
||||
}
|
||||
console.log("[PatternStore] Pattern offset changed:", { x, y });
|
||||
},
|
||||
|
||||
// Set pattern rotation (for original pattern only)
|
||||
setPatternRotation: (rotation: number) => {
|
||||
set({ patternRotation: rotation % 360 });
|
||||
if (isDev) {
|
||||
console.log("[PatternStore] Pattern rotation changed:", rotation);
|
||||
}
|
||||
console.log("[PatternStore] Pattern rotation changed:", rotation);
|
||||
},
|
||||
|
||||
// Set uploaded pattern data (called after upload completes)
|
||||
|
|
@ -108,17 +101,13 @@ export const usePatternStore = create<PatternState>((set) => ({
|
|||
// Optionally set filename if provided (for resume/reconnect scenarios)
|
||||
...(fileName && { currentFileName: fileName }),
|
||||
});
|
||||
if (isDev) {
|
||||
console.log("[PatternStore] Uploaded pattern set");
|
||||
}
|
||||
console.log("[PatternStore] Uploaded pattern set");
|
||||
},
|
||||
|
||||
// Clear uploaded pattern (called when deleting from machine)
|
||||
// This reverts to pre-upload state, keeping pesData so user can re-adjust and re-upload
|
||||
clearUploadedPattern: () => {
|
||||
if (isDev) {
|
||||
console.log("[PatternStore] CLEARING uploaded pattern...");
|
||||
}
|
||||
console.log("[PatternStore] CLEARING uploaded pattern...");
|
||||
set({
|
||||
uploadedPesData: null,
|
||||
uploadedPatternOffset: { x: 0, y: 0 },
|
||||
|
|
@ -126,11 +115,9 @@ export const usePatternStore = create<PatternState>((set) => ({
|
|||
// Keep pesData, currentFileName, patternOffset, patternRotation
|
||||
// so user can adjust and re-upload
|
||||
});
|
||||
if (isDev) {
|
||||
console.log(
|
||||
"[PatternStore] Uploaded pattern cleared - back to editable mode",
|
||||
);
|
||||
}
|
||||
console.log(
|
||||
"[PatternStore] Uploaded pattern cleared - back to editable mode",
|
||||
);
|
||||
},
|
||||
|
||||
// Reset pattern offset to default
|
||||
|
|
|
|||
Loading…
Reference in a new issue