Skip to content
Open
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .dependency-cruiser.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ module.exports = {
{
name: "no-deep-imports-into-runtime",
comment:
"Runtime is a deep module: code OUTSIDE the runtime package imports only its public entries — src/runtime/index.ts (production surface) or src/runtime/testing.ts (named test seams for cross-package *.test.ts) — never src/runtime/** internals (docker, docker-inplace, embedded-assets, kernel/*). Add a named re-export to src/runtime/index.ts (production) or src/runtime/testing.ts (test-only seams) instead of reaching in.",
"Runtime is a deep module: code OUTSIDE the runtime package imports only its public entries — src/runtime/index.ts (production surface) or src/runtime/testing.ts (named test seams for cross-package *.test.ts) — never src/runtime/** internals (embedded-assets, kernel/*). Add a named re-export to src/runtime/index.ts (production) or src/runtime/testing.ts (test-only seams) instead of reaching in.",
severity: "error",
from: { pathNot: "^src/runtime/" },
to: { path: "^src/runtime/", pathNot: "^src/runtime/(index|testing)\\.ts$" },
Expand Down
115 changes: 3 additions & 112 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,60 +38,13 @@ jobs:
VERSION="$(node -p "require('./package.json').version")"
git ls-remote --exit-code https://github.com/jaiphlang/jaiph.git "refs/tags/v${VERSION}"

k8s-manifest:
name: Validate Kubernetes deploy manifest
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

# `kubectl apply --dry-run=client` still needs an API server for resource
# discovery (RESTMapper), so provision a throwaway kind cluster for it.
# The same cluster then backs the real deploy test below.
- name: Create kind cluster
uses: helm/kind-action@v1
with:
cluster_name: jaiph-e2e

# Fast schema gate — cheap, but only proves the manifest parses.
- name: Dry-run apply the standalone deploy manifest
run: kubectl apply --dry-run=client -f docs/deploy/k8s.yaml

- name: Build runtime image for the deploy test
run: docker build -t jaiph-e2e-runtime:local -f runtime/Dockerfile .

# Real deployment contract: external Secret gate, pod hardening
# (non-root, no privilege escalation, dropped caps, no SA token,
# read-only rootfs), an authenticated HTTP run, and its journal on the
# writable runs volume.
- name: Deploy and exercise the manifest on kind
run: |
JAIPH_E2E_SKIP_INSTALL=1 \
JAIPH_E2E_KIND_CLUSTER=jaiph-e2e \
JAIPH_E2E_DOCKER_IMAGE=jaiph-e2e-runtime:local \
bash e2e/tests/150_k8s_deploy.sh

e2e:
name: E2E (${{ matrix.os }}, ${{ matrix.label }})
name: E2E (${{ matrix.os }})
runs-on: ${{ matrix.os }}
env:
# Host/safe split applies on Ubuntu only. macOS runners do not ship Docker the same way — keep host-only there.
# "docker": unset JAIPH_UNSAFE so resolveDockerConfig enables the sandbox (pulls ghcr.io/jaiphlang/jaiph-runtime).
# "host": explicit opt-out, same as a fast local `JAIPH_UNSAFE=true npm run test:e2e`.
JAIPH_UNSAFE: ${{ matrix.jaiph_unsafe }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
label: docker
jaiph_unsafe: ""
- os: ubuntu-latest
label: host
jaiph_unsafe: "true"
- os: macos-latest
label: host
jaiph_unsafe: "true"
os: [ubuntu-latest, macos-latest]
steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -101,12 +54,6 @@ jobs:
with:
node-version: "20"

- name: Build runtime image for Docker E2E
if: matrix.label == 'docker'
run: |
docker build -t jaiph-ci-runtime:local -f runtime/Dockerfile .
echo "JAIPH_DOCKER_IMAGE=jaiph-ci-runtime:local" >> "$GITHUB_ENV"

- name: Run runtime acceptance E2E
run: |
npm ci
Expand Down Expand Up @@ -141,11 +88,6 @@ jobs:
- name: Setup Bun
uses: oven-sh/setup-bun@v2

- name: Build runtime image for docs sample Docker runs
run: |
docker build -t jaiph-ci-runtime:local -f runtime/Dockerfile .
echo "JAIPH_DOCKER_IMAGE=jaiph-ci-runtime:local" >> "$GITHUB_ENV"

- name: Install dependencies
run: npm ci

Expand All @@ -169,7 +111,7 @@ jobs:
fi
command -v cursor-agent

- name: Install Claude Code CLI (prompt backend parity with Docker image)
- name: Install Claude Code CLI
run: |
npm install -g @anthropic-ai/claude-code
command -v claude
Expand Down Expand Up @@ -273,7 +215,6 @@ jobs:
$bashScript = @'
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive
export JAIPH_UNSAFE=true
# wsl.exe does not forward the parent runner's env into this Linux
# session, so CI (which docs/install treats as "trusted toolchain,
# checksum-only OK when minisign is absent") must be re-set here —
Expand Down Expand Up @@ -382,53 +323,3 @@ jobs:
run: |
$env:JAIPH_TEST_WINDOWS_EXE = Join-Path $env:GITHUB_WORKSPACE "jaiph-windows-x64.exe"
./e2e/tests/windows_native_smoke.ps1

docker-publish:
name: Publish Docker runtime image
needs: [test, e2e, docs-local, e2e-wsl, installer-powershell, windows-native-smoke]
if: github.ref == 'refs/heads/nightly' || startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
env:
REGISTRY: ghcr.io
IMAGE_NAME: jaiphlang/jaiph-runtime
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Image tags
id: meta
run: |
if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
VERSION="${GITHUB_REF_NAME#v}"
echo "tags=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${VERSION},${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" >> "$GITHUB_OUTPUT"
else
echo "tags=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:nightly" >> "$GITHUB_OUTPUT"
fi

- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
file: runtime/Dockerfile
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}

- name: Verify pushed image contains jaiph
run: |
TAG="$(echo '${{ steps.meta.outputs.tags }}' | cut -d',' -f1)"
docker run --rm --entrypoint sh "${TAG}" -lc "command -v jaiph && jaiph --version"
docker run --rm --cap-drop ALL --entrypoint sh "${TAG}" -lc "command -v jaiph"
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ e2e/nested_run.sh
e2e/nested_inner.sh
e2e/log_keyword.sh
e2e/fibonacci.sh
e2e/ensure_fail.sh
e2e/current_branch.sh
e2e/assign_capture.sh

Expand Down
16 changes: 8 additions & 8 deletions .jaiph/architect_review.jh
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ config {
script jaiph_review_body_file = `printf '%s\n' "$JAIPH_WORKSPACE/.jaiph/tmp/architect_review_body.txt"`

# Packed as: first line = verdict, rest = updated_description (must stay top-level:
# const … = prompt """…""" is not supported inside ensure … catch — see parseRecoverStatement).
workflow architect_agent_review(task) {
# const … = prompt """…""" is not supported inside run … catch — see parseRecoverStatement).
def architect_agent_review(task) {
const result = prompt """
You are a software architect reviewing a task from the Jaiph
improvement queue. Jaiph is a TypeScript compiler and runtime
Expand Down Expand Up @@ -70,12 +70,12 @@ workflow architect_agent_review(task) {
"""
}

workflow review_one_header(header) {
def review_one_header(header) {
run common.arg_nonempty(header) catch (err) {
return ""
}
const task = run queue.get_task_by_header(header)
ensure queue.task_is_dev_ready(task) catch (err) {
run queue.task_is_dev_ready(task) catch (err) {
const packed = run architect_agent_review(task)
const verdict = run common.first_line_str(packed)
const updated_description = run common.rest_lines_str(packed)
Expand Down Expand Up @@ -104,7 +104,7 @@ workflow review_one_header(header) {
log "Already dev-ready: ${header}"
}

workflow process_headers_recursive(header, remaining) {
def process_headers_recursive(header, remaining) {
run review_one_header(header)
run common.arg_nonempty(remaining) catch (err) {
return ""
Expand All @@ -114,19 +114,19 @@ workflow process_headers_recursive(header, remaining) {
run process_headers_recursive(next, rest)
}

workflow maybe_process_headers(first, rest) {
def maybe_process_headers(first, rest) {
run common.arg_nonempty(first) catch (err) {
return ""
}
run process_headers_recursive(first, rest)
}

workflow default() {
export def main() {
const headers = run queue.get_all_task_headers()
const first = run common.first_line_str(headers)
const rest = run common.rest_lines_str(headers)
run maybe_process_headers(first, rest)
ensure queue.all_dev_ready() catch (err) {
run queue.all_dev_ready() catch (err) {
fail "One or more tasks need work. Review the agent output above."
}
}
24 changes: 12 additions & 12 deletions .jaiph/docs_parity.jh
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const role = """
- Prose must follow the plain-writing skill
(.jaiph/skills/plain-writing/SKILL.md): everyday words, complete
sentences, limited clause stacking, and no unnecessary jargon. Real
Jaiph terms (workflow, sandbox, MCP, …) are allowed; define them briefly
Jaiph terms (def, sandbox, MCP, …) are allowed; define them briefly
on first use when a newcomer might not know them.
"""

Expand All @@ -49,7 +49,7 @@ script assert_newline_paths_are_files = ```
done <<< "$1"
```

rule docs_files_present(list) {
def docs_files_present(list) {
run assert_newline_paths_are_files(list)
}

Expand All @@ -70,7 +70,7 @@ script assert_worktree_clean_for_docs = ```
fi
```

rule worktree_is_clean() {
def worktree_is_clean() {
run assert_worktree_clean_for_docs()
}

Expand All @@ -94,7 +94,7 @@ script assert_only_allowed_changed = ```
done <<< "$after_changed_files"
```

rule only_expected_docs_changed_after_prompt(allowed) {
def only_expected_docs_changed_after_prompt(allowed) {
run assert_only_allowed_changed(allowed)
}

Expand All @@ -121,7 +121,7 @@ script build_allowed_paths_block = ```
printf '%s\n' "$out"
```

workflow update_from_task(taskDesc) {
export def update_from_task(taskDesc) {
prompt """
${skills_preamble}
<role>
Expand All @@ -148,7 +148,7 @@ workflow update_from_task(taskDesc) {
"""
}

workflow docs_page(path) {
def docs_page(path) {
prompt """
${skills_preamble}
<role>
Expand Down Expand Up @@ -182,7 +182,7 @@ workflow docs_page(path) {
"""
}

workflow docs_overview(docPaths) {
def docs_overview(docPaths) {
prompt """
${skills_preamble}
<role>
Expand Down Expand Up @@ -220,7 +220,7 @@ workflow docs_overview(docPaths) {
8. Ensure docs/index.html and README.md have links to getting-started.md
page of the documentation or jaiph.org/getting-started, and the agent
skill URL (https://raw.githubusercontent.com/jaiphlang/jaiph/refs/heads/main/docs/jaiph-skill.md).
9. Knowing the whole documentation, ensure the agent skill is up to date
9. Knowing the whole documentation, run the agent skill is up to date
and coherent with the documentation. It should be a minimal workflow set
that supports safe feature delivery, preflight checks, implementation
workflow, verification workflow, and a default entrypoint that
Expand All @@ -233,11 +233,11 @@ workflow docs_overview(docPaths) {
"""
}

workflow default() {
export def main() {
run claude.ensure_usage()
ensure worktree_is_clean()
run worktree_is_clean()
const allowed_list = run build_allowed_paths_block()
ensure docs_files_present(allowed_list)
run docs_files_present(allowed_list)
const docs_md_list = run list_docs_md_paths()
for path in docs_md_list {
if path != "" {
Expand All @@ -247,5 +247,5 @@ workflow default() {
}
run claude.ensure_usage()
run docs_overview(docs_md_list)
ensure only_expected_docs_changed_after_prompt(allowed_list)
run only_expected_docs_changed_after_prompt(allowed_list)
}
Loading
Loading