diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a4c9715..31b7316 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,9 @@ jobs: - name: Run repository checks run: bash scripts/ci/repository_checks.sh + - name: New-app author remap + run: bash scripts/ci/new_app_author_check.sh + quality: runs-on: ubuntu-latest diff --git a/AGENTS.md b/AGENTS.md index 0cf3a3c..654d186 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -28,7 +28,8 @@ gh project item-list 2 --owner traverse-framework --format json --limit 300 \ | `llm-mcp-meeting-notes-workflow` | **Done** (#239) | Meeting-notes MCP tool-sequence runbook | | `llm-mcp-cursor-live-smoke` | **Done** (#240) | Cursor MCP Mode A stdio evidence | | `llm-mcp-claude-live-smoke` | **Done** (#241) | Claude Desktop/Code MCP Mode A evidence | -| `kit-runner-persona-docs` | **In Progress** | Persona runbook + embedded onboarding; Future `new-app-author-e2e` | +| `kit-runner-persona-docs` | **Done** (#273) | Persona runbook + embedded onboarding | +| `new-app-author-e2e` | **In Progress** | CLI `app new` → App-Refs layout + Web host rewrite | | `llm-mcp-mode-a-spec119-scaffold` | **Done** (#271) | Spec 119 consumer scaffold (fail-closed); live kit execute stays `llm-mcp-traverse-starter-catalog` | | `llm-mcp-traverse-starter-catalog` | **Blocked** | Spec 119 Approved; wait on Mode A `traverse-mcp` implement. No kit content groups in v1 (FR-007) | | `loop-wf1-registry-deps` | **Done** (#263) | Digest inventory in `docs/loop-registry-deps.md` | diff --git a/README.md b/README.md index 9dd5612..5a5206c 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,7 @@ Spec 119 v1 has **no kit content groups**. Discovery is public registry entries. |---|---| | [`docs/getting-started-embedded.md`](docs/getting-started-embedded.md) | First full walkthrough | | [`docs/kit-runner-persona.md`](docs/kit-runner-persona.md) | Persona kit-runner bar (each OS) | +| [`docs/new-app-author.md`](docs/new-app-author.md) | Create a new app id (`app new` → App-Refs layout) | | [`docs/llm-reference-apps-plan.md`](docs/llm-reference-apps-plan.md) | LLM façades via MCP (Claude / Cursor / …) | | [`docs/app-manifest-schema.md`](docs/app-manifest-schema.md) | `app.manifest.json` fields + `traverse-cli app new` scaffold | | [`docs/add-platform-client.md`](docs/add-platform-client.md) | Add another OS shell | diff --git a/docs/add-platform-client.md b/docs/add-platform-client.md index 9e513f8..74e483d 100644 --- a/docs/add-platform-client.md +++ b/docs/add-platform-client.md @@ -19,7 +19,7 @@ Related: ## Prerequisites -1. App manifests exist under `manifests//` +1. App manifests exist under `manifests//` (new app id: [`new-app-author.md`](new-app-author.md)) 2. Public platform embedder SDK is available for the OS (vendor or package reference) 3. Project 2 ticket claimed (`AGENTS.md` pre-flight) with production-shaped DoD diff --git a/docs/app-manifest-schema.md b/docs/app-manifest-schema.md index 509687b..4da503c 100644 --- a/docs/app-manifest-schema.md +++ b/docs/app-manifest-schema.md @@ -6,7 +6,7 @@ Governing Traverse spec: [`044-application-bundle-manifest`](https://github.com/traverse-framework/Traverse/blob/main/specs/044-application-bundle-manifest/spec.md) (schema `1.0.0`). -Related App-Refs docs: [`production-packaging.md`](production-packaging.md) · [`runtime-bundle-sync.md`](runtime-bundle-sync.md) · [`getting-started-embedded.md`](getting-started-embedded.md) · [`kit-runner-persona.md`](kit-runner-persona.md) +Related App-Refs docs: [`production-packaging.md`](production-packaging.md) · [`runtime-bundle-sync.md`](runtime-bundle-sync.md) · [`getting-started-embedded.md`](getting-started-embedded.md) · [`kit-runner-persona.md`](kit-runner-persona.md) · [`new-app-author.md`](new-app-author.md) --- @@ -171,6 +171,9 @@ Schema-valid **empty** bundle: | empty `components/` | real `components//component.manifest.json` + digests | | empty `workflows/` | workflow JSON under `_traverse/…` (or synced Traverse tree) | | no state machine | add `state_machine` + `list_context_fields` for UI shells | +| `workspace_id: "-local"` | Primaries use `local-default` (kit seed) | + +**Won’t Fix in App-Refs:** renaming Traverse `app new` output. Helper: `scripts/ci/remap_app_new_to_kit.sh`. Persona recipe (Web proven): [`new-app-author.md`](new-app-author.md). Upstream: [Traverse #1170](https://github.com/traverse-framework/Traverse/issues/1170). Then sync into platform bundles with `scripts/ci/sync_*_bundle.sh` ([`runtime-bundle-sync.md`](runtime-bundle-sync.md)). diff --git a/docs/decision-log.md b/docs/decision-log.md index 7cf3d47..97f9747 100644 --- a/docs/decision-log.md +++ b/docs/decision-log.md @@ -346,3 +346,22 @@ Append-only record of design decisions for App-References. Newest sessions at th **Decision:** This ticket is docs + onboarding rewrite + repository_checks for the runbook. App code changes only if a persona step is broken in a way docs cannot fix. File Project 2 drafts for real bugs found during dogfood. `new-app-author-e2e` stays Future until kit-runner lands. **Why:** Smallest change that makes the persona test runnable and the docs honest. + +--- + +## 2026-08-26 — New-app author E2E + +**Context:** Personas want to **create** Traverse apps with App-Refs. Kit-runner (#273) covers running existing shells. `traverse-cli app new` still emits `apps//manifest.json` (empty); embedders load `manifests//app.manifest.json`. + +**Question:** Change Traverse CLI in this ticket, check in a throwaway product app, or remap + prove Web? + +**Options considered:** +- Implement `app new` filename change in Traverse — pros: one layout; cons: wrong repo for this thread +- Check in `apps/persona-demo` as a fifth primary — pros: visible app; cons: duplicate starter WASM; CI/workspace cost +- Remap helper + fixture CI + Web host rewrite; seed from traverse-starter; no new product app in tree — pros: honest layout proof; cons: live `app new` still needs TRAVERSE_REPO locally + +**Recommendation:** Remap helper + Web proof in CI. + +**Decision:** Ship `docs/new-app-author.md`, `scripts/ci/remap_app_new_to_kit.sh`, and `scripts/ci/new_app_author_check.sh`. First slice reuses `traverse-starter.pipeline` / `registry_ref`. Won’t Fix: renaming Traverse `app new` output in this repo. + +**Why:** Constitution: no invented business fields. Empty `app new` is not a product app. Web is the one OS in this slice; more OS uses add-platform-client after Web works. diff --git a/docs/demo-inventory.md b/docs/demo-inventory.md index ae2e892..a288e99 100644 --- a/docs/demo-inventory.md +++ b/docs/demo-inventory.md @@ -33,4 +33,4 @@ Shipped. Do not treat this table as live status — Project 2 is SoT. ## Status -Inventory plus follow-up tickets are complete. New-app author E2E is Future `new-app-author-e2e`. Kit-runner personas: [`kit-runner-persona.md`](kit-runner-persona.md). +Inventory plus follow-up tickets are complete. New-app author: [`new-app-author.md`](new-app-author.md). Kit-runner personas: [`kit-runner-persona.md`](kit-runner-persona.md). diff --git a/docs/getting-started-embedded.md b/docs/getting-started-embedded.md index 668a893..dee677b 100644 --- a/docs/getting-started-embedded.md +++ b/docs/getting-started-embedded.md @@ -144,6 +144,7 @@ CI runs this with `EMBEDDED_SMOKE_EXPECT=linux` on every PR (see `.github/workfl ## Related docs - [`kit-runner-persona.md`](kit-runner-persona.md) — persona kit-runner bar (each OS) +- [`new-app-author.md`](new-app-author.md) — create a new app id from `app new` - [`production-playbook.md`](production-playbook.md) — embedded-first production playbook - [`embedded-runtime-plan.md`](embedded-runtime-plan.md) — Phase 3 architecture - [`production-reference-plan.md`](production-reference-plan.md) — Phase 4 kit roadmap diff --git a/docs/kit-runner-persona.md b/docs/kit-runner-persona.md index fee4ccb..5452a38 100644 --- a/docs/kit-runner-persona.md +++ b/docs/kit-runner-persona.md @@ -2,9 +2,9 @@ **Audience:** someone using App-References as the copy-paste kit — run the **existing** `traverse-starter` (and siblings) on an OS they care about. -This is the first end-to-end bar. It is **not** “create a brand-new app from scratch” (Future: `new-app-author-e2e`) and **not** registry MCP on OS shells (LLM façades only; Mode A host still unimplemented). +This is the first end-to-end bar. It is **not** “create a brand-new app from scratch” ([`new-app-author.md`](new-app-author.md)) and **not** registry MCP on OS shells (LLM façades only; Mode A host still unimplemented). -Related: [`getting-started-embedded.md`](getting-started-embedded.md) · [`production-playbook.md`](production-playbook.md) · [`add-platform-client.md`](add-platform-client.md) · root [`README.md`](../README.md) +Related: [`getting-started-embedded.md`](getting-started-embedded.md) · [`production-playbook.md`](production-playbook.md) · [`add-platform-client.md`](add-platform-client.md) · [`new-app-author.md`](new-app-author.md) · root [`README.md`](../README.md) ## What must be true (kit bar) @@ -67,7 +67,7 @@ Local npm gates always. Manifest / `registry_ref` / runbook probes always. `TRAV |---|---| | Sync still **materializes** `registry_ref` → local wasm for many hosts | `retire-registry-ref-materialize-hosts` (Future) | | Registry MCP is not an OS-shell path | `llm-mcp-mode-a-spec119-scaffold` Done (fail-closed); live kit execute `llm-mcp-traverse-starter-catalog` Blocked | -| Creating a **new** app id from CLI + this kit | Future `new-app-author-e2e` | +| Creating a **new** app id from CLI + this kit | [`new-app-author.md`](new-app-author.md) (`new-app-author-e2e`) | | `onboarding_check.sh` is not a merge-blocking CI gate | By design (slow `npm install`); `embedded_smoke` is the PR gate | ## File bugs diff --git a/docs/new-app-author.md b/docs/new-app-author.md new file mode 100644 index 0000000..a9a0401 --- /dev/null +++ b/docs/new-app-author.md @@ -0,0 +1,102 @@ +# New-app author persona + +**Audience:** someone who wants to **create a new Traverse app id** using this repo as the kit — not only run `traverse-starter`. + +Kit-runner (existing shells on each OS): [`kit-runner-persona.md`](kit-runner-persona.md). Schema: [`app-manifest-schema.md`](app-manifest-schema.md). Extra OS: [`add-platform-client.md`](add-platform-client.md). + +## What this ticket proves + +A persona can: + +1. Run public `traverse-cli app new ` (empty, schema-valid scaffold). +2. Remap that tree into App-Refs `manifests//app.manifest.json`. +3. Seed the **kit bar** from `traverse-starter` (state machine, `registry_ref` caps, config, workflow). +4. Copy the **Web** shell, rewrite app identity + bundle path, keep the public embedder. + +First slice **reuses** `traverse-starter.pipeline` and published starter WASM. That is intentional: App-Refs must not invent title/tags/status. A new domain app needs new WASM in Traverse first. + +Do **not** start `traverse-cli serve`. Production path is embedded. + +## Won’t Fix here (Traverse CLI) + +| CLI `app new` | App-Refs / embedders | +|---|---| +| `apps//manifest.json` | `manifests//app.manifest.json` | +| Empty `components` / `workflows` | Real `registry_ref` + workflow JSON | +| No `state_machine` | Required for primary shells | +| `workspace_id: -local` | Primaries use `local-default` until you change config | + +App-Refs will **not** rename Traverse’s scaffold. Remap with `scripts/ci/remap_app_new_to_kit.sh`. Upstream: [Traverse #1170](https://github.com/traverse-framework/Traverse/issues/1170) (`app new` should emit `app.manifest.json`). Until then, treat CLI output as a stub, not a product app. + +## Recipe (Web) + +Work in a scratch directory for `app new` so you do not drop a stub under this repo’s `apps/` product shells. + +```bash +export TRAVERSE_REPO=/path/to/Traverse +export APP_REFS=/path/to/reference-apps # this clone +APP_ID=my-notes # your new app id + +# 1. Empty governed scaffold (not runnable) +cd /tmp +cargo run -p traverse-cli-rs --manifest-path "$TRAVERSE_REPO/Cargo.toml" -- \ + app new "$APP_ID" + +# 2. Remap + seed kit bar (state_machine, registry_ref, config, workflow) +bash "$APP_REFS/scripts/ci/remap_app_new_to_kit.sh" \ + --from "/tmp/apps/$APP_ID" \ + --out "$APP_REFS/manifests/$APP_ID" \ + --app-id "$APP_ID" \ + --seed-from traverse-starter + +# 3. Copy Web twin (structure only — do not add business-field math) +mkdir -p "$APP_REFS/apps/$APP_ID" +cp -R "$APP_REFS/apps/traverse-starter/web-react" "$APP_REFS/apps/$APP_ID/web-react" +``` + +In `apps//web-react/src/host/embeddedHost.ts` change **only**: + +- `DEFAULT_APP_ID` → `''` +- `DEFAULT_MANIFEST_PATH` → `'/bundles//app.manifest.json'` + +Leave `DEFAULT_WORKFLOW_ID = 'traverse-starter.pipeline'` until Traverse ships a new workflow. Copy the starter Web README **Runtime mode: Embedded** line. Add a `scripts/ci/sync_web__bundle.sh` wrapper that calls `sync_bundle_core.sh` the same way as `sync_web_starter_bundle.sh` (destination `apps//web-react/public/bundles/`). + +Then: + +```bash +bash scripts/ci/sync_web__bundle.sh +# wire the workspace package if you are checking the shell into this repo +npm run dev +``` + +Pass criteria (same as kit-runner Web): host **Embedded**; submit a fixed note; runtime-owned title/tags/note type/next action/status; no sidecar URL. + +## Validate (this repo, no live `app new`) + +```bash +bash scripts/ci/new_app_author_check.sh +``` + +CI runs that on every PR. It remaps the checked-in `app new` fixture and proves the Web host rewrite. Live `cargo run -p traverse-cli-rs -- app new` still needs `TRAVERSE_REPO` on your machine. + +Once the bundle has real components: + +```bash +bash scripts/ci/phase2_link_traverse.sh +cargo run -p traverse-cli-rs --manifest-path "$TRAVERSE_REPO/Cargo.toml" -- \ + app validate --manifest "manifests/$APP_ID/app.manifest.json" --json +``` + +Registration is optional local-dev (`app register`). It is **not** the UI shipping path. + +## Do / don’t + +| Do | Don’t | +|---|---| +| Remap `manifest.json` → `app.manifest.json` | Treat `app new` output as a runnable product | +| Seed from a primary kit or published `registry_ref` | Compute title/tags/status in React | +| Copy Web from `traverse-starter` | Import private Traverse internals | +| Keep workflow ids that match real WASM | Start `traverse-cli serve` for the OS shell | +| File a Project 2 draft if a step fails | Open a GitHub Issue in App-Refs | + +Seven-OS ports of the new id: follow [`add-platform-client.md`](add-platform-client.md) after Web works. MCP catalog is a separate façade. diff --git a/docs/production-playbook.md b/docs/production-playbook.md index ca95f5a..165084c 100644 --- a/docs/production-playbook.md +++ b/docs/production-playbook.md @@ -60,7 +60,7 @@ npm run dev # traverse-starter embedded web shell @ :5173 Do **not** start `traverse-cli serve`. Confirm the UI shows **Embedded** / ready, then submit a note and check runtime-owned fields. -Persona kit-runner (existing starter on each OS): [`kit-runner-persona.md`](kit-runner-persona.md). +Persona kit-runner (existing starter on each OS): [`kit-runner-persona.md`](kit-runner-persona.md). New app id: [`new-app-author.md`](new-app-author.md). --- diff --git a/docs/production-reference-plan.md b/docs/production-reference-plan.md index f51204f..4a6823c 100644 --- a/docs/production-reference-plan.md +++ b/docs/production-reference-plan.md @@ -79,7 +79,7 @@ Live status is always on [Project 2](https://github.com/orgs/traverse-framework/ - `meeting-notes-wave2-os-ports` — Done (#236) - `loop-wf1-multi-os` — Done (#265) -Kit-runner persona bar (run existing starter on each OS): [`kit-runner-persona.md`](kit-runner-persona.md). New-app author E2E is Future `new-app-author-e2e`. +Kit-runner persona bar (run existing starter on each OS): [`kit-runner-persona.md`](kit-runner-persona.md). New-app author E2E: [`new-app-author.md`](new-app-author.md). ## Architecture boundary (unchanged) diff --git a/scripts/ci/fixtures/app-new-scaffold/youaskm3/components/README.md b/scripts/ci/fixtures/app-new-scaffold/youaskm3/components/README.md new file mode 100644 index 0000000..58438c9 --- /dev/null +++ b/scripts/ci/fixtures/app-new-scaffold/youaskm3/components/README.md @@ -0,0 +1 @@ +Placeholder from `traverse-cli app new`. Not a capability. Replace via `--seed-from traverse-starter` (or real `registry_ref` components). Do not invent business fields here. diff --git a/scripts/ci/fixtures/app-new-scaffold/youaskm3/manifest.json b/scripts/ci/fixtures/app-new-scaffold/youaskm3/manifest.json new file mode 100644 index 0000000..c018f7f --- /dev/null +++ b/scripts/ci/fixtures/app-new-scaffold/youaskm3/manifest.json @@ -0,0 +1,23 @@ +{ + "app_id": "youaskm3", + "version": "0.1.0", + "schema_version": "1.0.0", + "workspace_defaults": { + "workspace_id": "youaskm3-local", + "config_path": "workspace.config.json" + }, + "components": [], + "workflows": [], + "model_dependencies": [], + "config_schema": { + "type": "object", + "additionalProperties": false, + "properties": {} + }, + "default_config": {}, + "placement_policy": { + "preferred_targets": ["local"], + "allow_fallback": false + }, + "public_surfaces": ["cli"] +} diff --git a/scripts/ci/fixtures/app-new-scaffold/youaskm3/workflows/README.md b/scripts/ci/fixtures/app-new-scaffold/youaskm3/workflows/README.md new file mode 100644 index 0000000..62307fb --- /dev/null +++ b/scripts/ci/fixtures/app-new-scaffold/youaskm3/workflows/README.md @@ -0,0 +1 @@ +Placeholder from `traverse-cli app new`. Not a workflow. Seed from a primary kit or add a real workflow JSON that invokes WASM — never compute product fields in the UI. diff --git a/scripts/ci/fixtures/app-new-scaffold/youaskm3/workspace.config.json b/scripts/ci/fixtures/app-new-scaffold/youaskm3/workspace.config.json new file mode 100644 index 0000000..a2fffdc --- /dev/null +++ b/scripts/ci/fixtures/app-new-scaffold/youaskm3/workspace.config.json @@ -0,0 +1,3 @@ +{ + "workspace_id": "youaskm3-local" +} diff --git a/scripts/ci/new_app_author_check.sh b/scripts/ci/new_app_author_check.sh new file mode 100755 index 0000000..6b19f2a --- /dev/null +++ b/scripts/ci/new_app_author_check.sh @@ -0,0 +1,141 @@ +#!/usr/bin/env bash +# Prove new-app-author remap + Web host constants (no sidecar, no business fields). +# Does not start processes. Does not require TRAVERSE_REPO. +set -euo pipefail + +REPO_ROOT="${REPO_ROOT:-$(git rev-parse --show-toplevel)}" +FIXTURE="$REPO_ROOT/scripts/ci/fixtures/app-new-scaffold/youaskm3" +HOST_SRC="$REPO_ROOT/apps/traverse-starter/web-react/src/host/embeddedHost.ts" +README_SRC="$REPO_ROOT/apps/traverse-starter/web-react/README.md" +FAIL=0 + +pass() { echo "[PASS] $1"; } +fail() { echo "[FAIL] $1"; FAIL=1; } + +if ! command -v jq >/dev/null 2>&1; then + echo "FAIL: jq is required" + exit 1 +fi + +TMP="$(mktemp -d)" +trap 'rm -rf "$TMP"' EXIT + +echo "=== New-app author check ===" + +echo "[1] remap CLI scaffold (no seed)..." +bash "$REPO_ROOT/scripts/ci/remap_app_new_to_kit.sh" \ + --from "$FIXTURE" \ + --out "$TMP/empty/youaskm3" +if [ -f "$TMP/empty/youaskm3/app.manifest.json" ] && [ ! -f "$TMP/empty/youaskm3/manifest.json" ]; then + pass "filename is app.manifest.json" +else + fail "expected app.manifest.json only" +fi +empty_wf="$(jq '.workflows | length' "$TMP/empty/youaskm3/app.manifest.json")" +if [ "$empty_wf" = "0" ]; then + pass "empty scaffold still has no workflows (not a product app)" +else + fail "empty remap should not invent workflows" +fi +if jq -e '.state_machine' "$TMP/empty/youaskm3/app.manifest.json" >/dev/null 2>&1; then + fail "empty scaffold should not invent a state_machine" +else + pass "empty scaffold has no state_machine" +fi + +echo "[2] remap + seed traverse-starter (kit bar)..." +APP_ID="persona-demo" +bash "$REPO_ROOT/scripts/ci/remap_app_new_to_kit.sh" \ + --from "$FIXTURE" \ + --out "$TMP/kit/$APP_ID" \ + --app-id "$APP_ID" \ + --seed-from traverse-starter +MANIFEST="$TMP/kit/$APP_ID/app.manifest.json" +PROCESS="$TMP/kit/$APP_ID/components/process/component.manifest.json" +got_id="$(jq -r '.app_id' "$MANIFEST")" +got_wf="$(jq -r '.workflows[0].workflow_id' "$MANIFEST")" +if [ "$got_id" = "$APP_ID" ]; then + pass "app_id=$APP_ID" +else + fail "app_id is $got_id" +fi +if [ "$got_wf" = "traverse-starter.pipeline" ]; then + pass "workflow id remains traverse-starter.pipeline (reuse published WASM)" +else + fail "workflow_id unexpectedly $got_wf" +fi +if jq -e '.state_machine' "$MANIFEST" >/dev/null 2>&1 \ + && jq -e '.config_schema' "$MANIFEST" >/dev/null 2>&1 \ + && jq -e '.default_config' "$MANIFEST" >/dev/null 2>&1 \ + && jq -e '.workflows | length > 0' "$MANIFEST" >/dev/null 2>&1; then + pass "state_machine + config + workflows" +else + fail "seeded manifest missing kit fields" +fi +if jq -e '.registry_ref.namespace and .registry_ref.id' "$PROCESS" >/dev/null 2>&1; then + pass "process component registry_ref" +else + fail "seeded process component missing registry_ref" +fi +if [ -e "$TMP/kit/$APP_ID/_traverse" ]; then + fail "seed copied _traverse symlink (must stay out of author output)" +else + pass "no _traverse symlink in remapped tree" +fi +if [ -f "$TMP/kit/$APP_ID/workspace.config.json" ]; then + fail "seeded tree kept CLI workspace.config.json" +else + pass "CLI workspace.config.json not carried over after seed" +fi +ws="$(jq -r '.workspace_defaults.workspace_id' "$MANIFEST")" +if [ "$ws" = "local-default" ]; then + pass "workspace_defaults.workspace_id=local-default" +else + fail "workspace_id is $ws (expected local-default from starter seed)" +fi + +echo "[3] Web OS twin (copy starter host constants)..." +if [ ! -f "$HOST_SRC" ] || [ ! -f "$README_SRC" ]; then + fail "missing traverse-starter web-react host/README" +else + mkdir -p "$TMP/web/src/host" + # Keep workflow id; only rewrite app identity + bundle path. + sed \ + -e "s|export const DEFAULT_APP_ID = 'traverse-starter'|export const DEFAULT_APP_ID = '${APP_ID}'|" \ + -e "s|export const DEFAULT_MANIFEST_PATH = '/bundles/traverse-starter/app.manifest.json'|export const DEFAULT_MANIFEST_PATH = '/bundles/${APP_ID}/app.manifest.json'|" \ + "$HOST_SRC" >"$TMP/web/src/host/embeddedHost.ts" + if grep -q "DEFAULT_APP_ID = '${APP_ID}'" "$TMP/web/src/host/embeddedHost.ts" \ + && grep -q "/bundles/${APP_ID}/app.manifest.json" "$TMP/web/src/host/embeddedHost.ts" \ + && grep -q "DEFAULT_WORKFLOW_ID = 'traverse-starter.pipeline'" "$TMP/web/src/host/embeddedHost.ts" \ + && grep -q "BundleEmbedder" "$TMP/web/src/host/embeddedHost.ts" \ + && grep -q "traverse-embedder-web" "$TMP/web/src/host/embeddedHost.ts"; then + pass "Web host constants rewrite (embedded BundleEmbedder)" + else + fail "Web host rewrite did not keep public embedder + starter workflow" + fi + if grep -Eq '127\.0\.0\.1:8787|traverse-cli -- serve' "$TMP/web/src/host/embeddedHost.ts"; then + fail "rewritten host references sidecar" + else + pass "rewritten host has no sidecar URL" + fi + if grep -qi 'Runtime mode: embedded' "$README_SRC"; then + pass "starter Web README documents Runtime mode: Embedded (copy this)" + else + fail "starter Web README missing Runtime mode: Embedded" + fi +fi + +echo "[4] remap helper does not treat sidecar as production..." +if grep -Eq 'cargo run -p traverse-cli -- serve|VITE_TRAVERSE_BASE_URL=http://127.0.0.1:8787' \ + "$REPO_ROOT/scripts/ci/remap_app_new_to_kit.sh"; then + fail "remap helper encodes sidecar as production" +else + pass "no sidecar serve / 8787 production probe in remap helper" +fi + +echo "" +if [ "$FAIL" -eq 1 ]; then + echo "FAIL: new-app author check failed." + exit 1 +fi +echo "PASS: new-app author check complete." diff --git a/scripts/ci/remap_app_new_to_kit.sh b/scripts/ci/remap_app_new_to_kit.sh new file mode 100755 index 0000000..c06ad90 --- /dev/null +++ b/scripts/ci/remap_app_new_to_kit.sh @@ -0,0 +1,103 @@ +#!/usr/bin/env bash +# Remap `traverse-cli app new` output into App-Refs layout. +# +# CLI scaffold: apps//manifest.json (empty bundle; not a product app) +# App-Refs: manifests//app.manifest.json +# +# Does not invent title/tags/status. Does not start traverse-cli serve. +# Optional --seed-from copies a primary kit (components, workflows, state_machine) +# and sets app_id; workflow ids stay those of the seed (reuse published WASM). +set -euo pipefail + +usage() { + cat <<'EOF' +Usage: + bash scripts/ci/remap_app_new_to_kit.sh --from --out [options] + +Options: + --from PATH Directory created by `app new` (contains manifest.json) + --out PATH Destination manifests// directory + --app-id ID Override app_id (default: .app_id from the CLI manifest) + --seed-from NAME Overlay manifests// (e.g. traverse-starter), excluding _traverse + -h, --help + +Won’t Fix in this repo: Traverse `app new` filename. See docs/new-app-author.md. +EOF +} + +FROM="" +OUT="" +APP_ID="" +SEED="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --from) FROM="${2:-}"; shift 2 ;; + --out) OUT="${2:-}"; shift 2 ;; + --app-id) APP_ID="${2:-}"; shift 2 ;; + --seed-from) SEED="${2:-}"; shift 2 ;; + -h|--help) usage; exit 0 ;; + *) echo "FAIL: unknown argument: $1" >&2; usage; exit 1 ;; + esac +done + +if [ -z "$FROM" ] || [ -z "$OUT" ]; then + echo "FAIL: --from and --out are required" >&2 + usage + exit 1 +fi + +if [ ! -f "$FROM/manifest.json" ]; then + echo "FAIL: $FROM/manifest.json not found (expected traverse-cli app new output)" >&2 + exit 1 +fi + +if ! command -v jq >/dev/null 2>&1; then + echo "FAIL: jq is required" >&2 + exit 1 +fi + +REPO_ROOT="${REPO_ROOT:-$(cd "$(dirname "$0")/../.." && pwd)}" + +mkdir -p "$OUT" +cp "$FROM/manifest.json" "$OUT/app.manifest.json" +if [ -f "$FROM/workspace.config.json" ]; then + cp "$FROM/workspace.config.json" "$OUT/workspace.config.json" +fi + +if [ -z "$APP_ID" ]; then + APP_ID="$(jq -r '.app_id' "$OUT/app.manifest.json")" +fi +if [ -z "$APP_ID" ] || [ "$APP_ID" = "null" ]; then + echo "FAIL: could not determine app_id" >&2 + exit 1 +fi + +tmp="$(mktemp)" +jq --arg id "$APP_ID" '.app_id = $id' "$OUT/app.manifest.json" >"$tmp" +mv "$tmp" "$OUT/app.manifest.json" + +if [ -n "$SEED" ]; then + SEED_DIR="$REPO_ROOT/manifests/$SEED" + if [ ! -d "$SEED_DIR" ]; then + echo "FAIL: seed kit not found: $SEED_DIR" >&2 + exit 1 + fi + # Overlay kit files; keep destination app_id. Do not follow _traverse symlink. + if command -v rsync >/dev/null 2>&1; then + rsync -a --exclude '_traverse' "$SEED_DIR/" "$OUT/" + else + # Portable fallback: copy tree then drop a copied _traverse symlink if present + cp -R "$SEED_DIR/." "$OUT/" + rm -f "$OUT/_traverse" + fi + tmp="$(mktemp)" + jq --arg id "$APP_ID" '.app_id = $id' "$OUT/app.manifest.json" >"$tmp" + mv "$tmp" "$OUT/app.manifest.json" + # CLI workspace.config.json must not override seeded kit defaults. + if [ ! -f "$SEED_DIR/workspace.config.json" ]; then + rm -f "$OUT/workspace.config.json" + fi +fi + +echo "OK: remapped $FROM/manifest.json -> $OUT/app.manifest.json (app_id=$APP_ID${SEED:+ seed=$SEED})" diff --git a/scripts/ci/repository_checks.sh b/scripts/ci/repository_checks.sh index 3fe7303..e9a6919 100644 --- a/scripts/ci/repository_checks.sh +++ b/scripts/ci/repository_checks.sh @@ -30,6 +30,7 @@ check "docs/traverse-runtime.md" "Traverse runtime setup" check "docs/design-language.md" "UI design language" check "docs/runtime-bundle-sync.md" "Runtime bundle sync contract" check "docs/kit-runner-persona.md" "Kit-runner persona bar" +check "docs/new-app-author.md" "New-app author persona" check "docs/production-packaging.md" "Production packaging / registry_ref contract" check "docs/app-manifest-schema.md" "Application bundle manifest schema" @@ -167,6 +168,9 @@ check "scripts/ci/sync_android_doc_approval_bundle.sh" "Android doc-approval bun check "scripts/ci/sync_android_meeting_notes_bundle.sh" "Android meeting-notes bundle sync" check "scripts/ci/sync_android_loop_bundle.sh" "Android loop bundle sync" check "scripts/ci/onboarding_check.sh" "Onboarding check" +check "scripts/ci/remap_app_new_to_kit.sh" "app new → kit remap" +check "scripts/ci/new_app_author_check.sh" "New-app author check" +check "scripts/ci/fixtures/app-new-scaffold/youaskm3/manifest.json" "app new scaffold fixture" # GitHub Actions check ".github/workflows/ci.yml" "CI workflow"