diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a7141f1b..fc5a14e4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -150,3 +150,52 @@ jobs: with: tag: ${{ needs.create-release.outputs.tag }} secrets: inherit + + update-homebrew-tap: + needs: [create-release, build] + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Require tap push token + env: + TAP_TOKEN: ${{ secrets.RELEASE_PAT }} + run: | + if [ -z "$TAP_TOKEN" ]; then + echo "Missing secret RELEASE_PAT" + exit 1 + fi + - name: Checkout hack + uses: actions/checkout@v4 + - name: Checkout tap repo + uses: actions/checkout@v4 + with: + repository: hack-dance/homebrew-tap + token: ${{ secrets.RELEASE_PAT }} + ref: main + path: homebrew-tap + - name: Setup Bun + uses: oven-sh/setup-bun@v1 + with: + bun-version: "1.3.9" + - name: Render formula + env: + GH_TOKEN: ${{ github.token }} + run: | + bun run scripts/update-homebrew-tap.ts \ + --tag="${{ needs.create-release.outputs.tag }}" \ + --version="${{ needs.create-release.outputs.version }}" \ + --tap-dir=homebrew-tap + - name: Commit and push tap update + working-directory: homebrew-tap + run: | + set -euo pipefail + git add Formula/hack.rb + if git diff --cached --quiet; then + echo "No Homebrew tap changes to push." + exit 0 + fi + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git commit -m "build(hack): update formula to ${{ needs.create-release.outputs.tag }}" + git push origin HEAD:main diff --git a/.gitignore b/.gitignore index 91218fd5..5a08cf5b 100644 --- a/.gitignore +++ b/.gitignore @@ -28,9 +28,16 @@ report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json *.app-key.pem *.p8 hackdance.*.private-key.pem +.hack/hack.env.default.yaml .hack.secret.key +.hack/.env +.hack/.env.state.json .hack-secrets-file.key .hack-secrets.enc.json +.hack/linear +.hack/_linear +.hack/internal +.hack/.env.state.json # caches .eslintcache diff --git a/.gitleaksignore b/.gitleaksignore index 9668b822..c753a2d9 100644 --- a/.gitleaksignore +++ b/.gitleaksignore @@ -1,3 +1,4 @@ 14f9809b6a474ac2c820a4268dcbfc67fe878639:services/auth-broker/Untitled:generic-api-key:2 cbad51795170d25e1ab0926c1ac5a74d1e001ef9:.factory/validation/misc-admin-followups-1/user-testing/flows/management-token-email-verified.json:generic-api-key:8 e069b8546c112e5b5c8ab0ec82fd24a4f19ef16b:.hack/tickets/events/events-2026-03.jsonl:generic-api-key:58 +939c2b2cb680744707b1d085db0bc0ce8fac32e4:tests/env.test.ts:private-key:7 diff --git a/.hack/docker-compose.yml b/.hack/docker-compose.yml index 58083abf..ed1e7464 100644 --- a/.hack/docker-compose.yml +++ b/.hack/docker-compose.yml @@ -23,12 +23,6 @@ services: environment: CHOKIDAR_USEPOLLING: "true" WATCHPACK_POLLING: "true" - HACK_WEB_APP_BASE_URL: https://hack-cli.hack - HACK_AUTH_BROKER_URL: https://auth.hack-cli.hack - HACK_AUTH_BROKER_INTERNAL_URL: http://auth-broker:8080 - NEXT_PUBLIC_HACK_WEB_APP_BASE_URL: https://hack-cli.hack - NEXT_PUBLIC_HACK_AUTH_BROKER_URL: https://auth.hack-cli.hack - BETTER_AUTH_TRUSTED_ORIGINS: https://hack-cli.hack,https://hack-cli.hack.gy labels: caddy: "hack-cli.hack, hack-cli.hack.gy" caddy.reverse_proxy: "{{upstreams 3000}}" @@ -50,9 +44,6 @@ services: environment: PORT: "8080" HOST: "0.0.0.0" - AUTH_BROKER_PUBLIC_BASE_URL: https://auth.hack-cli.hack - HACK_WEB_APP_BASE_URL: https://hack-cli.hack - BETTER_AUTH_TRUSTED_ORIGINS: https://hack-cli.hack,https://hack-cli.hack.gy labels: caddy: "auth.hack-cli.hack, auth.hack-cli.hack.gy" caddy.reverse_proxy: "{{upstreams 8080}}" diff --git a/.hack/hack.env.remote.yaml b/.hack/hack.env.remote.yaml new file mode 100644 index 00000000..6a3deeb6 --- /dev/null +++ b/.hack/hack.env.remote.yaml @@ -0,0 +1,15 @@ +version: 1 +environment: remote +secretsprovider: project_key +values: + web: + HACK_AUTH_BROKER_URL: https://auth.hack.broker + NEXT_PUBLIC_HACK_AUTH_BROKER_URL: https://auth.hack.broker + auth-broker: + AUTH_BROKER_PUBLIC_BASE_URL: https://auth.hack.broker + BETTER_AUTH_URL: https://auth.hack.broker + # Broker custom GitHub OAuth callback for Hack-owned flows. + # Better Auth browser social login uses: + # ${BETTER_AUTH_URL}/api/auth/callback/github + GITHUB_REDIRECT_URI: https://auth.hack.broker/gh/callback + HACK_LINEAR_REDIRECT_URI: https://auth.hack.broker/linear/callback diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/closeout-scope.json b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/closeout-scope.json deleted file mode 100644 index 0b7f0b8d..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/closeout-scope.json +++ /dev/null @@ -1,110 +0,0 @@ -{ - "projectId": "7a3c8adf-ede5-4d3a-8779-9c32695c76bf", - "projectName": "Hack", - "teamId": "e0aedec9-5273-446f-b975-aa4cd1525900", - "profileId": "default", - "definition": "All Hack-project Linear issues open at mission start plus mission-created optional-web-control-plane issues.", - "seedStatus": "opened_at_start_and_mission_created_seeded", - "openedAtStart": [ - { - "ticketId": "T-J780JQ2VK0", - "externalId": "91c16d6b-deda-47d7-af5a-e7acf2cafdaf", - "externalKey": "HACK-457", - "title": "Dogfood the Hack App Linear project through Hack-native planning and sync flows", - "status": "open" - }, - { - "ticketId": "T-Y4QFAGYKC7", - "externalId": "eb96b169-35da-45cf-a9f6-9a708ab4c487", - "externalKey": "HACK-458", - "title": "Improve autosync, webhook delivery, and operator visibility for Linear sync", - "status": "open" - }, - { - "ticketId": "T-W2TT0YH7FV", - "externalId": "d7d02527-1f29-4a5e-bf17-1405dc758208", - "externalKey": "HACK-463", - "title": "Harden the Docker Desktop primary path and remove fragile Orbstack assumptions", - "status": "open" - }, - { - "ticketId": "T-NFZAWEKT5K", - "externalId": "ec38378c-e36a-416f-a6fc-9241b27b3376", - "externalKey": "HACK-470", - "title": "Connect team and organization administration to env sharing and project ownership", - "status": "open" - }, - { - "ticketId": "T-WGZTQTDWQ4", - "externalId": "3d55ffdb-ed82-4d59-b6b0-af4796cf5d64", - "externalKey": "HACK-471", - "title": "Separate local-only versus broker or cloud-mediated admin operations", - "status": "open" - }, - { - "ticketId": "T-HT0JHXX1QA", - "externalId": "b0cb66e7-925d-488d-8da0-cff1052f4a01", - "externalKey": "HACK-474", - "title": "Define the proposed runtime architecture, interfaces, and build-versus-borrow boundaries", - "status": "open" - }, - { - "ticketId": "T-Q7XAWDR8JZ", - "externalId": "9566c8fc-bd3e-42b8-a3c9-55a81fe1f394", - "externalKey": "HACK-475", - "title": "Produce a separation plan so runtime R&D informs but does not block the current hardening roadmap", - "status": "open" - }, - { - "ticketId": "T-RMCRX5CBCY", - "externalId": "6bb84e91-1cb3-4765-9407-1fc988900999", - "externalKey": "HACK-558", - "title": "Support multiline env values in Hack plaintext env workflow", - "status": "open" - } - ], - "missionCreated": [ - { - "ticketId": "T-XQ0VTXW5AJ", - "externalId": "12c1576b-2366-400e-b5be-3853f984854a", - "externalKey": "HACK-559", - "title": "Optional web control plane delivery tracker", - "parentExternalKey": null, - "status": "open" - }, - { - "ticketId": "T-M9H3R81H2G", - "externalId": "98a94392-fb4e-4d1d-a0fc-05eb7b2b228c", - "externalKey": "HACK-560", - "title": "Optional web control plane: shared auth and web foundation", - "parentExternalKey": "HACK-559", - "status": "open" - }, - { - "ticketId": "T-CBZE19TVEP", - "externalId": "ee0156d8-e883-4b11-b29e-750cc86993e3", - "externalKey": "HACK-561", - "title": "Optional web control plane: org, team, and project administration", - "parentExternalKey": "HACK-559", - "status": "open" - }, - { - "ticketId": "T-W5ZGW8M3QF", - "externalId": "cb5ae6b0-2160-46bd-9eda-3404207decda", - "externalKey": "HACK-562", - "title": "Optional web control plane: GitHub and Linear integration management", - "parentExternalKey": "HACK-559", - "status": "open" - }, - { - "ticketId": "T-DP0Q3VKTTJ", - "externalId": "47788fd6-65ee-4fe6-8eec-55ca5063bee3", - "externalKey": "HACK-563", - "title": "Optional web control plane: env status, CLI optionality, and closeout", - "parentExternalKey": "HACK-559", - "status": "open" - } - ], - "seededAt": "2026-03-24T21:42:00Z", - "missionCreatedAt": "2026-03-24T21:53:30Z" -} diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/delivery-audit.json b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/delivery-audit.json deleted file mode 100644 index a5e4c75b..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/delivery-audit.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "projectId": "7a3c8adf-ede5-4d3a-8779-9c32695c76bf", - "projectIds": ["7a3c8adf-ede5-4d3a-8779-9c32695c76bf"], - "profileId": "default", - "updatedAt": "2026-03-25T15:09:02.519Z", - "processedDeliveries": 0, - "appliedDeliveries": 0, - "failedDeliveries": 0, - "skippedDeliveries": 0, - "created": 0, - "updated": 0, - "commentsPulled": 0, - "conflictsRecorded": 0, - "checkpointsRecorded": 0, - "deliveries": [] -} diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/04b4b1538d50.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/04b4b1538d50.md deleted file mode 100644 index 55e10712..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/04b4b1538d50.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -kind: linear-project-document -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: Agent-Native Container Runtime In Zig Spec -linearId: f5e67f6c-c09c-484c-b556-8f61bf415ae8 -slug: "04b4b1538d50" -archived: false -updatedAt: "2026-03-12T15:50:09.449Z" -sortOrder: 9264 ---- -## Goal - -Define the research and specification work for a future runtime purpose-built for local, agent-heavy development. - -## Why This Exists - -Current container runtimes solve general local container execution well enough, but they are not designed around persistent agent sessions, subagents, local orchestration recovery, rich workspace isolation, or the control-plane semantics Hack is growing into. - -## Research Scope - -Study existing open-source runtimes and adjacent systems to understand: - -* Container lifecycle management. -* Filesystem sync and workspace isolation. -* Network and proxy management. -* Crash recovery and health supervision. -* Host-agent and remote-agent interaction models. - -## Hack-Specific Requirements - -The spec should define requirements for: - -* Fast project and branch isolation. -* Reliable local networking for many active projects. -* Durable session and agent execution semantics. -* Strong crash detection and repair. -* Control-plane integration points. -* Clear boundaries between what should be built versus borrowed. - -## Deliverables - -* Landscape research and constraints summary. -* Hack-specific runtime requirements. -* Proposed architecture and interfaces. -* Build-versus-buy decisions. -* Separation plan so this R&D does not block near-term CLI hardening. - -## Acceptance Criteria - -The stream produces a credible technical specification and research baseline for a future runtime without derailing the current product simplification and hardening work. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/5babf8ed3817.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/5babf8ed3817.md deleted file mode 100644 index 12e942c9..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/5babf8ed3817.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -kind: linear-project-document -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: Web Control Plane Architecture -linearId: "8f55521e-de4f-42c8-a066-0fe3f8f429fc" -slug: "5babf8ed3817" -archived: false -updatedAt: "2026-03-24T17:26:22.514Z" -sortOrder: 11253 ---- -# Web Control Plane Architecture - -## Recommended Shape - -* `apps/web` — Next.js App Router UI on Vercel -* `services/auth-broker` — Railway-hosted control-plane APIs and broker-managed workflows -* `packages/db` — shared Neon and Drizzle database client and schema - -Add small shared packages only when they remove real duplication: - -* auth core -* typed control-plane SDK or contracts -* shared UI tokens or components if they prove necessary - -## Auth Direction - -Extract Better Auth configuration into shared code and let the browser-first app own the web auth surface, while the broker remains the control-plane API backend. This avoids long-term cross-origin auth sprawl and keeps one identity model. - -## Optionality Rule - -No critical local-only Hack flow should require the web app. Shared admin and integration management may prefer the app, but CLI workflows must remain valid and documented. - -## Immediate Risks To Manage - -* auth topology drift between app and broker -* duplicated schemas or validation contracts -* silently making shared admin flows web-only -* allowing the app milestone to stall GitHub, Linear, or runtime delivery streams \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/683cf0d82fe9.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/683cf0d82fe9.md deleted file mode 100644 index 1de22d7f..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/683cf0d82fe9.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -kind: linear-project-document -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: Optional Web Control Plane Spec -linearId: "5dbbefd0-47a9-485a-a6bd-e429d805676b" -slug: "683cf0d82fe9" -archived: false -updatedAt: "2026-03-24T17:26:25.056Z" -sortOrder: 10326 ---- -# Optional Web Control Plane Spec - -## Goal - -Add a real browser-based control plane for shared and account-scoped workflows without making the web app a requirement for local Hack usage. - -## Product Boundary - -The web app is optional. Hack CLI remains the source of truth for local-first project workflows and must continue to work when the app is unavailable. - -The web app becomes the preferred surface for: - -* account and session management -* org and team administration -* project registration, ownership, and access controls -* GitHub app installation and configuration -* Linear app installation and configuration -* env trust-model visibility, secret sharing, recovery, and rotation - -## Deployment Model - -* `apps/web` runs on Vercel -* `services/auth-broker` remains on Railway -* shared persistence stays on Neon via Drizzle - -## Delivery Principle - -Build the thinnest coherent control-plane slice first, then grow into integration and env-management surfaces while keeping CLI parity explicit. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/69bc00cb653e.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/69bc00cb653e.md deleted file mode 100644 index 9cdc516d..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/69bc00cb653e.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -kind: linear-project-document -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: Linear Integration And Dogfooding Spec -linearId: "256179ce-28aa-4bbd-b07e-d06fb9c32101" -slug: "69bc00cb653e" -archived: false -updatedAt: "2026-03-12T15:50:08.066Z" -sortOrder: 5251 ---- -## Goal - -Turn `hack linear` into a clear product-management surface and use it to manage Hack’s own planning workflow. - -## Product Promise - -Linear support should not feel like token plumbing. It should help users understand: - -* What account or profile is active. -* What team and project are bound. -* What work can be synced or managed. -* What next setup or repair step is needed. - -## UX Scope - -The primary flows are: - -* Connect and status. -* Project bind and routing. -* Sync issue or sync project. -* Autosync visibility and control. -* Project-management operations for docs, milestones, and status updates. - -## Dogfooding Requirement - -Hack should manage the Hack App Linear project itself. Specs should live as project documents. Stream planning should use milestones. Execution should use umbrella issues and child issues. Over time, this project should become the first real example of richer Hack-to-Linear project coordination. - -## Sync Direction - -Linear should sync against the normalized Hack Tickets core, not a separate ad hoc mapping layer. Status, dependencies, ownership, and provenance need explicit translation rules and conflict behavior. - -## Deliverables - -* Clear setup, bind, and status semantics. -* Support for project docs, milestones, and status updates. -* Better visibility into autosync, webhook, and delivery behavior. -* Dogfooded use of the new project from Hack itself. - -## Acceptance Criteria - -A user can connect Linear, understand the active binding, manage project docs and milestones, and sync work against normalized Hack Tickets without reverse engineering profile and routing internals. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/74a66d941bc4.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/74a66d941bc4.md deleted file mode 100644 index 533891c9..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/74a66d941bc4.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -kind: linear-project-document -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: "Runtime, Session, And Remote Beta Hardening Spec" -linearId: efcdf062-4a6d-4aa5-8c82-47cd70c23aee -slug: "74a66d941bc4" -archived: false -updatedAt: "2026-03-12T15:50:08.813Z" -sortOrder: 7185 ---- -## Goal - -Make the core runtime path more reliable while preserving advanced remote features behind clear beta boundaries. - -## Runtime Priorities - -* Restore a clean Docker Desktop path that does not assume Orbstack quirks. -* Detect runtime resets and broken proxy assumptions quickly. -* Improve crash capture, repair, and restart guidance. -* Make daemon-led recovery safer and more automatic where possible. - -## Session Priorities - -Sessions are important enough to deserve a more opinionated setup path. Hack should guide users toward a mux provider, use tmux as the default recommendation, and explain session semantics in terms of persistent project workspaces and agent workflows. - -## Beta Posture - -Remote control plane, multi-node, and related advanced flows remain in the same binary, but they must look beta in docs, help output, setup, and diagnostics. Users should know when they are leaving the core path. - -## Deliverables - -* Docker Desktop hardening and removal of fragile Orbstack assumptions from the primary path. -* Better daemon/runtime reset detection and auto-repair. -* Better crash capture and restart flows. -* Clear tmux-first session onboarding and semantics. -* Explicit beta labeling for remote and multi-node capabilities. - -## Acceptance Criteria - -Runtime failures are easier to diagnose and recover from, Docker Desktop-only users can succeed on the core path, and sessions plus beta remote flows feel intentional rather than incidental. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/81ac485e0ad4.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/81ac485e0ad4.md deleted file mode 100644 index eaa98e37..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/81ac485e0ad4.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -kind: linear-project-document -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: Portable Env And Secret Management Spec -linearId: d4746c14-d0a4-4d77-9ccc-252acfb17628 -slug: "81ac485e0ad4" -archived: false -updatedAt: "2026-03-12T15:50:08.487Z" -sortOrder: 6211 ---- -## Goal - -Define a project env model that is portable, explicit, and safe enough for local development and team sharing without turning Hack into a secrets-hosting service. - -## Target Model - -Projects should support a managed env file that can contain: - -* Plain values that may still be written to local `.env`-compatible files. -* Secret values that are encrypted when stored in the managed project artifact. -* Metadata describing purpose, secrecy, and service scope. - -## Sharing Model - -The default sharing posture is manual project-key registration. Users can share a project key with trusted collaborators, who can then decrypt and use the managed env set. This keeps Hack out of the business of centrally storing all project secrets by default. - -## Rotation And Recovery - -Key rotation must decrypt existing secret entries with the current key and re-encrypt them with the replacement key before cutover. The UX must make clear that losing the only valid key can brick encrypted env data unless users have intentionally stored a recovery path. - -## Compatibility - -Existing `.env` workflows must continue to work. `hack env` should clearly show what is plain, what is secret, which backend is active, and what trust model is in effect. - -## Deliverables - -* Portable project env file design. -* Secret and non-secret entry semantics. -* Manual key registration and sharing flow. -* Safe key rotation flow. -* Recovery and lost-key guidance. - -## Acceptance Criteria - -Users can manage env state through Hack without accidentally committing secrets, rotate keys safely, and understand the tradeoffs between local plaintext compatibility and encrypted portable project state. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/c876e9cfb691.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/c876e9cfb691.md deleted file mode 100644 index 784bac99..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/c876e9cfb691.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -kind: linear-project-document -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: Hack App Program Overview -linearId: f9af6c88-c732-4daa-9ebb-93142445b7c4 -slug: c876e9cfb691 -archived: false -updatedAt: "2026-03-12T15:52:32.765Z" -sortOrder: 26.81 ---- -# Hack App Curation And Hardening Program - -## Direction - -Hack remains a balanced platform, but the public story must become easier to digest. The primary user value is local orchestration plus the adjacent workflows that make that orchestration useful day to day: sessions, tickets, integrations, and env management. Remote control plane, multi-node, and the macOS app remain supported, but they are beta surfaces and should be presented that way everywhere user-facing. - -## Core Promises - -* Run projects in parallel. -* Normalize all your tickets. -* Manage project env safely. - -## Beta Surfaces - -* Remote control plane and gateway-driven access. -* Multi-node and remote execution flows. -* Hack Desktop for macOS. - -## Execution Model - -This project uses milestones for streams, project documents for specs, and umbrella issues plus child issues for implementation work. New work starts in `Backlog`; only the active stream umbrella moves forward. The project itself should become the first dogfooded example of richer Hack to Linear coordination over time. - -## Delivery Streams - -* Core offer and docs information architecture. -* CLI UX and guided setup. -* GitHub capability expansion. -* Tickets normalization core. -* Linear integration and dogfooding. -* Env portability and secret management. -* Runtime, sessions, and remote beta hardening. -* Teams and organizations management. -* Agent-native runtime R&D. - -## Non-Goals - -* No full rewrite of Hack. -* No rollback of Cloudflare or Tailwind-related extension work. -* No attempt to make beta surfaces look production-complete before their UX and recovery paths are ready. - -## Program Success Criteria - -* A new user with Bun and Docker Desktop can get productive through guided setup. -* README, help, and docs clearly separate core and beta capabilities. -* GitHub and Linear integrations explain what they enable before asking for auth. -* Hack Tickets evolves into the normalized issue core for local-first and integrated workflows. -* Env management becomes portable and explicit about trust, sharing, rotation, and recovery. -* Runtime and session failures produce actionable repair paths instead of ambiguous breakage. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/ca365d300381.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/ca365d300381.md deleted file mode 100644 index 4212c72a..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/ca365d300381.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -kind: linear-project-document -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: Core Platform Positioning And Docs IA -linearId: edaa289a-1b77-45a7-b614-db7230f19c79 -slug: ca365d300381 -archived: false -updatedAt: "2026-03-12T15:49:33.581Z" -sortOrder: 1109 ---- -## Goal - -Make Hack easier to understand in under five minutes without shrinking the product. The top-level presentation should explain the main promise, the adjacent capabilities that support it, and the beta surfaces that are available but not yet the default path. - -## Product Language - -The primary message should lead with three promises: - -* Run projects in parallel. -* Normalize all your tickets. -* Manage project env safely. - -Sessions and integrations are first-class supporting capabilities because they materially improve those promises. Remote control plane, multi-node, and the macOS app are still part of Hack, but they must be labeled beta in the README, help output, install flows, and docs navigation. - -## Information Architecture - -The root README should explain: - -1. What Hack is. -2. Why it exists. -3. The three core promises. -4. Core commands and first-run path. -5. A short integrations overview. -6. Beta capabilities with links out. - -Docs navigation should separate: - -* Core: project orchestration, sessions, tickets, env, integrations. -* Beta: remote control plane, multi-node, macOS app. -* Extensions/reference: Cloudflare, Tailscale, SDK, gateway API. - -## Command Taxonomy - -The CLI should keep `hack` as the main entrypoint, but command descriptions and help groups should tell the truth about capability level. Core commands should be easy to find. Advanced or beta commands should explicitly say so. - -## Deliverables - -* Rewritten root README and docs landing page. -* Clear command grouping and help summaries. -* Plain-language integrations overview. -* Explicit beta labeling and linked docs for advanced surfaces. - -## Acceptance Criteria - -A new user can scan the README or `hack help` and understand the core product, know where beta starts, and know what GitHub, Linear, tickets, sessions, and env are for without reading architecture docs. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/ceaec591ed73.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/ceaec591ed73.md deleted file mode 100644 index 91d53feb..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/ceaec591ed73.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -kind: linear-project-document -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: Tickets Normalization And Storage Spec -linearId: df7c847f-1c0d-4674-b9c4-2b72e39e75e0 -slug: ceaec591ed73 -archived: false -updatedAt: "2026-03-12T15:49:35.745Z" -sortOrder: 4342 ---- -## Goal - -Make Hack Tickets the canonical normalized issue model that can power local-first workflows while syncing cleanly with external systems. - -## Target Model - -Hack Tickets should remain portable and git-friendly, but no longer depend on a purely in-memory projection of an append-only git log. The target architecture is: - -* Append-only journal and durable history. -* SQLite-backed local projection for fast reads, indexing, and extensibility. -* Git-backed portability through hidden ref sync. -* External-link and provenance metadata for Linear, GitHub, Asana, and future sources. - -## Required Capabilities - -* Rebuild projection deterministically from journal state. -* Support idempotent repeated event application across multiple machines. -* Handle multi-writer sync without duplicating or corrupting state. -* Preserve source lineage and authority decisions for external sync. -* Add first-class markdown-backed ticket documents or spec attachments. - -## Sync Posture - -Hack Tickets is the normalized core, not a thin wrapper. Adapters map in and out of Linear, GitHub, Asana, and other sources while preserving provenance and conflict state. - -## Storage Direction - -Git remains the durable portable layer. SQLite becomes the operational read and sync engine. Journal entries must be replayable, inspectable, and safe to sync repeatedly. - -## Acceptance Criteria - -Tickets can be created, queried, rebuilt, and synced without loss of history. External source changes can be applied idempotently. Multi-machine users converge on the same normalized state, and richer document/spec associations become possible without abandoning markdown portability. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/d88a385d8a14.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/d88a385d8a14.md deleted file mode 100644 index 8b7907f0..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/d88a385d8a14.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -kind: linear-project-document -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: GitHub Integration Product Spec -linearId: "79ea4182-5de7-4296-8ff6-e7fb5d581655" -slug: d88a385d8a14 -archived: false -updatedAt: "2026-03-12T15:49:35.314Z" -sortOrder: 3293 ---- -## Goal - -Reframe GitHub from an implementation detail of multi-node work into a broadly useful capability layer for Hack. - -## Product Promise - -When a user installs and connects the GitHub integration, Hack should be able to help with: - -* Code reviews. -* PR creation and updates. -* Review comments and discussion follow-up. -* Repo-aware sync and metadata flows. -* Other repo actions that benefit from a trusted GitHub identity. - -## UX Expectations - -Users should understand what the integration enables before being asked to authenticate. `connect`, `status`, and setup output should describe capabilities, current bindings, and any missing permissions in plain language. - -## Command Scope - -The GitHub surface should grow from auth/profile management into capability-led workflows. Profile support can stay, but it should feel like implementation detail in support of user goals. - -## Delivery Areas - -* Better setup/install language around the GitHub app. -* Clear status output for connection health, active profile, accessible repos or installations, and enabled capabilities. -* Project or repo binding semantics where that reduces ambiguity. -* Documentation and help content that explains outcomes, not just token storage. - -## Acceptance Criteria - -A user can answer three questions from CLI output alone: what GitHub unlocks, what account or installation is active, and what next action is available. The integration should clearly support review, PR update, and comment-oriented workflows without feeling tied only to remote-node plumbing. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/f96a7ec3a4f4.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/f96a7ec3a4f4.md deleted file mode 100644 index 9c166395..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/f96a7ec3a4f4.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -kind: linear-project-document -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: CLI UX And Guided Setup Spec -linearId: "78e5b6e2-d948-473f-bdc5-8a1cbcf45b9e" -slug: f96a7ec3a4f4 -archived: false -updatedAt: "2026-03-12T15:49:33.903Z" -sortOrder: 2201 ---- -## Goal - -Reduce failed first runs and command confusion by making Hack detect missing prerequisites, explain dependencies, and guide users into the correct next step. - -## Core Principles - -* Commands should fail informatively, not cryptically. -* Missing prerequisites should be surfaced with the exact fix. -* The CLI should prefer guided flows over leaving users to discover setup docs after a failure. -* Auth and profile requirements for integrations must be explicit before work is attempted. - -## Guided Setup Scope - -Hack should guide setup for: - -* Docker runtime compatibility and global install prerequisites. -* Mux provider installation and default selection, with tmux as the guided default. -* GitHub integration installation and account binding. -* Linear integration connection, project bind, and team/project routing. - -## Surface Cleanup - -Top-level commands should feel canonical and non-overlapping. `hack`, `hack x`, and auth/profile flows should have a clearer story so users know when they are in a core path versus an extension or beta path. - -## Output Contract - -Status, help, and error messages should answer: - -* What went wrong. -* What prerequisite is missing. -* Why the command needed it. -* What exact next command to run. - -## Deliverables - -* Prerequisite detection and interception rules. -* Guided setup flows for Docker, mux, GitHub, and Linear. -* Clearer help text and status output for profiles, teams, and projects. -* Reduced cognitive overlap between main command surfaces. - -## Acceptance Criteria - -A new user with Bun and Docker Desktop can follow guided output to a working project run. An existing user hitting a missing GitHub, Linear, or mux requirement sees an actionable next step instead of guessing at docs or config. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/fa12cc05df6b.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/fa12cc05df6b.md deleted file mode 100644 index 2e3178c3..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/fa12cc05df6b.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -kind: linear-project-document -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: Web Control Plane UI System -linearId: "3980ba9d-2607-4c51-bc75-8c051d867d8e" -slug: fa12cc05df6b -archived: false -updatedAt: "2026-03-24T17:26:21.800Z" -sortOrder: 12348 ---- -# Web Control Plane UI System - -## Required Stack - -* Tailwind CSS v4 -* `shadcn/ui` -* Kibo UI patterns and additional components where they improve the admin surface -* Motion for React for subtle, accessible micro-interactions - -## Usage Rules - -Use `shadcn/ui` as the base primitive layer. Use Kibo UI selectively for richer composed admin patterns, not as a bulk dependency dump. - -Use Motion for: - -* drawers, dialogs, and sheet transitions -* optimistic state changes -* small selection and emphasis transitions -* layout changes that help orientation - -Do not use Motion for: - -* decorative dashboard churn -* large page animations -* interactions that obscure state changes - -## Accessibility Rules - -* respect reduced-motion preferences -* preserve semantic structure and keyboard interaction -* keep contrast, focus states, and loading states explicit - -## Design Goal - -The app should feel like a calm product control plane, not a flashy demo site. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/fb6b7a6ab148.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/fb6b7a6ab148.md deleted file mode 100644 index 0ff3a1da..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/documents/fb6b7a6ab148.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -kind: linear-project-document -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: Teams And Organizations Admin Spec -linearId: f725fcc0-fcbe-4eda-a5a9-4e69d74d2591 -slug: fb6b7a6ab148 -archived: false -updatedAt: "2026-03-12T15:50:09.147Z" -sortOrder: 8272 ---- -## Goal - -Make Hack able to manage teams and organizations in a way that is explicit, secure by default, and consistent with project access and env sharing. - -## Required Operations - -* Create a team or organization. -* Invite or add members. -* Remove members. -* Adjust roles. -* Control project access and ownership. - -## Security Model - -Administrative operations should make the trust boundary obvious. The design must distinguish: - -* What can be managed locally. -* What requires broker or remote service support. -* Which actions affect shared secrets or project env access. - -## Integration Points - -Team and org semantics should connect to: - -* Project ownership. -* Shared env key distribution. -* Future project-level collaboration and audit flows. - -## Deliverables - -* Team and org command semantics. -* Role model and access-control rules. -* Member lifecycle UX. -* Clear relationship to env sharing and project administration. - -## Acceptance Criteria - -A user can understand how teams and organizations map to project ownership and shared operations, and admin actions are explicit enough to avoid accidental privilege or secret exposure. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/agent-native-runtime-r-d.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/agent-native-runtime-r-d.md deleted file mode 100644 index 446d3a86..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/agent-native-runtime-r-d.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -kind: linear-project-milestone -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: "Agent-Native Runtime R&D" -linearId: "52c77839-97bd-4455-8ffb-b909afdfb3a7" -slug: agent-native-runtime-r-d -archived: false -updatedAt: "2026-03-12T15:48:46.365Z" -state: unstarted -sortOrder: 7798 ---- -Run an active research and specification stream for a future agent-native container runtime, separate from the current CLI hardening roadmap. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/cli-ux-and-guided-setup.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/cli-ux-and-guided-setup.md deleted file mode 100644 index 349a2fc9..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/cli-ux-and-guided-setup.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -kind: linear-project-milestone -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: CLI UX And Guided Setup -linearId: f6c715e4-4c46-412a-bcbf-d2958d5e9142 -slug: cli-ux-and-guided-setup -archived: false -updatedAt: "2026-03-12T15:48:43.925Z" -state: done -sortOrder: 918 ---- -Improve prerequisite detection, command guidance, setup interception, and top-level command semantics so Hack is easier to install and operate successfully. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/core-offer-and-information-architecture.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/core-offer-and-information-architecture.md deleted file mode 100644 index 9b4bdd58..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/core-offer-and-information-architecture.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -kind: linear-project-milestone -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: Core Offer And Information Architecture -linearId: "8c97019b-a4f9-4cc7-9af6-869592102677" -slug: core-offer-and-information-architecture -archived: false -updatedAt: "2026-03-12T15:48:43.607Z" -state: done -sortOrder: 8 ---- -Clarify the top-level Hack story, docs IA, README, and command taxonomy so the product is easier to understand and beta capabilities are clearly separated from the core offer. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/env-portability-and-secret-management.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/env-portability-and-secret-management.md deleted file mode 100644 index 3d00e445..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/env-portability-and-secret-management.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -kind: linear-project-milestone -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: Env Portability And Secret Management -linearId: "055747f7-a3d1-4f53-9361-bf5db87a8f24" -slug: env-portability-and-secret-management -archived: false -updatedAt: "2026-03-12T15:48:44.979Z" -state: done -sortOrder: 4906 ---- -Define a portable project env model with encrypted secrets, rotation, local compatibility, and clear sharing semantics. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/github-capability-expansion.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/github-capability-expansion.md deleted file mode 100644 index 09d6c777..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/github-capability-expansion.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -kind: linear-project-milestone -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: GitHub Capability Expansion -linearId: af64b734-8254-4d41-a44f-9ce0dd7a881b -slug: github-capability-expansion -archived: false -updatedAt: "2026-03-12T15:48:44.153Z" -state: next -sortOrder: 1991 ---- -Reposition GitHub as a general capability unlock for reviews, PR updates, comments, sync, and repo-aware workflows rather than just multi-node plumbing. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/linear-integration-and-dogfooding.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/linear-integration-and-dogfooding.md deleted file mode 100644 index b6f93adc..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/linear-integration-and-dogfooding.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -kind: linear-project-milestone -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: Linear Integration And Dogfooding -linearId: "54cb0e65-3bb3-4d80-bc29-9d255934b4dc" -slug: linear-integration-and-dogfooding -archived: false -updatedAt: "2026-03-12T15:48:44.677Z" -state: unstarted -sortOrder: 3935 ---- -Make Hack’s Linear integration clearer and more capable, then use it to manage this Hack App project, docs, milestones, and synced work. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/optional-web-control-plane.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/optional-web-control-plane.md deleted file mode 100644 index 69d0302f..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/optional-web-control-plane.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -kind: linear-project-milestone -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: Optional Web Control Plane -linearId: ab9a91c4-9de7-47fe-82f7-542ea8237684 -slug: optional-web-control-plane -archived: false -updatedAt: "2026-03-24T17:26:17.761Z" -state: unstarted -sortOrder: 8768 ---- -Add an optional Next.js control plane on Vercel for account management, teams and orgs, project registration, integration setup, and env or secret-sharing workflows, while keeping Hack fully usable without the app. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/runtime-sessions-and-remote-beta-hardening.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/runtime-sessions-and-remote-beta-hardening.md deleted file mode 100644 index bde4417b..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/runtime-sessions-and-remote-beta-hardening.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -kind: linear-project-milestone -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: "Runtime, Sessions, And Remote Beta Hardening" -linearId: "46912d43-991c-4fbf-9a7a-c5ca9632a9db" -slug: runtime-sessions-and-remote-beta-hardening -archived: false -updatedAt: "2026-03-12T15:48:45.207Z" -state: unstarted -sortOrder: 5851 ---- -Harden Docker runtime compatibility, session semantics, crash recovery, and beta remote flows while keeping advanced surfaces supported but clearly labeled. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/teams-and-organizations-management.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/teams-and-organizations-management.md deleted file mode 100644 index 29d0c7b7..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/teams-and-organizations-management.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -kind: linear-project-milestone -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: Teams And Organizations Management -linearId: aca1b0b4-ef42-4ba8-910d-938e677578f9 -slug: teams-and-organizations-management -archived: false -updatedAt: "2026-03-12T15:48:45.648Z" -state: unstarted -sortOrder: 6866 ---- -Add secure-by-default team and organization management flows that connect identity, roles, project access, and shared env operations. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/tickets-normalization-core.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/tickets-normalization-core.md deleted file mode 100644 index 9ea98b58..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/milestones/tickets-normalization-core.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -kind: linear-project-milestone -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: Tickets Normalization Core -linearId: db8eb1ae-a093-489d-bf84-83a941c27616 -slug: tickets-normalization-core -archived: false -updatedAt: "2026-03-12T15:48:44.394Z" -state: done -sortOrder: 2910 ---- -Evolve Hack Tickets into the canonical normalized issue model with durable local projection, provenance, external adapters, and idempotent multi-writer sync. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/status-updates/published/2026-03-24-mission-freeze-optional-web-control-plane.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/status-updates/published/2026-03-24-mission-freeze-optional-web-control-plane.md deleted file mode 100644 index 44c505ce..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/status-updates/published/2026-03-24-mission-freeze-optional-web-control-plane.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -kind: linear-project-status-update -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: Mission freeze for optional web control plane -linearId: "5c842fc1-164f-4f1e-b4bf-d7305ca1133b" -slug: mission-freeze-optional-web-control-plane -archived: false -updatedAt: "2026-03-25T15:08:58.123Z" -date: "2026-03-24" -publishedAt: "2026-03-25T15:08:58.123Z" -health: onTrack ---- -## Summary - -Seeded the frozen mission closeout scope and created the missing optional-web-control-plane issue hierarchy under the bound Hack Linear project. - -## Open at mission start - -- HACK-457 — Dogfood the Hack App Linear project through Hack-native planning and sync flows -- HACK-458 — Improve autosync, webhook delivery, and operator visibility for Linear sync -- HACK-463 — Harden the Docker Desktop primary path and remove fragile Orbstack assumptions -- HACK-470 — Connect team and organization administration to env sharing and project ownership -- HACK-471 — Separate local-only versus broker or cloud-mediated admin operations -- HACK-474 — Define the proposed runtime architecture, interfaces, and build-versus-borrow boundaries -- HACK-475 — Produce a separation plan so runtime R&D informs but does not block the current hardening roadmap -- HACK-558 — Support multiline env values in Hack plaintext env workflow - -## Mission-created optional web control plane hierarchy - -- HACK-559 — Optional web control plane delivery tracker - - HACK-560 — Shared auth and web foundation - - HACK-561 — Org, team, and project administration - - HACK-562 — GitHub and Linear integration management - - HACK-563 — Env status, CLI optionality, and closeout - -## Audit notes - -- The authoritative frozen scope lives in `linear-closeout-scope.json` in the mission directory. -- Repo-bound project documents and milestones were pulled into `.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/` so later workers can use canonical artifacts instead of legacy paths. \ No newline at end of file diff --git a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/status-updates/published/2026-03-25-mission-closeout-audit.md b/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/status-updates/published/2026-03-25-mission-closeout-audit.md deleted file mode 100644 index d0cd1b1d..00000000 --- a/.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/status-updates/published/2026-03-25-mission-closeout-audit.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -kind: linear-project-status-update -linearProjectId: "7a3c8adf-ede5-4d3a-8779-9c32695c76bf" -title: Mission closeout audit -linearId: "93e622be-21df-4665-a72f-e796e9c8e3f2" -slug: mission-closeout-audit -archived: false -updatedAt: "2026-03-25T20:36:19.417Z" -date: "2026-03-25" -publishedAt: "2026-03-25T20:36:19.417Z" -health: onTrack ---- -## Summary - -Closed the frozen mission-scoped Hack Linear work set to zero unresolved items in the repo-bound ticket substrate and surfaced the same closeout state through the CLI and web control plane audit views. - -## Evidence - -- Frozen scope: `.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/closeout-scope.json` -- Repo-bound status: `./dist/hack linear status --json` -- Delivery reconciliation: `.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/delivery-audit.json` -- Freeze baseline: `.hack/linear/projects/7a3c8adf-ede5-4d3a-8779-9c32695c76bf/status-updates/published/2026-03-24-mission-freeze-optional-web-control-plane.md` - -## Reconciled scope - -- HACK-457 — done -- HACK-458 — done -- HACK-463 — done -- HACK-470 — done -- HACK-471 — done -- HACK-474 — done -- HACK-475 — done -- HACK-558 — done -- HACK-559 — done - - HACK-560 — done - - HACK-561 — done - - HACK-562 — done - - HACK-563 — done \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index aae2b66d..254a0543 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -358,3 +358,16 @@ Agent setup (CLI-first): - MCP (no-shell only): `hack setup mcp` - MCP install (explicit): `hack mcp install --all --scope project` + +## Learned User Preferences + +- Prefer Tailwind utilities and shadcn components for auth and similar UI instead of bespoke CSS class stacks such as `.auth-*` when utilities can express the same layout and states. +- After substantive `apps/web` UI changes, verify in a real browser and check the console for runtime warnings. +- When running shadcn CLI init or updates in `apps/web`, merge generated output with existing providers, registries, and project-specific styles rather than overwriting custom shell or auth wiring. + +## Learned Workspace Facts + +- Better Auth runs in `services/auth-broker`, not inside the Next app. Browser GitHub sign-in uses a `redirect_uri` on the **auth broker** host (for example `auth..hack.gy`), not on the primary web app host (`.hack.gy`). +- On the auth broker host this repo may use two GitHub callback paths: Better Auth at `/api/auth/callback/github` and the broker custom flow at `/gh/callback`. The GitHub OAuth app must allow the exact `redirect_uri` emitted in the live authorize request. +- Keep `services/auth-broker` as the auth authority (sessions, provider callbacks, CLI-related flows); treat `apps/web` as browser UX and thin BFF/proxy. See `docs/guides/auth-broker-callbacks.md` for callback and handoff wording. +- `apps/web` theme switching uses a small custom theme context plus layout bootstrap rather than `next-themes` `ThemeProvider`, to avoid Next.js 16 / React client warnings about ` + {children} + + + ); +} diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx new file mode 100644 index 00000000..b8a63720 --- /dev/null +++ b/apps/web/src/app/page.tsx @@ -0,0 +1,13 @@ +import { BigLogo } from "@/components/big-logo"; +import { MarketingChrome } from "@/components/marketing-chrome"; + +export default function HomePage() { + return ( +
+ +
+ +
+
+ ); +} diff --git a/apps/web/src/app/providers.tsx b/apps/web/src/app/providers.tsx new file mode 100644 index 00000000..0f359d8e --- /dev/null +++ b/apps/web/src/app/providers.tsx @@ -0,0 +1,14 @@ +"use client"; + +import type { ReactNode } from "react"; + +import { ThemeProvider } from "@/components/theme-provider"; +import { TooltipProvider } from "@/components/ui/tooltip"; + +export function Providers({ children }: { readonly children: ReactNode }) { + return ( + + {children} + + ); +} diff --git a/apps/web/src/components/account-control-plane-sections.tsx b/apps/web/src/components/account-control-plane-sections.tsx index 2c7d0fee..03835f4b 100644 --- a/apps/web/src/components/account-control-plane-sections.tsx +++ b/apps/web/src/components/account-control-plane-sections.tsx @@ -1,12 +1,12 @@ import type { ReactNode } from "react"; -import LinearManagementSection from "@/src/components/linear-management-section"; -import type { AccountControlPlaneFeedback } from "@/src/lib/account-control-plane"; -import { buildAccountControlPlanePath } from "@/src/lib/account-control-plane"; -import type { AccountShellContext } from "@/src/lib/account-shell"; -import type { EnvManagementState } from "@/src/lib/env-management"; -import type { GitHubManagementState } from "@/src/lib/github-management"; -import type { LinearManagementState } from "@/src/lib/linear-management"; -import { cn } from "@/src/lib/utils"; +import LinearManagementSection from "@/components/linear-management-section"; +import type { AccountControlPlaneFeedback } from "@/lib/account-control-plane"; +import { buildAccountControlPlanePath } from "@/lib/account-control-plane"; +import type { AccountShellContext } from "@/lib/account-shell"; +import type { EnvManagementState } from "@/lib/env-management"; +import type { GitHubManagementState } from "@/lib/github-management"; +import type { LinearManagementState } from "@/lib/linear-management"; +import { cn } from "@/lib/utils"; const sectionSurfaceClassName = cn( "rounded-3xl border border-white/10 bg-white/[0.04] shadow-[0_24px_80px_rgba(15,23,42,0.24)]", diff --git a/apps/web/src/components/account-page-frame.tsx b/apps/web/src/components/account-page-frame.tsx new file mode 100644 index 00000000..589dfb4f --- /dev/null +++ b/apps/web/src/components/account-page-frame.tsx @@ -0,0 +1,91 @@ +import type { ReactNode } from "react"; + +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; + +export function AccountPageFrame(input: { + readonly title: string; + readonly description: string; + readonly children: ReactNode; +}) { + return ( +
+
+

+ {input.title} +

+

+ {input.description} +

+
+ {input.children} +
+ ); +} + +export function AccountSectionCard(input: { + readonly title: string; + readonly description?: string; + readonly action?: ReactNode; + readonly children: ReactNode; +}) { + return ( + + +
+
+ {input.title} + {input.description ? ( + {input.description} + ) : null} +
+ {input.action ?
{input.action}
: null} +
+
+ {input.children} +
+ ); +} + +export function AccountEmptyState(input: { + readonly title: string; + readonly body: string; +}) { + return ( +
+

{input.title}

+

{input.body}

+
+ ); +} + +export function AccountStatsGrid(input: { + readonly items: readonly { + readonly label: string; + readonly value: string; + readonly hint?: string; + }[]; +}) { + return ( +
+ {input.items.map((item) => ( +
+
+ {item.label} +
+
+ {item.value} +
+ {item.hint ? ( +

{item.hint}

+ ) : null} +
+ ))} +
+ ); +} diff --git a/apps/web/src/components/account-shell-loading.tsx b/apps/web/src/components/account-shell-loading.tsx index 178d68ef..91152d4b 100644 --- a/apps/web/src/components/account-shell-loading.tsx +++ b/apps/web/src/components/account-shell-loading.tsx @@ -1,7 +1,7 @@ import { Compass } from "lucide-react"; -import { shellSummary, shellTitle } from "@/src/lib/control-plane-shell"; -import { cn } from "@/src/lib/utils"; +import { shellSummary, shellTitle } from "@/lib/control-plane-shell"; +import { cn } from "@/lib/utils"; const loadingSurfaceClassName = cn( "rounded-3xl border border-white/10 bg-white/[0.04] shadow-[0_24px_80px_rgba(15,23,42,0.24)]", @@ -14,11 +14,6 @@ const loadingPlaceholderClassName = export default function AccountShellLoading() { return (
- + {mode === "account" ? ( + + + + ) : null} +
); } +function resolveProviderGate(input: { + readonly betterAuthSource: "broker" | "fail_closed"; + readonly betterAuthEnabled: boolean; + readonly providerCount: number; +}): { readonly title: string; readonly body: string } | null { + if (input.betterAuthSource === "fail_closed") { + return { + title: "Cannot reach the auth broker", + body: "Start your stack with Hack (for example `hack up`), then open this site using your Hack dev hostname (for example https://hack-cli.hack), not raw localhost, so the app can reach the broker.", + }; + } + if (!input.betterAuthEnabled) { + return { + title: "Better Auth is not active", + body: "The broker is reachable but Better Auth is off. Ensure DATABASE_URL and BETTER_AUTH_SECRET are set for the auth-broker service, then restart it.", + }; + } + if (input.providerCount === 0) { + return { + title: "No OAuth providers", + body: "GitHub client credentials are not configured on the broker. Set GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET (or BETTER_AUTH_GITHUB_*), redeploy the broker, and add your callback URL to the GitHub OAuth app.", + }; + } + return null; +} + +function authPanelClassName( + tone: "neutral" | "info" | "success" | "danger" | "muted" +): string { + return cn( + "grid gap-2 rounded-xl border p-4", + tone === "neutral" && "border-border bg-muted/40", + tone === "info" && + "border-sky-500/30 bg-sky-500/10 dark:border-sky-400/25 dark:bg-sky-400/10", + tone === "success" && + "border-emerald-500/35 bg-emerald-500/10 dark:border-emerald-400/30 dark:bg-emerald-400/10", + tone === "danger" && "border-destructive/40 bg-destructive/10", + tone === "muted" && "border-border bg-muted/25" + ); +} + function resolveSummary(input: { readonly mode: "sign-in" | "account"; readonly hasFlowContext: boolean; - readonly authBrokerBaseUrl: string; }): { readonly title: string; readonly body: string } { if (input.mode === "account") { return { title: "Finish your Hack browser handoff", body: input.hasFlowContext ? "Hack will poll the broker-backed session flow here while the browser completes sign-in." - : `Use this route to resume broker-backed auth handoff or continue account management via ${input.authBrokerBaseUrl}.`, + : "Use this route to complete browser sign-in and manage your Hack session.", }; } return { - title: "Sign in to Hack", + title: "", body: input.hasFlowContext - ? "This sign-in request came from Hack. Continue with a provider to finish the CLI and browser handoff." - : "Start a shared Hack session in the browser while keeping the broker as the source of truth for auth and session APIs.", + ? "This browser tab is linked to a Hack client flow. Authorize GitHub to finish the handoff." + : "", }; } -function buildAuthRouteHref(input: { - readonly mode: "sign-in" | "account"; +function buildAuthPageHref(input: { readonly flowId?: string; readonly deviceCode?: string; readonly redirect: string | null; }): string { - const path = input.mode === "sign-in" ? "/auth" : "/auth/account"; const searchParams = new URLSearchParams(); if (input.flowId) { searchParams.set("flowId", input.flowId); @@ -408,7 +512,7 @@ function buildAuthRouteHref(input: { searchParams.set("redirect", input.redirect); } const query = searchParams.toString(); - return query.length > 0 ? `${path}?${query}` : path; + return query.length > 0 ? `/auth?${query}` : "/auth"; } function buildFlowStatusUrl(input: { @@ -457,6 +561,7 @@ function createFlowErrorState(input: { function resolveFlowStatus(input: { readonly flowState: FlowState; + readonly hasFlowContext: boolean; readonly normalizedRedirect: string | null; }): { readonly title: string; @@ -475,17 +580,28 @@ function resolveFlowStatus(input: { }; } if (input.flowState.kind === "ready" || input.flowState.kind === "claimed") { + const title = + input.hasFlowContext || input.normalizedRedirect + ? "Browser handoff confirmed" + : "Signed in to Hack"; + let body = + "Your browser session is active. You can close this tab or start another sign-in."; + if (input.normalizedRedirect) { + body = + "The broker established the session. Return to Hack when you are ready."; + } else if (input.hasFlowContext) { + body = + "The broker established the session. You can close this tab when you are done."; + } return { - title: "Browser handoff confirmed", - body: input.normalizedRedirect - ? "The broker established the session. Return to Hack when you are ready." - : "The broker established the session. You can close this tab when you are done.", + title, + body, tone: "success", statusText: input.normalizedRedirect && shouldAutoNavigateToReturnUrl({ value: input.normalizedRedirect }) ? "Returning to Hack…" - : "Broker-backed session confirmed.", + : title, ...(input.normalizedRedirect ? { href: input.normalizedRedirect, diff --git a/apps/web/src/components/big-logo.tsx b/apps/web/src/components/big-logo.tsx new file mode 100644 index 00000000..df2c281f --- /dev/null +++ b/apps/web/src/components/big-logo.tsx @@ -0,0 +1,145 @@ +export function BigLogo({ className }: { className?: string }) { + return ( + + Hack logo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/apps/web/src/components/control-plane-shell.tsx b/apps/web/src/components/control-plane-shell.tsx index 2894cb80..a34e7ac7 100644 --- a/apps/web/src/components/control-plane-shell.tsx +++ b/apps/web/src/components/control-plane-shell.tsx @@ -1,7 +1,7 @@ import { ArrowRight, Compass, Keyboard, ShieldCheck } from "lucide-react"; -import AccountControlPlaneSections from "@/src/components/account-control-plane-sections"; -import type { AccountControlPlaneFeedback } from "@/src/lib/account-control-plane"; -import type { AccountShellContext } from "@/src/lib/account-shell"; +import AccountControlPlaneSections from "@/components/account-control-plane-sections"; +import type { AccountControlPlaneFeedback } from "@/lib/account-control-plane"; +import type { AccountShellContext } from "@/lib/account-shell"; import { shellGuardrails, shellHighlights, @@ -9,11 +9,11 @@ import { shellPrinciples, shellSummary, shellTitle, -} from "@/src/lib/control-plane-shell"; -import type { EnvManagementState } from "@/src/lib/env-management"; -import type { GitHubManagementState } from "@/src/lib/github-management"; -import type { LinearManagementState } from "@/src/lib/linear-management"; -import { cn } from "@/src/lib/utils"; +} from "@/lib/control-plane-shell"; +import type { EnvManagementState } from "@/lib/env-management"; +import type { GitHubManagementState } from "@/lib/github-management"; +import type { LinearManagementState } from "@/lib/linear-management"; +import { cn } from "@/lib/utils"; const interactiveSurfaceClassName = cn( "rounded-3xl border border-white/10 bg-white/[0.04] shadow-[0_24px_80px_rgba(15,23,42,0.24)]", @@ -132,11 +132,6 @@ export default function ControlPlaneShell({ return (
-