Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
edd13da
feat(console): complete trusted publication operations UI
XnLemon Jul 26, 2026
efe6352
test(console): add browser acceptance harness
XnLemon Jul 26, 2026
7e1cc53
fix(console): close browser acceptance review gaps
XnLemon Jul 26, 2026
a1307a0
test(console): assert browser error and stream correlation
XnLemon Jul 27, 2026
decff64
ci(console): approve esbuild build scripts
XnLemon Jul 27, 2026
fa6b0e8
fix(console): associate registry authentication field
XnLemon Jul 27, 2026
2619759
fix(console): expose exact authentication field label
XnLemon Jul 27, 2026
1999502
fix(console): expose capabilities field label
XnLemon Jul 27, 2026
cc4e59e
fix(console): expose agent id in registry rows
XnLemon Jul 27, 2026
134da19
test(e2e): respect release lifecycle state
XnLemon Jul 27, 2026
a3fe9f5
test(e2e): read release provenance from facts
XnLemon Jul 27, 2026
6f4b112
test(e2e): wait for published agent options
XnLemon Jul 27, 2026
0f37c2b
test(e2e): align runtime fixture identities
XnLemon Jul 27, 2026
7ba486f
test(e2e): assert owner discovery provenance
XnLemon Jul 27, 2026
c8f11df
test(e2e): expose catalog option diagnostics
XnLemon Jul 27, 2026
182478a
test(e2e): include select state on readiness failure
XnLemon Jul 27, 2026
608a023
test(e2e): preserve select locator failures
XnLemon Jul 27, 2026
9b9730c
test(e2e): assert installation selector readiness
XnLemon Jul 27, 2026
a9a76aa
test(e2e): capture installation DOM state
XnLemon Jul 27, 2026
05f6d38
fix(console): associate installation agent label
XnLemon Jul 27, 2026
5aa3cf2
fix(console): associate trusted release label
XnLemon Jul 27, 2026
86fc4c7
test(e2e): use streaming runtime fixture
XnLemon Jul 27, 2026
f1ee0a7
fix(console): associate ledger labels
XnLemon Jul 27, 2026
f7c77b5
docs(console): document platform import ownership
XnLemon Jul 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# NeKiro Control Plane Northbound API configuration.
VITE_NEKIRO_API_BASE_URL="http://127.0.0.1:18080"
VITE_NEKIRO_TOKEN=""
VITE_NEKIRO_OWNER_ID=""
VITE_NEKIRO_OWNER_NAME=""
# NeKiro public Gateway configuration. Every value must be supplied explicitly.
VITE_NEKIRO_API_BASE_URL=""
VITE_NEKIRO_PROVIDER_ID=""
VITE_NEKIRO_PROVIDER_NAME=""
VITE_NEKIRO_PROVIDER_TOKEN=""
VITE_NEKIRO_OWNER_TOKEN=""
VITE_NEKIRO_DEFAULT_WORKSPACE_ID=""
150 changes: 150 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
name: Console CI

on:
push:
pull_request:

permissions:
contents: read

jobs:
frontend:
runs-on: ubuntu-latest
timeout-minutes: 15

steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 11.3.0
run_install: false

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 24.16.0
cache: pnpm
cache-dependency-path: pnpm-lock.yaml

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Typecheck
run: pnpm run typecheck

- name: Test
run: pnpm run test

- name: Build
run: pnpm run build

browser-acceptance:
needs: frontend
runs-on: ubuntu-latest
timeout-minutes: 40
env:
# Deterministic CI-only fixtures. These credentials and signing values
# are never used as production configuration or emitted as artifacts.
POSTGRES_USER: nekiro_acceptance
POSTGRES_PASSWORD: acceptance-only-password
POSTGRES_DB: nekiro_acceptance
POSTGRES_PORT: "55432"
CONTROL_PLANE_PORT: "18080"
A2A_ROUTER_PORT: "18081"
NEKIRO_COMPOSE_DATABASE_URL: postgresql://nekiro_acceptance:acceptance-only-password@postgres:5432/nekiro_acceptance?sslmode=disable
NEKIRO_DEV_AUTH_PRINCIPALS_JSON: '[{"id":"browser-provider","tokenSha256":"b44e989af5cb9bb1b315c9754b348747bc2adc400d20f413c96b0caf6cd76283"},{"id":"browser-owner","tokenSha256":"2db89754f354a623af6c54bb48473555bf68ae165f1d63001cb041e064078047"}]'
NEKIRO_INTERNAL_DEV_AUTH_PRINCIPALS_JSON: '[{"id":"router-internal","tokenSha256":"f9232718425b5ebee721187a79703448bce513ecf0600eb161f9256ddac27c4d"}]'
NEKIRO_ROUTER_SERVICE_PRINCIPALS_JSON: '[{"id":"control-plane","tokenSha256":"5abfd00de27c6b2f57d45fdc90999134e4e088414ba1f39bf67ee0d1c9cec554"}]'
NEKIRO_ROUTER_AGENT_PRINCIPALS_JSON: '[{"workspaceId":"workspace-browser","agentId":"runtime-a","tokenSha256":"e304d0370532633d535824a897d5c03445b636e8d1649064aa35a8fb50fef200"},{"workspaceId":"workspace-browser","agentId":"runtime-b","tokenSha256":"9b990de9bb74efd4e1d26a43a01e132deb60d563d49faf6878dca4af40858a38"}]'
NEKIRO_ROUTER_INTERNAL_BEARER_TOKEN: router-internal-token
NEKIRO_CONTROL_PLANE_SERVICE_TOKEN: control-plane-internal-token
NEKIRO_CORS_ALLOWED_ORIGINS: http://127.0.0.1:4173
NEKIRO_ENDPOINT_CHALLENGE_TTL_SECONDS: "300"
NEKIRO_ENDPOINT_VERIFICATION_TIMEOUT_MS: "10000"
NEKIRO_ENDPOINT_ALLOWED_PRIVATE_HOSTS_JSON: '["runtime-a","runtime-b"]'
NEKIRO_CONTROL_PLANE_INTERNAL_REQUEST_MAX_BYTES: "1048576"
NEKIRO_GATEWAY_INVOCATION_REQUEST_MAX_BYTES: "1048576"
NEKIRO_GATEWAY_SSE_EVENT_MAX_BYTES: "65536"
NEKIRO_GATEWAY_METADATA_RESPONSE_MAX_BYTES: "1048576"
NEKIRO_GATEWAY_INVOCATION_DEADLINE_MS: "30000"
NEKIRO_ROUTER_INTERNAL_REQUEST_LIMIT_BYTES: "1048576"
NEKIRO_ROUTER_AGENT_REQUEST_LIMIT_BYTES: "1048576"
NEKIRO_ROUTER_CONTROL_PLANE_RESPONSE_LIMIT_BYTES: "1048576"
NEKIRO_ROUTER_AGENT_RESPONSE_LIMIT_BYTES: "1048576"
NEKIRO_ROUTER_A2A_EVENT_LIMIT_BYTES: "1048576"
NEKIRO_ROUTER_SSE_EVENT_LIMIT_BYTES: "65536"
NEKIRO_ROUTER_RESOLUTION_DEADLINE_MS: "30000"
NEKIRO_ROUTER_AGENT_DEADLINE_MS: "30000"
NEKIRO_ROUTER_AGENT_CREDENTIAL_ISSUER: https://a2a-router.nekiro.test
NEKIRO_ROUTER_AGENT_CREDENTIAL_KEY_ID: ci-browser-key-1
NEKIRO_ROUTER_AGENT_CREDENTIAL_PRIVATE_KEY_BASE64URL: AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8DoQe_884Qvh1w3RjnS8CZZ-TWMJulDV8d3IZkElUxuA
NEKIRO_ROUTER_AGENT_CREDENTIAL_TTL_SECONDS: "30"
NEKIRO_AGENT_ROUTER_ISSUER: https://a2a-router.nekiro.test
NEKIRO_AGENT_ROUTER_KEY_ID: ci-browser-key-1
NEKIRO_AGENT_ROUTER_PUBLIC_KEY_BASE64URL: A6EHv_POEL4dcN0Y50vAmWfk1jCbpQ1fHdyGZBJVMbg
RUNTIME_A_ROUTER_TOKEN: runtime-a-router-token
RUNTIME_A_RESPONSE_LIMIT_BYTES: "1048576"
RUNTIME_A_EVENT_LIMIT_BYTES: "65536"
RUNTIME_B_ROUTER_TOKEN: runtime-b-router-token
RUNTIME_B_RESPONSE_LIMIT_BYTES: "1048576"
RUNTIME_B_EVENT_LIMIT_BYTES: "65536"
NEKIRO_E2E_BASE_URL: http://127.0.0.1:4173
NEKIRO_E2E_COMPOSE_PROJECT: nekiro-console-browser
NEKIRO_E2E_COMPOSE_FILE: ${{ github.workspace }}/nekiro-platform/deploy/compose.yaml
VITE_NEKIRO_API_BASE_URL: http://gateway.nekiro.test:18080
VITE_NEKIRO_PROVIDER_ID: browser-provider
VITE_NEKIRO_PROVIDER_NAME: Browser Provider
VITE_NEKIRO_PROVIDER_TOKEN: browser-provider-token
VITE_NEKIRO_OWNER_TOKEN: browser-owner-token
VITE_NEKIRO_DEFAULT_WORKSPACE_ID: workspace-browser

steps:
- name: Check out Console
uses: actions/checkout@v4

- name: Check out platform acceptance dependency
uses: actions/checkout@v4
with:
repository: NeKiro-project/NeKiro
ref: dec548e7b85da79c5982167688f0c698677d47c7
path: nekiro-platform

- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 11.3.0
run_install: false

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 24.16.0
cache: pnpm
cache-dependency-path: pnpm-lock.yaml

- name: Install frontend dependencies
run: pnpm install --frozen-lockfile

- name: Map the Gateway to an explicit non-IP origin
run: echo "127.0.0.1 gateway.nekiro.test" | sudo tee -a /etc/hosts

- name: Start fresh platform Compose
working-directory: nekiro-platform
run: docker compose --project-name "$NEKIRO_E2E_COMPOSE_PROJECT" --file deploy/compose.yaml up --build --detach --wait --wait-timeout 120

- name: Install Chromium
run: pnpm exec playwright install --with-deps chromium

- name: Build production Console with explicit browser configuration
run: pnpm run build

- name: Run production browser acceptance
run: pnpm run test:e2e

- name: Tear down fresh platform Compose
if: always()
working-directory: nekiro-platform
run: docker compose --project-name "$NEKIRO_E2E_COMPOSE_PROJECT" --file deploy/compose.yaml down --volumes --remove-orphans
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ coverage/
*.log
.env*
!.env.example
test-results/
playwright-report/
78 changes: 70 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ This Console follows the MVP spec in docs/superpowers/specs/2026-07-16-nekiro-co
- Registry: GET/POST /v3/agents, exact reads, publish, and disable for Agent Card v0.2.
- Workspace: POST /v3/workspaces and GET /v3/workspaces/{workspaceId} from the header.
- Installations: install, list, enable, disable, and uninstall through /v3/workspaces/{workspaceId}/installations.
- Trusted Publication: provider-owned Binding, Challenge, and immutable Release lifecycle through public /v4 Gateway routes.
- Installation trust handoff: an explicit Release ID is preflighted through GET /v4/releases/{releaseId}; Catalog publication alone is not trusted publication.

## Runtime surfaces

Expand All @@ -17,20 +19,56 @@ This Console follows the MVP spec in docs/superpowers/specs/2026-07-16-nekiro-co
- Ledger reads metadata-only Invocation and Trace projections through the same
Workspace-scoped Gateway API. No fake traces, task streams, or timeout events
are rendered.
- The browser uses one active Workspace and the development-static bearer token;
Agent authentication is declaration-only and never collects secrets.
- The canonical nested path is `Agent B -> Agent SDK -> A2A Router -> Agent A`.
The Console invokes B through Gateway v4 and reads the root/child lineage from
the metadata-only Ledger; it never accepts an Agent endpoint or runtime
credential in the form.
- The browser uses separate provider and Workspace-owner bearer contexts. Agent
authentication is declaration-only and never collects Agent secrets.

## Configuration

Create .env.local or export these values for local development:
Create .env.local or export these six values for local development:

VITE_NEKIRO_API_BASE_URL=http://127.0.0.1:18080
VITE_NEKIRO_TOKEN=
VITE_NEKIRO_OWNER_ID=
VITE_NEKIRO_OWNER_NAME=
VITE_NEKIRO_API_BASE_URL=https://gateway.example.test
VITE_NEKIRO_PROVIDER_ID=
VITE_NEKIRO_PROVIDER_NAME=
VITE_NEKIRO_PROVIDER_TOKEN=
VITE_NEKIRO_OWNER_TOKEN=
VITE_NEKIRO_DEFAULT_WORKSPACE_ID=

The bearer token is sent only as an Authorization header. It is not written to local storage.
`VITE_NEKIRO_PROVIDER_TOKEN` is used only for provider Catalog and Trusted
Publication operations. `VITE_NEKIRO_OWNER_TOKEN` is used only for Discovery,
Workspace, Installation, Invocation, and Ledger operations. Both are sent only
as Authorization headers and are not written to browser storage.

The standalone repository is the upstream source for Console Issues #2/#4/#3.
The platform repository imports the reviewed runtime source into `apps/console`
and owns the root workspace lockfile and fresh-environment CI; do not maintain
a second hand-edited production Console implementation.

The operational path is:

1. Register an Agent Card with the provider context.
2. Create and verify an Endpoint Binding, then create, verify, and publish an immutable Release.
3. Give the Release ID to the Workspace owner.
4. Preflight that exact Release in Installations, accept permissions, and install the exact Card version.
5. Invoke only an enabled Installation that has a returned `installedReleaseId`.

## Failure and recovery ownership

The Console preserves the Gateway HTTP status, stable error code, trace ID, and
correlated invocation IDs where the contract returns them. Timeout, cancellation,
unavailable endpoint, disabled Installation, suspended/revoked Release, invalid
proof, expired/reused challenge, and malformed SSE are distinct failure
categories; the Console does not retry or turn them into success.

Provider recovery is owned by the provider: issue a fresh challenge, repair the
declared endpoint, or create a new Release when the server requires it. Workspace
owner recovery is owned by the owner: review the exact Release ID and permissions,
enable or uninstall an Installation according to the server state, and submit a
new invocation only through an enabled trusted Installation. Router and Ledger
facts remain server-owned and are inspected through the public Gateway.

## Run locally

Expand All @@ -40,7 +78,31 @@ The bearer token is sent only as an Authorization header. It is not written to l
## Verification

npm test
npm run typecheck
npm run lint
npm run build
rg "/v4/workspaces/.+invocations|/v4/workspaces/.+traces" src docs -n
rg "INITIAL_AGENTS|INITIAL_INSTALLATIONS|TRACE_HISTORIES" src -n

## Browser acceptance

The browser acceptance suite runs against a fresh real Gateway and Compose
environment. It requires an explicitly installed Chromium and these values:

NEKIRO_E2E_BASE_URL=http://127.0.0.1:4173
NEKIRO_E2E_COMPOSE_FILE=/absolute/path/to/deploy/compose.yaml
NEKIRO_E2E_COMPOSE_PROJECT=nekiro-browser-acceptance
VITE_NEKIRO_API_BASE_URL=http://gateway.nekiro.test
VITE_NEKIRO_PROVIDER_ID=browser-provider
VITE_NEKIRO_PROVIDER_NAME=Browser Provider
VITE_NEKIRO_PROVIDER_TOKEN=...
VITE_NEKIRO_OWNER_TOKEN=...
VITE_NEKIRO_DEFAULT_WORKSPACE_ID=workspace-browser

Build the production Console with the five VITE_NEKIRO_* values before
running npm run test:e2e. Missing or whitespace-padded values fail
configuration. The suite uses the Gateway only, creates server-backed state,
and never stores credentials or challenge proofs in browser storage.

Playwright traces, screenshots, videos, and HTML reports are disabled for this
acceptance path and are ignored by Git if a local runner creates them.
Loading
Loading