diff --git a/.claude/commands/app-refs-ops.md b/.claude/commands/app-refs-ops.md new file mode 100644 index 0000000..b325282 --- /dev/null +++ b/.claude/commands/app-refs-ops.md @@ -0,0 +1,147 @@ +--- +name: "app-refs-ops" +description: "Start or resume the App-References operating model when the user says APP REFS OPS, asks to start app-refs ops/dev work, asks for the ready-ticket worker, PR finisher, or backlog gardener, or wants Codex to pick ready Project 2 work and run the App-References coordination process." +--- + +# App-References Ops + +Use this skill when the user wants Codex to start or resume the standard App-References operating model. + +Canonical trigger: + +```text +APP REFS OPS +``` + +## Context + +This repo is **UI-only**. Traverse runtime and business logic live outside this repo. +The UI must not compute business fields (tags, note type, next action, status) — it renders runtime-provided data only. + +All tickets live in [Project 2](https://github.com/orgs/traverse-framework/projects/2) (`traverse-framework`, project number `2`). +The target repo is `traverse-framework/App-References`. + +Read `docs/traverse-starter-plan.md` and `.specify/memory/constitution.md` before any implementation work. + +## Workflow + +1. Read `.specify/memory/constitution.md` before any implementation work. +2. Read `AGENTS.md` and follow the agent coordination rules. +3. Inspect current GitHub and Project 2 state. +4. Prefer finishing existing open PRs before claiming new Ready work. +5. If no active PR needs attention, pick one Ready Project 2 issue. +6. Before work on an issue, run the pre-flight checks from `AGENTS.md`: + - issue must not have `agent:claude` + - no remote `claude/issue-NNN-*` branch may exist +7. If pre-flight passes, claim the issue: + - add `agent:codex` + - set Project 2 `Agent` to `Codex` + - set Project 2 `Status` to `In Progress` +8. Use a dedicated `codex/issue-NNN-*` branch. +9. Keep work scoped to the claimed issue and the UI-only architecture boundary. +10. Open a dedicated PR with the required sections (Summary, Definition of Done, Validation). + +## Project 2 IDs + +| Resource | ID | +|---|---| +| Project node ID | `PVT_kwDOEbiBt84BbzAz` | +| Status field | `PVTSSF_lADOEbiBt84BbzAzzhWg5OQ` | +| Status: Todo | `f75ad846` | +| Status: In Progress | `47fc9ee4` | +| Status: Done | `98236657` | +| Status: Ready | `81742589` | +| Status: Blocked | `559e1fec` | +| Status: Future | `7130dc35` | +| Agent field | `PVTSSF_lADOEbiBt84BbzAzzhWjEik` | +| Agent: Unassigned | `8ebf043b` | +| Agent: Codex | `e428b05e` | +| Agent: Claude Code | `8f903ad6` | +| Agent: Cursor | `a9811389` | +| Agent: Antigravity | `77295899` | +| Note field | `PVTF_lADOEbiBt84BbzAzzhWjEio` | + +## Pre-flight + Claim Sequence + +Multiple agents run in parallel. All three checks must pass before claiming. + +```bash +# Check 1 — any agent:* label already on this issue? +gh issue view --repo traverse-framework/App-References --json labels \ + --jq '.labels[].name | select(startswith("agent:"))' +# If anything is returned → STOP. Issue is already claimed. + +# Check 2 — any agent branch already exists? +git ls-remote --heads origin | grep "/issue--" +# If anything is returned → STOP. Another agent is already working this. + +# Check 3 — status is Ready? +gh project item-list 2 --owner traverse-framework --format json --limit 300 \ + --jq '.items[] | select(.content.number == ) | .status' +# If not "Ready" → STOP. + +# ── All three passed — now claim ────────────────────────────────────────── + +gh issue edit --repo traverse-framework/App-References --add-label "agent:codex" + +ITEM_ID=$(gh project item-list 2 --owner traverse-framework --format json --limit 300 \ + --jq '.items[] | select(.content.number == ) | .id') + +gh project item-edit --project-id PVT_kwDOEbiBt84BbzAz \ + --id "$ITEM_ID" \ + --field-id PVTSSF_lADOEbiBt84BbzAzzhWjEik \ + --single-select-option-id e428b05e # Codex + +gh project item-edit --project-id PVT_kwDOEbiBt84BbzAz \ + --id "$ITEM_ID" \ + --field-id PVTSSF_lADOEbiBt84BbzAzzhWg5OQ \ + --single-select-option-id 47fc9ee4 # In Progress +``` + +## Token Discipline + +- Prefer targeted GitHub queries over full board dumps. For Ready work: + ```bash + gh project item-list 2 --owner traverse-framework --format json --limit 300 \ + --jq '.items[] | select(.status == "Ready") | {number: .content.number, title: .content.title}' + ``` +- Do not paste full project lists, test output, or CI logs. Summarize pass/fail and quote only failing lines. +- Use `git diff --stat` and focused file hunks before large diffs. +- Keep progress updates short: current action, any blocker, next action. + +## Minimality Ladder + +Before adding code: + +1. Does this change need to exist for the active issue? +2. Does it belong in the UI layer at all, or in Traverse? +3. Can existing components, hooks, or config already satisfy it? +4. Can a type, config, or doc update solve it without a new abstraction? +5. Can one focused component or hook solve it? +6. Add only the minimum new structure needed. + +Minimality must never push business logic into the UI, import private Traverse internals, or fake runtime behavior. + +## Architecture Guardrails + +- **Never** compute title, tags, note type, next action, or status in the UI +- **Never** import private Traverse internals +- **Never** fake workflow registration or runtime behavior in application code +- **Always** drive UI state from runtime-provided events +- Phase 2 (app validation/registration) is **blocked** until Traverse public CLI surface exists + +## Operating Lanes + +- **Ready-ticket worker**: claim one Ready Project 2 issue and implement it end to end. +- **PR finisher**: inspect open PRs, fix CI/review issues, and merge when green. +- **Backlog gardener**: audit Project 2 statuses, labels, blockers, and notes. + +## Guardrails + +- Do not mark work `In Progress` unless a real dev thread has started. +- Do not use labels as status; Project 2 status is the actionability source of truth. +- Do not claim work already owned by Claude Code. +- Do not broaden scope beyond the issue and the UI-only architecture boundary. +- Create follow-up tickets for non-blocking improvements instead of expanding an active slice. + +For the full operating model, see `docs/multi-thread-workflow.md`. diff --git a/apps/youaskm3/PLAN.md b/apps/youaskm3/PLAN.md deleted file mode 100644 index 2b5658e..0000000 --- a/apps/youaskm3/PLAN.md +++ /dev/null @@ -1,86 +0,0 @@ -# youaskm3 Plan - -## Purpose - -youaskm3 is the primary downstream reference app for Traverse. It is a browser-hosted knowledge workflow app that demonstrates the full app-consumable path: - -- Phase 1: UI → HTTP execute → poll → render runtime output -- Phase 2: app manifest → `traverse-cli app validate` → `traverse-cli app register` → runtime loads → UI invokes registered workflow - -## Architecture Boundary - -**UI layer (this repo):** -- React shell at `apps/youaskm3/web-react` -- Thin HTTP client using spec-033 surfaces only -- App manifests at `manifests/youaskm3/` - -**Traverse runtime (external):** -- WASM component execution -- Workflow state machine -- Structured output fields (answer, reasoning, status) -- Trace generation - -The UI renders, sorts, filters, and displays runtime-provided data. It computes nothing. - -## Phase 1 — HTTP Integration - -**Governing spec:** `033-http-json-api` (approved v1.1.0) - -**Runtime surface used:** -``` -GET /healthz -POST /v1/workspaces/{workspace_id}/execute -GET /v1/workspaces/{workspace_id}/executions/{execution_id} -GET /v1/workspaces/{workspace_id}/traces/{execution_id} -``` - -**Discovery:** `.traverse/server.json` → `base_url`, `workspace_default` - -**UI states:** idle → submitting → polling → succeeded / failed - -**Runtime-provided output fields (UI renders, does not compute):** -- `answer` or result -- `reasoning` or trace summary -- `status` -- `executionId` - -## Phase 2 — App Registration - -**Governing specs:** `044-application-bundle-manifest`, `046-public-cli-app-registration` (both approved) - -**CLI surface:** -```bash -traverse-cli app validate --manifest manifests/youaskm3/app.manifest.json --json -traverse-cli app register --manifest manifests/youaskm3/app.manifest.json --workspace local-default --json -``` - -**What registration unlocks:** runtime loads the registered WASM workflow → UI invokes it by capability ID → full end-to-end path without harness shortcuts. - -## Ticket Sequence - -| # | Ticket | Depends on | -|---|---|---| -| 10 | Define youaskm3 plan (this doc) | #9 | -| 11 | Scaffold React UI shell | #10, #2 (toolchain) | -| 12 | Author app manifest + WASM component manifests | #10, #9 | -| 13 | Add Traverse HTTP runtime client | #11, #3 | -| 14 | Implement knowledge workflow UI | #13 | -| 15 | Add Phase 1 smoke test | #14 | -| 16 | Phase 2 CLI validate + register | #12, #13 | -| 17 | Add Phase 2 smoke test | #16, #15 | - -## Open Questions - -1. What capability ID does the youaskm3 workflow register under? (needed for `POST /execute`) -2. What are the exact input fields the Traverse workflow expects from the UI? -3. What output fields does the registered workflow guarantee in the execution envelope? -4. Are the WASM components pre-built artifacts or does this repo need to reference an external build? -5. What model dependency does the knowledge workflow require? (ref spec `045`) - -## Constraints - -- No business logic in the React layer -- No private Traverse internals imported -- No fake runtime responses in application code -- No HTTP app registration endpoint — setup uses CLI only -- Phase 2 does not start until #12 (manifests) passes `traverse-cli app validate` diff --git a/apps/youaskm3/web-react/.env b/apps/youaskm3/web-react/.env deleted file mode 100644 index 7679773..0000000 --- a/apps/youaskm3/web-react/.env +++ /dev/null @@ -1,3 +0,0 @@ -# Local Traverse Runtime configuration -# Change this to match your Traverse serving port -VITE_TRAVERSE_RUNTIME_URL=http://localhost:3000 diff --git a/apps/youaskm3/web-react/.gitignore b/apps/youaskm3/web-react/.gitignore deleted file mode 100644 index 2d7a11c..0000000 --- a/apps/youaskm3/web-react/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules/ -dist/ -coverage/ -.env.local -.env.*.local diff --git a/apps/youaskm3/web-react/README.md b/apps/youaskm3/web-react/README.md deleted file mode 100644 index f4d7995..0000000 --- a/apps/youaskm3/web-react/README.md +++ /dev/null @@ -1,78 +0,0 @@ -# youaskm3 — Web React UI - -Browser-hosted knowledge workflow app built on Traverse. - -This UI shell owns nothing but rendering. Traverse runtime owns business execution, workflow state, trace generation, and structured output. - -## What It Does - -User submits a question or knowledge item → Traverse executes the registered workflow → UI renders runtime-provided output (answer, reasoning, status). The UI computes none of these fields. - -## Architecture Boundary - -| Concern | Lives here | -|---|---| -| React components and UI state | Yes | -| HTTP client to Traverse runtime | Yes (thin boundary only) | -| Business logic, workflow execution | No — Traverse runtime | -| WASM components | No — `manifests/youaskm3/` | - -## Local Setup - -### Step 1 — Start Traverse runtime (v0.3.0) - -```bash -git clone https://github.com/traverse-framework/Traverse.git /tmp/traverse -cd /tmp/traverse && git checkout v0.3.0 -cargo run -p traverse-cli -- serve -# Writes .traverse/server.json — base_url=http://127.0.0.1:8787 -``` - -### Step 2 — (Phase 2 only) Register the app - -```bash -cd -traverse-cli app validate --manifest manifests/youaskm3/app.manifest.json --json -traverse-cli app register --manifest manifests/youaskm3/app.manifest.json --workspace local-default --json -``` - -### Step 3 — Start the UI - -```bash -npm install -npm run dev -``` - -### Override for Traverse framework development - -```bash -export TRAVERSE_REPO=/path/to/Traverse -cd $TRAVERSE_REPO && cargo run -p traverse-cli -- serve -``` - -## Commands - -```bash -npm run dev # Start local dev server -npm run build # Production build -npm run typecheck # TypeScript check -npm run lint # ESLint -npm run test # Vitest unit tests -npm run test:coverage -``` - -## Environment - -The app discovers the runtime via `.traverse/server.json` (written by `traverse-cli serve`). - -Override for CI environments: -```bash -VITE_TRAVERSE_BASE_URL=http://127.0.0.1:8787 -VITE_TRAVERSE_WORKSPACE=local-default -``` - -## Governing Specs - -- `033-http-json-api` (approved v1.1.0) — runtime HTTP API -- `044-application-bundle-manifest` (approved) — app manifest model -- `046-public-cli-app-registration` (approved) — CLI validate + register diff --git a/apps/youaskm3/web-react/eslint.config.js b/apps/youaskm3/web-react/eslint.config.js deleted file mode 100644 index cd66985..0000000 --- a/apps/youaskm3/web-react/eslint.config.js +++ /dev/null @@ -1,22 +0,0 @@ -import js from '@eslint/js' -import globals from 'globals' -import reactHooks from 'eslint-plugin-react-hooks' -import reactRefresh from 'eslint-plugin-react-refresh' -import tseslint from 'typescript-eslint' -import { defineConfig, globalIgnores } from 'eslint/config' - -export default defineConfig([ - globalIgnores(['dist', 'coverage']), - { - files: ['**/*.{ts,tsx}'], - extends: [ - js.configs.recommended, - tseslint.configs.recommended, - reactHooks.configs.flat.recommended, - reactRefresh.configs.vite, - ], - languageOptions: { - globals: globals.browser, - }, - }, -]) diff --git a/apps/youaskm3/web-react/index.html b/apps/youaskm3/web-react/index.html deleted file mode 100644 index 0465058..0000000 --- a/apps/youaskm3/web-react/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - youaskm3 - - -
- - - diff --git a/apps/youaskm3/web-react/package.json b/apps/youaskm3/web-react/package.json deleted file mode 100644 index e6937d5..0000000 --- a/apps/youaskm3/web-react/package.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "youaskm3-web-react", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc -b && vite build", - "typecheck": "tsc -b", - "lint": "eslint .", - "preview": "vite preview", - "test": "vitest run", - "test:coverage": "vitest run --coverage" - }, - "dependencies": { - "react": "^19.2.7", - "react-dom": "^19.2.7" - }, - "devDependencies": { - "@eslint/js": "^10.0.1", - "@types/node": "^24.13.2", - "@types/react": "^19.2.17", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.2", - "eslint": "^10.5.0", - "eslint-plugin-react-hooks": "^7.1.1", - "eslint-plugin-react-refresh": "^0.5.3", - "globals": "^17.6.0", - "typescript": "~6.0.2", - "typescript-eslint": "^8.61.0", - "vite": "^8.1.0", - "vitest": "^3.0.7", - "jsdom": "^26.0.0", - "@testing-library/react": "^16.2.0", - "@testing-library/jest-dom": "^6.6.3", - "@vitest/coverage-v8": "^3.0.7" - } -} diff --git a/apps/youaskm3/web-react/src/App.test.tsx b/apps/youaskm3/web-react/src/App.test.tsx deleted file mode 100644 index fb8f759..0000000 --- a/apps/youaskm3/web-react/src/App.test.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { render, screen } from '@testing-library/react' -import App from './App' - -describe('App', () => { - it('renders the app title', () => { - render() - expect(screen.getByRole('heading', { name: /youaskm3/i })).toBeInTheDocument() - }) - - it('renders the run button', () => { - render() - expect(screen.getByRole('button', { name: /run/i })).toBeInTheDocument() - }) -}) diff --git a/apps/youaskm3/web-react/src/App.tsx b/apps/youaskm3/web-react/src/App.tsx deleted file mode 100644 index 627fc57..0000000 --- a/apps/youaskm3/web-react/src/App.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { useMemo } from 'react' -import { createTraverseClient } from './client/traverseClient' -import { useExecution } from './hooks/useExecution' - -const BASE_URL = import.meta.env.VITE_TRAVERSE_BASE_URL ?? 'http://127.0.0.1:8787' -const WORKSPACE = import.meta.env.VITE_TRAVERSE_WORKSPACE ?? 'local-default' - -function App() { - const client = useMemo(() => createTraverseClient(BASE_URL), []) - const { state, run } = useExecution(client, WORKSPACE) - - const handleRun = () => { - run('youaskm3.answer', { question: 'What is Traverse?' }) - } - - return ( -
-

youaskm3

-

Runtime: {BASE_URL} · Workspace: {WORKSPACE}

- - - - {state.phase === 'loading' &&

Starting…

} - {state.phase === 'polling' &&

Polling {state.executionId}…

} - {state.phase === 'succeeded' && ( -
-

Done: {JSON.stringify(state.result.output)}

- {state.trace.length > 0 &&

Trace events: {state.trace.length}

} -
- )} - {state.phase === 'failed' &&

Error: {state.error}

} -
- ) -} - -export default App diff --git a/apps/youaskm3/web-react/src/client/traverseClient.test.ts b/apps/youaskm3/web-react/src/client/traverseClient.test.ts deleted file mode 100644 index 82358eb..0000000 --- a/apps/youaskm3/web-react/src/client/traverseClient.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { createTraverseClient } from './traverseClient' - -const BASE = 'http://localhost:8787' - -function mockFetch(responses: Record) { - return vi.fn((url: string) => { - const key = Object.keys(responses).find(k => url.includes(k)) - if (!key) return Promise.resolve({ ok: false, status: 404 }) - return Promise.resolve({ - ok: true, - json: () => Promise.resolve(responses[key]), - }) - }) as unknown as typeof fetch -} - -describe('createTraverseClient', () => { - it('execute posts and returns execution_id', async () => { - const fetch = mockFetch({ '/execute': { execution_id: 'exec-1' } }) - global.fetch = fetch - const client = createTraverseClient(BASE) - const id = await client.execute('local-default', 'cap.foo', { q: 'hi' }) - expect(id).toBe('exec-1') - expect(fetch).toHaveBeenCalledWith( - `${BASE}/v1/workspaces/local-default/execute`, - expect.objectContaining({ method: 'POST' }), - ) - }) - - it('pollExecution returns result', async () => { - const fetch = mockFetch({ '/executions/exec-1': { execution_id: 'exec-1', status: 'succeeded', output: 42 } }) - global.fetch = fetch - const client = createTraverseClient(BASE) - const result = await client.pollExecution('local-default', 'exec-1') - expect(result.status).toBe('succeeded') - expect(result.output).toBe(42) - }) - - it('fetchTrace returns events', async () => { - const fetch = mockFetch({ '/traces/exec-1': [{ event_type: 'start', timestamp: 't0' }] }) - global.fetch = fetch - const client = createTraverseClient(BASE) - const trace = await client.fetchTrace('local-default', 'exec-1') - expect(trace).toHaveLength(1) - expect(trace[0].event_type).toBe('start') - }) - - it('execute throws on non-ok response', async () => { - global.fetch = vi.fn(() => Promise.resolve({ ok: false, status: 500 })) as unknown as typeof fetch - const client = createTraverseClient(BASE) - await expect(client.execute('ws', 'cap', {})).rejects.toThrow('execute failed: 500') - }) -}) diff --git a/apps/youaskm3/web-react/src/client/traverseClient.ts b/apps/youaskm3/web-react/src/client/traverseClient.ts deleted file mode 100644 index dc538f3..0000000 --- a/apps/youaskm3/web-react/src/client/traverseClient.ts +++ /dev/null @@ -1,54 +0,0 @@ -export type ExecutionStatus = 'pending' | 'running' | 'succeeded' | 'failed' - -export interface ExecutionResult { - execution_id: string - status: ExecutionStatus - output?: unknown - error?: string -} - -export interface TraceEvent { - event_type: string - timestamp: string - data?: unknown -} - -export interface TraverseClient { - execute(workspaceId: string, capability: string, input: unknown): Promise - pollExecution(workspaceId: string, executionId: string): Promise - fetchTrace(workspaceId: string, executionId: string): Promise -} - -export function createTraverseClient(baseUrl: string): TraverseClient { - return { - async execute(workspaceId, capability, input) { - const res = await fetch( - `${baseUrl}/v1/workspaces/${workspaceId}/execute`, - { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ capability, input }), - }, - ) - if (!res.ok) throw new Error(`execute failed: ${res.status}`) - const data = (await res.json()) as { execution_id: string } - return data.execution_id - }, - - async pollExecution(workspaceId, executionId) { - const res = await fetch( - `${baseUrl}/v1/workspaces/${workspaceId}/executions/${executionId}`, - ) - if (!res.ok) throw new Error(`poll failed: ${res.status}`) - return (await res.json()) as ExecutionResult - }, - - async fetchTrace(workspaceId, executionId) { - const res = await fetch( - `${baseUrl}/v1/workspaces/${workspaceId}/traces/${executionId}`, - ) - if (!res.ok) throw new Error(`trace fetch failed: ${res.status}`) - return (await res.json()) as TraceEvent[] - }, - } -} diff --git a/apps/youaskm3/web-react/src/hooks/useExecution.test.ts b/apps/youaskm3/web-react/src/hooks/useExecution.test.ts deleted file mode 100644 index e6135c1..0000000 --- a/apps/youaskm3/web-react/src/hooks/useExecution.test.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { renderHook, act } from '@testing-library/react' -import { useExecution } from './useExecution' -import type { TraverseClient, ExecutionResult } from '../client/traverseClient' - -function makeClient(overrides: Partial = {}): TraverseClient { - return { - execute: vi.fn().mockResolvedValue('exec-1'), - pollExecution: vi.fn().mockResolvedValue({ - execution_id: 'exec-1', - status: 'succeeded', - output: 'ok', - } as ExecutionResult), - fetchTrace: vi.fn().mockResolvedValue([]), - ...overrides, - } -} - -const POLL_MS = 10 - -describe('useExecution', () => { - beforeEach(() => vi.useFakeTimers()) - afterEach(() => vi.useRealTimers()) - - it('starts idle', () => { - const { result } = renderHook(() => useExecution(makeClient(), 'ws', POLL_MS)) - expect(result.current.state.phase).toBe('idle') - }) - - it('transitions loading → succeeded via polling', async () => { - const client = makeClient() - const { result } = renderHook(() => useExecution(client, 'ws', POLL_MS)) - - act(() => { result.current.run('cap', {}) }) - expect(result.current.state.phase).toBe('loading') - - // flush execute promise, interval not yet fired - await act(async () => { await Promise.resolve() }) - expect(result.current.state.phase).toBe('polling') - - // fire the poll interval - await act(async () => { await vi.advanceTimersByTimeAsync(POLL_MS) }) - expect(result.current.state.phase).toBe('succeeded') - }) - - it('transitions to failed when execute throws', async () => { - const client = makeClient({ - execute: vi.fn().mockRejectedValue(new Error('net error')), - }) - const { result } = renderHook(() => useExecution(client, 'ws', POLL_MS)) - - await act(async () => { - result.current.run('cap', {}) - await Promise.resolve() - }) - - expect(result.current.state.phase).toBe('failed') - expect((result.current.state as { phase: 'failed'; error: string }).error).toContain('net error') - }) - - it('transitions to failed when poll returns failed status', async () => { - const client = makeClient({ - pollExecution: vi.fn().mockResolvedValue({ - execution_id: 'exec-1', - status: 'failed', - error: 'boom', - } as ExecutionResult), - }) - const { result } = renderHook(() => useExecution(client, 'ws', POLL_MS)) - - act(() => { result.current.run('cap', {}) }) - await act(async () => { await Promise.resolve() }) - await act(async () => { await vi.advanceTimersByTimeAsync(POLL_MS) }) - - expect(result.current.state.phase).toBe('failed') - expect((result.current.state as { phase: 'failed'; error: string }).error).toBe('boom') - }) -}) diff --git a/apps/youaskm3/web-react/src/hooks/useExecution.ts b/apps/youaskm3/web-react/src/hooks/useExecution.ts deleted file mode 100644 index 03c712d..0000000 --- a/apps/youaskm3/web-react/src/hooks/useExecution.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { useState, useCallback, useRef } from 'react' -import { type TraverseClient, type ExecutionResult, type TraceEvent } from '../client/traverseClient' - -export type ExecutionState = - | { phase: 'idle' } - | { phase: 'loading' } - | { phase: 'polling'; executionId: string } - | { phase: 'succeeded'; result: ExecutionResult; trace: TraceEvent[] } - | { phase: 'failed'; error: string } - -const POLL_TERMINAL: readonly string[] = ['succeeded', 'failed'] - -export function useExecution(client: TraverseClient, workspaceId: string, pollIntervalMs = 1000) { - const [state, setState] = useState({ phase: 'idle' }) - const pollRef = useRef | null>(null) - - const stopPolling = useCallback(() => { - if (pollRef.current !== null) { - clearInterval(pollRef.current) - pollRef.current = null - } - }, []) - - const run = useCallback( - async (capability: string, input: unknown) => { - stopPolling() - setState({ phase: 'loading' }) - - let executionId: string - try { - executionId = await client.execute(workspaceId, capability, input) - } catch (e) { - setState({ phase: 'failed', error: String(e) }) - return - } - - setState({ phase: 'polling', executionId }) - - pollRef.current = setInterval(async () => { - try { - const result = await client.pollExecution(workspaceId, executionId) - if (POLL_TERMINAL.includes(result.status)) { - stopPolling() - const trace = await client.fetchTrace(workspaceId, executionId).catch(() => []) - if (result.status === 'succeeded') { - setState({ phase: 'succeeded', result, trace }) - } else { - setState({ phase: 'failed', error: result.error ?? 'execution failed' }) - } - } - } catch (e) { - stopPolling() - setState({ phase: 'failed', error: String(e) }) - } - }, pollIntervalMs) - }, - [client, workspaceId, stopPolling, pollIntervalMs], - ) - - return { state, run } -} diff --git a/apps/youaskm3/web-react/src/main.tsx b/apps/youaskm3/web-react/src/main.tsx deleted file mode 100644 index 4aff025..0000000 --- a/apps/youaskm3/web-react/src/main.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { StrictMode } from 'react' -import { createRoot } from 'react-dom/client' -import App from './App.tsx' - -createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/apps/youaskm3/web-react/src/test/setup.ts b/apps/youaskm3/web-react/src/test/setup.ts deleted file mode 100644 index c44951a..0000000 --- a/apps/youaskm3/web-react/src/test/setup.ts +++ /dev/null @@ -1 +0,0 @@ -import '@testing-library/jest-dom' diff --git a/apps/youaskm3/web-react/tsconfig.app.json b/apps/youaskm3/web-react/tsconfig.app.json deleted file mode 100644 index dccb228..0000000 --- a/apps/youaskm3/web-react/tsconfig.app.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "es2023", - "lib": ["ES2023", "DOM"], - "module": "esnext", - "types": ["vite/client", "vitest/globals"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] -} diff --git a/apps/youaskm3/web-react/tsconfig.json b/apps/youaskm3/web-react/tsconfig.json deleted file mode 100644 index 1ffef60..0000000 --- a/apps/youaskm3/web-react/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/apps/youaskm3/web-react/tsconfig.node.json b/apps/youaskm3/web-react/tsconfig.node.json deleted file mode 100644 index 8455dcb..0000000 --- a/apps/youaskm3/web-react/tsconfig.node.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "es2023", - "lib": ["ES2023"], - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "module": "nodenext", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["vite.config.ts"] -} diff --git a/apps/youaskm3/web-react/vite.config.ts b/apps/youaskm3/web-react/vite.config.ts deleted file mode 100644 index e3f6e69..0000000 --- a/apps/youaskm3/web-react/vite.config.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' - -export default defineConfig({ - plugins: [react()], - // @ts-expect-error - vitest types clash with Vite 8's Rolldown-based type definitions - test: { - environment: 'jsdom', - globals: true, - setupFiles: './src/test/setup.ts', - coverage: { - provider: 'v8', - reporter: ['text', 'json', 'html'], - exclude: [ - 'node_modules/', - 'src/test/setup.ts', - 'eslint.config.js', - 'vite.config.ts', - ], - }, - }, -}) diff --git a/manifests/youaskm3/.gitkeep b/manifests/youaskm3/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/package-lock.json b/package-lock.json index 091d0c9..2697f65 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,8 +6,7 @@ "": { "name": "app-references", "workspaces": [ - "apps/traverse-starter/web-react", - "apps/youaskm3/web-react" + "apps/traverse-starter/web-react" ] }, "apps/traverse-starter/web-react": { @@ -39,6 +38,7 @@ "apps/youaskm3/web-react": { "name": "youaskm3-web-react", "version": "0.0.0", + "extraneous": true, "dependencies": { "react": "^19.2.7", "react-dom": "^19.2.7" @@ -5679,10 +5679,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/youaskm3-web-react": { - "resolved": "apps/youaskm3/web-react", - "link": true - }, "node_modules/zod": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", diff --git a/package.json b/package.json index ae80732..e91ed12 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,7 @@ "name": "app-references", "private": true, "workspaces": [ - "apps/traverse-starter/web-react", - "apps/youaskm3/web-react" + "apps/traverse-starter/web-react" ], "scripts": { "dev": "npm run dev -w apps/traverse-starter/web-react",