Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 4 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ jobs:
run: cargo test --locked --workspace --all-targets
- name: check the canonical Uhura project
run: |
cargo run --locked -p uhura-cli -- fmt --check examples/instagram/client
# Project-wide formatting remains gated on Uhura RFC 0003 comment
# attachment; the formatter refuses to erase the evidence catalogue's
# authored comments.
cargo run --locked -p uhura-cli -- check examples/instagram/client --deny-warnings
cargo run --locked -p uhura-cli -- trace examples/instagram/client --script=demo >/dev/null
cargo run --locked -p uhura-cli -- trace examples/instagram/client --script=feed_like_refused_scenario --expanded >/dev/null
13 changes: 8 additions & 5 deletions .github/workflows/npm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ jobs:
PACKAGE_VERSION: ${{ steps.resolve.outputs.version }}
run: cd npm && npm version "$PACKAGE_VERSION" --no-git-tag-version --allow-same-version

- name: guard — packed package is complete and within 25 MiB
- name: guard — packed package is complete and within 26 MiB
env:
PACKAGE_VERSION: ${{ steps.resolve.outputs.version }}
run: |
Expand Down Expand Up @@ -398,7 +398,7 @@ jobs:
throw new Error(`packed executable must have mode 0755: ${path} (mode ${mode})`);
}
}
const limit = 25 * 1024 * 1024;
const limit = 26 * 1024 * 1024;
if (entry.size > limit) {
throw new Error(`packed package is ${entry.size} bytes; limit is ${limit} bytes`);
}
Expand All @@ -424,7 +424,10 @@ jobs:
echo "::error::expected exactly one guarded npm tarball; found ${#packages[@]}"
exit 1
fi
npm publish "${packages[0]}" --dry-run --tag "$DIST_TAG"
# A branch may revalidate the Cargo version after that version is
# already on npm. npm otherwise rejects even --dry-run; --force is
# safe here only because this step is gated to dry_run == true.
npm publish "${packages[0]}" --dry-run --force --tag "$DIST_TAG"

- name: npm publish
if: steps.resolve.outputs.dry_run != 'true'
Expand Down Expand Up @@ -554,7 +557,7 @@ jobs:
fi
curl -fsS http://127.0.0.1:4124/ | grep -qi "<!doctype html"
curl -fsS http://127.0.0.1:4124/play | grep -qi "<!doctype html"
curl -fsS http://127.0.0.1:4124/api/editor/state | grep -q '"protocol":"uhura-editor-state/2"'
curl -fsS http://127.0.0.1:4124/api/editor/state | grep -q '"protocol":"uhura-editor-state/5"'
curl -fsS http://127.0.0.1:4124/api/play/wasm/uhura_wasm.js >/dev/null
curl -fsS http://127.0.0.1:4124/api/play/wasm/uhura_wasm_bg.wasm >/dev/null
curl -fsS http://127.0.0.1:4124/~project/status | grep -q '"protocol":"spock-project-status/1"'
Expand Down Expand Up @@ -608,7 +611,7 @@ jobs:
throw "Editor or Play did not serve HTML"
}
$state = Invoke-RestMethod -Uri "http://127.0.0.1:4124/api/editor/state"
if ($state.protocol -ne "uhura-editor-state/2") { throw "wrong Editor protocol" }
if ($state.protocol -ne "uhura-editor-state/5") { throw "wrong Editor protocol" }
Invoke-WebRequest -Uri "http://127.0.0.1:4124/api/play/wasm/uhura_wasm.js" | Out-Null
Invoke-WebRequest -Uri "http://127.0.0.1:4124/api/play/wasm/uhura_wasm_bg.wasm" | Out-Null
$status = Invoke-RestMethod -Uri "http://127.0.0.1:4124/~project/status"
Expand Down
39 changes: 26 additions & 13 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

55 changes: 39 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,20 @@ other musl-based Linux distributions are not supported yet. Framework commands
begin with `0.5.0`; registry releases through `0.4.0` expose only the standalone
language commands.

With the `0.5.0` framework npm release:
Published `0.5.x` supports framework projects. The shortest version-stable
start is backend-only:

```sh
npx spock new demo
npx spock new demo --backend-only
cd demo
npx spock dev
```

Published `spock@0.5.3` embeds the retired Uhura frontend. The strict Uhura 0.4
client documented below is integrated in current source and requires the
[source build](#uhura-the-client-language) until a compatible npm release
ships. Do not mix a 0.4 client with the 0.5.3 sidecar.

Standalone programs keep the same entry points:

```sh
Expand All @@ -50,10 +56,17 @@ npm i -g spock
```

```sh
spock new demo # create backend + Uhura client + spock.toml
spock check # check the whole nearest project
spock dev # watch client; observe backend as restart-required
spock start # serve one fixed combined generation
# published 0.5.3: backend-only
spock new api --backend-only
spock check api
spock dev api

# current checkout: strict Uhura 0.4 full stack, after the asset build below
cargo run --locked -p spock-cli -- new demo
cargo run --locked -p spock-cli -- check demo
SPOCK_UHURA_WEB_DIST="$PWD/uhura/web/dist" \
SPOCK_UHURA_WASM_DIST="$PWD/uhura/crates/uhura-wasm/pkg/web" \
cargo run --locked -p spock-cli -- dev demo

# standalone language escape hatches stay available
spock check app.spock # parse + fully load-check one program
Expand Down Expand Up @@ -99,17 +112,26 @@ status, contract metadata, Editor, and Play can still run.

The repository's canonical full-stack example uses this exact shape at
[`uhura/examples/instagram`](https://github.com/gridaco/uhura/tree/main/examples/instagram). Build its app-owned
provider once, then one command checks and serves the authority and client:
provider and the source-only Editor/Play assets once, then the current Spock
source checks and serves the authority and strict Uhura 0.4 client:

```sh
git submodule update --init --recursive
corepack pnpm@10.11.0 -C crates/spock-runtime/studio install --frozen-lockfile
corepack pnpm@10.11.0 -C crates/spock-runtime/studio build
corepack pnpm@10.11.0 -C uhura/web install --frozen-lockfile
corepack pnpm@10.11.0 -C uhura/web build:provider
spock start uhura/examples/instagram
corepack pnpm@10.11.0 -C uhura/web build
bash uhura/scripts/build-wasm.sh

SPOCK_UHURA_WEB_DIST="$PWD/uhura/web/dist" \
SPOCK_UHURA_WASM_DIST="$PWD/uhura/crates/uhura-wasm/pkg/web" \
cargo run --locked -p spock-cli -- start uhura/examples/instagram
```

The `0.5.2` CLI includes the fixture's proposed `error` declarations as an
experimental RFD 0024 implementation preview, so this remains a distribution
smoke through the published npm CLI. The same project remains independently
Published `spock@0.5.3` and earlier accept the backend's experimental RFD 0024
`error` declarations but embed the retired Uhura frontend, so they cannot run
this strict 0.4 checkout. The next compatible npm release must package this
same checked runtime and asset generation. The project remains independently
checkable as a Spock backend and an Uhura client.

`spock dev` deliberately has asymmetric reload semantics today. Valid Uhura
Expand Down Expand Up @@ -751,10 +773,11 @@ shim only selects and owns the matching native process. Releases through
Spock's doctrine forbids Spock from building a client language — "generate
types, never the client" (`docs/rfd/0010`), "borrow, don't build"
(`docs/rfd/0009`). That slot is filled by
[Uhura](https://github.com/gridaco/uhura): a declarative UI language and
deterministic headless experience runtime that owns non-authoritative
UI-session state and experience behavior, with Spock as its canonical
provider. No fact may be authoritative in both languages.
[Uhura](https://github.com/gridaco/uhura): a deterministic machine language
with an explicit optional Web UI profile. It owns non-authoritative client
state and experience behavior, with Spock as its canonical provider; its UI
modules are pure projections of machine observations rather than a second
state model. No fact may be authoritative in both languages.

Uhura is a subsystem of the Spock project: its canonical source lives in its
own repository and is included here as a git submodule at `uhura/`. The root
Expand Down
6 changes: 3 additions & 3 deletions crates/spock-cli/tests/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ fn project_check_deduplicates_shared_editor_and_play_diagnostics() {
.assert()
.success();
std::fs::write(
temporary.path().join("demo/client/app/home/page.uhura"),
temporary.path().join("demo/client/machine.uhura"),
"not valid uhura\n",
)
.unwrap();
Expand All @@ -314,9 +314,9 @@ fn project_check_deduplicates_shared_editor_and_play_diagnostics() {
.assert()
.failure();
let stderr = String::from_utf8(assertion.get_output().stderr.clone()).unwrap();
let repeated = "`not` is not a definition kind";
let repeated = "[R1001 uhura-0.4/parse/invalid-declaration]";
assert_eq!(stderr.matches(repeated).count(), 1, "{stderr}");
assert!(stderr.contains("app/home/page.uhura:"), "{stderr}");
assert!(stderr.contains("machine.uhura:"), "{stderr}");
}

#[test]
Expand Down
18 changes: 9 additions & 9 deletions crates/spock-host/src/assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ const SIDECAR_PROTOCOL: &str = "spock-asset-sidecar/1";
const HOST_ENVIRONMENT_PROTOCOL: &str = "spock-host-environment/1";
const PROJECT_STATUS_PROTOCOL: &str = "spock-project-status/1";
const PROJECT_EVENT_PROTOCOL: &str = "spock-project-event/1";
const EDITOR_STATE_PROTOCOL: &str = "uhura-editor-state/2";
const EDITOR_STATE_PROTOCOL: &str = "uhura-editor-state/5";
const EDITOR_EVENT_PROTOCOL: &str = "uhura-editor-event/0";
const IR_PROTOCOL: &str = "uhura-ir/0";
const INSPECT_PROTOCOL: &str = "uhura-inspect/0";
const VIEW_PROTOCOL: &str = "uhura-view/0";
const PROVIDER_PROTOCOL: &str = "uhura-provider/0";
const IR_PROTOCOL: &str = "uhura-ir/1";
const INSPECT_PROTOCOL: &str = "uhura-inspection/1";
const VIEW_PROTOCOL: &str = "uhura-view/1";
const ADAPTER_PROVIDER_PROTOCOL: &str = "uhura-adapter-provider/0";
const SIDECAR_PROTOCOLS: [(&str, &str); 9] = [
("environment", HOST_ENVIRONMENT_PROTOCOL),
("project_status", PROJECT_STATUS_PROTOCOL),
Expand All @@ -37,7 +37,7 @@ const SIDECAR_PROTOCOLS: [(&str, &str); 9] = [
("ir", IR_PROTOCOL),
("inspect", INSPECT_PROTOCOL),
("view", VIEW_PROTOCOL),
("provider", PROVIDER_PROTOCOL),
("adapter_provider", ADAPTER_PROVIDER_PROTOCOL),
];
const MAX_MANIFEST_BYTES: u64 = 8 * 1024 * 1024;
const REQUIRED_FILES: [&str; 3] = [
Expand Down Expand Up @@ -762,12 +762,12 @@ mod tests {
fixture.manifest["protocols"]
.as_object_mut()
.expect("protocol object")
.remove("provider");
.remove("adapter_provider");
fixture.write_manifest();
let error = validate_packaged_sidecar(&fixture.root, &fixture.roots)
.expect_err("missing protocol must fail closed");
assert!(
error.contains("required protocol provider is missing"),
error.contains("required protocol adapter_provider is missing"),
"{error}"
);

Expand Down Expand Up @@ -1024,7 +1024,7 @@ mod tests {
"ir": IR_PROTOCOL,
"inspect": INSPECT_PROTOCOL,
"view": VIEW_PROTOCOL,
"provider": PROVIDER_PROTOCOL
"adapter_provider": ADAPTER_PROVIDER_PROTOCOL
},
"files": files,
});
Expand Down
Loading
Loading