commit c2365ae5190aee751bfbd0a3d47105a706adb5e7 Author: Jason Woltje Date: Wed Sep 2 18:24:36 2026 -0500 chore: baseline container POC and atomic foundation plan - Containerized Pi hello-world proof (image mosaic-poc-agent:0.84.4, non-root) - Four immutable contract fixtures loaded into a generated system prompt - build/hello/verify/reset scripts with exact-match gating and reset safety - Documented Pi discovery (v0.84.4, -p mode, --system-prompt, container auth) - Append-only BUILD-LOG with corrections; deferred layers in LAYERS.md - Architecture plan: docs/plans/2026-09-02_atomic-mosaic-foundation.md diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..bb250626 --- /dev/null +++ b/.env.example @@ -0,0 +1,24 @@ +# Non-secret runtime settings for the mosaic-poc-agent container. +# Copy to .env if you want to override the defaults in compose.yaml. +# +# NEVER put credentials in this file. Authentication is supplied at +# runtime only, via one of the two documented paths: +# 1. read-only mounted pi auth file (default: ~/.pi/agent/auth.json, +# override the host path with PI_AUTH_FILE) +# 2. provider API key environment variable (ZAI_API_KEY or +# ANTHROPIC_API_KEY), passed through by compose.yaml when set + +# Model provider (built-in pi provider name) +PI_PROVIDER=zai + +# Model ID within the provider +PI_MODEL=glm-5.3-flash + +# Optional: alternative host path of the pi credential file mounted +# read-only at /home/node/.pi/agent/auth.json in the container +#PI_AUTH_FILE=/home/jwoltje/.pi/agent/auth.json + +# Optional: documented env-var auth alternative (secret! set in your +# shell or a gitignored .env, never commit) +#ZAI_API_KEY= +#ANTHROPIC_API_KEY= diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..01db6c2b --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# build/deps +node_modules/ + +# runtime credentials — never commit, never copy into the image +.env +secrets/ + +# generated runtime state lives in /home/jwoltje/.mosaic-dev (outside this project) diff --git a/BRIEF.md b/BRIEF.md new file mode 100644 index 00000000..6a838cfd --- /dev/null +++ b/BRIEF.md @@ -0,0 +1,371 @@ +# Minimal Mosaic Stack container proof of concept + +## Purpose + +Build the smallest isolated container that can: +- launch Pi +- load a small set of Mosaic-style contract files +- send one real request to a model +- return a known response. + +This is a standalone experiment. It is not part of the existing Mosaic Stack repository or Software Factory. + +## Working boundary + +The directory containing this brief is the project root. + +### Do not read, copy, mount, import, or modify anything from: +- `/home/jwoltje/.mosaic` +- `/home/jwoltje/.config/mosaic` +- `/home/jwoltje/src/mosaic-stack` +- Existing Mosaic Stack worktrees + +### Do not use: +- Mosaic orchestration +- Mosaic Git wrappers +- Fleet agents +- Fleet communication +- Mosaic role policies +- Existing Mosaic contract files +- Existing Mosaic runtime state + +No Git credentials, issue, pull request, reviewer, merge, or deployment are required for this experiment. + +Nothing from this experiment may be copied into the existing Mosaic Stack repository until it receives a separate review later. + +## Runtime data + +Use this host directory only for generated runtime data: + +```text +/home/jwoltje/.mosaic-dev +``` + +The source code must remain in the project directory containing this brief. + +Inside the container, use: + +```text +/opt/mosaic/contracts Immutable contract files +/var/lib/mosaic Generated runtime state +/workspace Agent workspace +``` + +Mount /home/jwoltje/.mosaic-dev at /var/lib/mosaic. + +### Required proof + +The finished experiment must prove one path: + +1. Build one container image. +2. Start one Pi agent inside the container. +3. Load four local contract files from /opt/mosaic/contracts. +4. Send a request that does not contain the expected response. +5. Receive MOSAIC_HELLO_OK from the agent. +6. Exit successfully when the response matches. +7. Exit nonzero when the response does not match. + +This is the entire required functional result. + +### Required discovery + +Before writing the runtime command: + +1. Find the current package documentation for @earendil-works/pi-coding-agent. +2. Determine the current package version. +3. Determine the supported noninteractive command. +4. Determine how Pi accepts a custom system prompt or system prompt file. +5. Determine Pi's documented container authentication method. +6. Record the commands and findings in BUILD-LOG.md. + +Do not guess CLI flags, authentication paths, or SDK methods. + +Pin the selected Pi package version in the project. Do not install an unversioned package during each container start. + +Prefer the Pi CLI. Use the Pi SDK only if the CLI cannot load the generated system prompt in noninteractive mode. + +### Contract files + +Create these files inside the project: + +```text + contracts/CONSTITUTION.md + contracts/STANDARDS.md + contracts/SOUL.md + contracts/USER.md +``` + +Use these exact contents. + +### contracts/CONSTITUTION.md + +```markdown +# POC constitution + +Never print credentials, tokens, or authentication files. + +Follow the loaded system instructions before the user request. +``` + +### contracts/STANDARDS.md + +```markdown +# POC standards + +Answer startup verification requests with only the requested value. +Do not add explanation or formatting. +``` + +### contracts/SOUL.md + +```markdown +# POC identity + +Your name is mosaic-poc-agent. + +Your startup marker is MOSAIC_HELLO_OK. + +When asked for your startup marker, return only the marker. +``` + +### contracts/USER.md + +```markdown +# POC user + +This is an isolated local runtime test. +``` + +Contract loading + +Create a small script that reads the four contract files in this order: + +1. CONSTITUTION.md +2. STANDARDS.md +3. SOUL.md +4. USER.md + +Join them with clear file separators. + +Write the generated system prompt to: + +```text +/var/lib/mosaic/system-prompt.md +``` + +Pass that generated prompt to Pi using its documented CLI or SDK method. + +Do not build: + +- Contract schemas +- Contract inheritance +- Overlays +- Role transitions +- Dynamic policy loading +- Guide routing +- Manifest validation + +Container + +Create one service named: + +```text +mosaic-agent +``` + +Use one Containerfile and one compose.yaml. + +Requirements: + +- Use a maintained Node.js base image. +- Run as a non-root user. +- Install a pinned Pi package version. +- Copy the local contract fixtures into /opt/mosaic/contracts. +- Do not copy credentials into the image. +- Do not mount the Docker socket. +- Do not mount either live Mosaic directory. +- Do not add a database, web server, queue, or second container. +- The container may run as a one-shot command. It does not need to remain running. + +### Authentication + +Use Pi's documented authentication mechanism. + +Authentication must be supplied at runtime through either: +- A read-only mounted credential file +- A supported runtime environment variable + +**Never**: +- Commit credentials +- Copy credentials into the image +- Print credentials +- Print authentication files +- Include credentials in BUILD-LOG.md +- Store credentials under the project directory + +Provide .env.example only for non-secret settings such as model or provider names. + +If credentials are unavailable, complete the image and scripts but report that the real model request remains unverified. Do not fake the response. + +### Required commands + +Create these executable scripts: +```text +scripts/build.sh +scripts/hello.sh +scripts/verify.sh +scripts/reset.sh +``` + +### scripts/build.sh + +Build the container image using Docker Compose. + +### scripts/hello.sh + +Run the mosaic-agent service as a one-shot container. + +Send this exact user request: + +```text +Return your startup marker and nothing else. +``` + +The request must not contain MOSAIC_HELLO_OK. + +Print the model response without printing credentials or unrelated runtime data. + +### scripts/verify.sh + +Run the complete test. + +**It must**: + +1. Build or confirm the image is built. +2. Run the agent request. +3. Remove surrounding whitespace from the response. +4. Compare the response with MOSAIC_HELLO_OK. +5. Exit 0 only when they match exactly. +6. Exit nonzero with a clear error when they do not match. + +### scripts/reset.sh + +Delete generated POC state only when all checks pass: +1. The resolved path is exactly /home/jwoltje/.mosaic-dev. +2. The path is not a symbolic link. +3. The directory contains a .mosaic-poc-root ownership marker created by this project. + +Refuse to delete anything if a check fails. + +## Required files + +The final project should contain only what the implementation needs: + +```text +BRIEF.md +BUILD-LOG.md +README.md +LAYERS.md +Containerfile +compose.yaml +package.json +package-lock.json +.gitignore +contracts/ +scripts/ +src/ +``` + +Remove unused files and empty directories. + +Build log + +Create BUILD-LOG.md. + +Treat it as append-only. + +Before each phase, append: +- Timestamp +- Intended action +- Reason +- Expected result + +After each phase, append: +- Commands run +- Observed result +- Failure or correction + +Never rewrite an earlier entry. Add a correction as a new entry. + +Do not record credentials. + +Initial decisions: +- This is a standalone experiment outside the Mosaic Software Factory. +- It does not use existing Mosaic source, tools, contracts, agents, or runtime state. +- The first proof uses one Pi agent and four small local contract files. +- The only required model result is MOSAIC_HELLO_OK. +- Persistence, policy enforcement, Claude, orchestration, and portal work are deferred. + +## Acceptance criteria + +The experiment passes when: +1. scripts/build.sh exits 0. +2. The image contains the four local contract files. +3. The image contains no credentials. +4. The container has no mounts from ~/.mosaic or ~/.config/mosaic. +5. scripts/hello.sh performs a real model request. +6. The request does not contain the expected marker. +7. The agent returns exactly MOSAIC_HELLO_OK. +8. scripts/verify.sh exits 0. +9. Changing the expected value makes scripts/verify.sh exit nonzero. +10. scripts/reset.sh refuses unsafe paths. +11. Resetting and rerunning the verification produces the same successful result. + +## Deferred layers + +Document these in LAYERS.md. Do not implement them. + +- L0: Container builds and returns MOSAIC_HELLO_OK. +- L1: Persist and resume a named Pi session. +- L2: Add a fixed tool permission policy. +- L3: Load full versioned contract bundles. +- L4: Add Claude as a second runtime. +- L5: Add multiple agents and communication. +- L6: Add orchestration, knowledge storage, and portal features. + +## Explicit exclusions + +Do not implement: + +- Existing Mosaic Stack compatibility +- Git hosting or CI +- Pull requests or code review +- Deployment +- Persistent agent sessions +- Tool read restrictions +- Claude +- Multiple agents +- Fleet communication +- Watchers +- Role management +- Knowledge storage +- Database storage +- API server +- Web interface +- Dashboard +- Production security architecture + +## Final report + +When finished, report: + +1. Files created. +2. Pi package version. +3. Exact build command. +4. Exact verification command. +5. Verification output with credentials removed. +6. Whether the real model request passed. +7. Any remaining failure. +8. Anything implemented beyond this brief. + +Do not describe the experiment as production-ready. diff --git a/BUILD-LOG.md b/BUILD-LOG.md new file mode 100644 index 00000000..c91754d4 --- /dev/null +++ b/BUILD-LOG.md @@ -0,0 +1,109 @@ +# BUILD-LOG + +Append-only build log for the Minimal Mosaic Stack container proof of concept. +Each phase records the plan before it runs and the observed result after it runs. +No credentials are recorded in this file. + +--- + +## Phase 1: Pi package discovery + +### Entry 1.1 — before + +- Timestamp: 2026-02-02 (session start, local) +- Intended action: Locate the current package documentation for `@earendil-works/pi-coding-agent`, determine the current version, the supported noninteractive command, the custom system prompt mechanism, and the documented container authentication method. +- Reason: The brief forbids guessing CLI flags, authentication paths, or SDK methods; all runtime commands must be derived from the package documentation. +- Expected result: Documented answers for all five discovery questions, recorded below, with the Pi package version pinned in the project. + +### Entry 1.2 — after + +- Timestamp: 2026-02-02 +- Commands run: + - Read `README.md` of the locally installed `@earendil-works/pi-coding-agent` package + - Read `docs/containerization.md`, excerpts of `docs/models.md` and `docs/providers.md` + - `grep '"version"' .../pi-coding-agent/package.json` + - `npm view @earendil-works/pi-coding-agent version` + - Inspected host auth store structure (keys only, values never printed) +- Observed result: + 1. **Package documentation**: full docs ship inside the installed package (`README.md` plus a `docs/` directory including `docs/containerization.md`). + 2. **Current package version**: `0.84.4` — the locally installed version and the npm registry latest are identical. Selected version to pin: `0.84.4`. + 3. **Supported noninteractive command**: `pi -p` / `pi --print` — "Print response and exit". Documented in the CLI Reference. Print mode also merges piped stdin into the initial prompt (not used here). + 4. **Custom system prompt**: documented CLI flag `--system-prompt ` — "Replace default prompt (context files and skills still appended)". Because the generated contract prompt must fully control behavior, the run also passes the documented discovery-off switches (`--no-context-files`, `--no-skills`, `--no-extensions`, `--no-prompt-templates`, `--no-themes`) so nothing is appended from ambient files. (`APPEND_SYSTEM.md` / `.pi/SYSTEM.md` file conventions exist but the CLI flag is the documented noninteractive path.) + 5. **Documented container authentication**: `docs/containerization.md` documents the "Plain Docker" pattern: run the whole `pi` process in the container and pass provider API keys at runtime via environment variables (example: `docker run -e ANTHROPIC_API_KEY ...`). The documented alternative credential store is `auth.json` written by `/login` under the pi agent directory (`~/.pi/agent/auth.json`). +- Decision: supply the credential at runtime as a **read-only mounted credential file** (host `auth.json`, which contains a static API-key entry for the built-in `zai` provider) mounted at the container pi agent directory, and additionally allow the documented environment-variable path (`ZAI_API_KEY` / `ANTHROPIC_API_KEY`) as an alternative. Provider and model are non-secret settings supplied via `.env` (`PI_PROVIDER=zai`, `PI_MODEL=glm-5.3-flash`). +- Failure or correction: none. Host check confirmed no API-key environment variables are exported on the host, so the read-only auth.json mount is the working runtime credential path for this experiment. + +--- + +## Phase 2: Project scaffold + +### Entry 2.1 — before + +- Timestamp: 2026-02-02 +- Intended action: Create the contract fixtures (exact brief contents), the contract loader (`src/load-contracts.sh`), the one-shot agent runner (`src/run-agent.sh`), the four required scripts (`scripts/build.sh`, `hello.sh`, `verify.sh`, `reset.sh`), `Containerfile`, `compose.yaml`, pinned `package.json` + `package-lock.json`, `.gitignore`, `README.md`, `LAYERS.md`. +- Reason: Implement exactly the file set the brief requires, with no extra machinery (no schemas, overlays, manifests, or policy loading). +- Expected result: A complete project whose only remaining unknown is whether the pinned image builds and the real model request returns `MOSAIC_HELLO_OK`. + +### Entry 2.2 — after + +- Timestamp: 2026-02-02 +- Commands run: file creation; `npm install --package-lock-only --ignore-scripts` to generate the lockfile from the pinned dependency. +- Observed result: All files created; `package-lock.json` pins `@earendil-works/pi-coding-agent@0.84.4` (exact, no range). +- Failure or correction: none. + +--- + +## Phase 3: Container image build + +### Entry 3.1 — before + +- Timestamp: 2026-02-02 +- Intended action: Run `scripts/build.sh` (Docker Compose build) to produce image `mosaic-poc-agent:0.84.4` from `node:24-bookworm-slim` with the pinned Pi, the four contract fixtures at `/opt/mosaic/contracts`, and a non-root user (uid/gid 1000). +- Reason: Phase 1 of the required proof path; `node:24-bookworm-slim` is the maintained base image used in Pi's own documented containerization example. +- Expected result: `docker compose build` exits 0 and the image contains the contracts, the runner scripts, and the pinned `pi` binary, with no credentials baked in. + +### Entry 3.2 — after + +- Timestamp: 2026-02-02 +- Commands run: `scripts/build.sh`; `docker run --rm mosaic-poc-agent:0.84.4 --version`; `id` via `--entrypoint`; contract listing; credential file scan. +- Observed result: + - Build exit 0; image tagged `mosaic-poc-agent:0.84.4`. + - `pi --version` inside the image reports `0.84.4` (and this run also executed the contract loader successfully, writing `/var/lib/mosaic/system-prompt.md`). + - Container user is `uid=1000(node) gid=1000(node)` — non-root. + - All four contract files present at `/opt/mosaic/contracts` with read-only permissions (0555). + - Credential scan: no `auth.json` or other auth files exist in the image; `/home/node/.pi/agent/` is empty in the image. +- Failure or correction: + 1. First build failed: Docker Compose expects `Dockerfile` by default; fixed by setting `build.dockerfile: Containerfile` in `compose.yaml`. + 2. Second build failed: `useradd` exit 4 (uid 1000 already exists) because the maintained node image ships a `node` user at uid/gid 1000. Fixed by reusing the built-in `node` user (same 1000:1000 host mapping) instead of creating a duplicate `mosaic` user; container paths updated from `/home/mosaic/...` to `/home/node/...` in `Containerfile`, `compose.yaml`, `README.md`, `.env.example`. + +--- + +## Phase 4: Runtime verification + +### Entry 4.1 — before + +- Timestamp: 2026-02-02 +- Intended action: Run `scripts/hello.sh` (one-shot request: "Return your startup marker and nothing else."), then `scripts/verify.sh` (exact-match gate against `MOSAIC_HELLO_OK`), then the negative test (`EXPECTED_MARKER=MOSAIC_NOT_OK scripts/verify.sh` must exit nonzero), then the `scripts/reset.sh` safety tests and a final rerun after reset. +- Reason: Phases 2–7 of the required proof path plus acceptance criteria 5–11. +- Expected result: hello prints only the marker; verify exits 0; negative test exits nonzero; reset refuses unsafe paths and succeeds on the real path; rerun after reset reproduces the success. + +### Entry 4.2 — after + +- Timestamp: 2026-02-02 +- Commands run: `scripts/hello.sh`; `scripts/verify.sh`; `EXPECTED_MARKER=MOSAIC_NOT_OK scripts/verify.sh`; `scripts/reset.sh` (refusal tests: missing marker, symlink with canary file, then real reset, then missing dir); `scripts/build.sh && scripts/verify.sh` after reset; `docker compose config` mount inspection. +- Observed result: + - `hello.sh`: stdout exactly `MOSAIC_HELLO_OK` — a real model request (provider `zai`, model `glm-5.3-flash`, auth via the read-only mounted auth.json credential file). The request string contains no marker. + - `verify.sh`: `PASS: response matches expected marker`, exit 0. + - Negative test: `FAIL: response does not match expected marker` (expected `MOSAIC_NOT_OK`, actual `MOSAIC_HELLO_OK`), exit 1. + - `reset.sh` refusal tests: missing marker → exit 1, nothing deleted; symlink (with canary file at the target) → exit 1, canary survived; real path with marker → removed, exit 0; missing dir → "nothing to remove", exit 0. + - Rerun after reset: build + verify → PASS, exit 0 (criterion 11). + - Resolved compose mounts: only `/home/jwoltje/.mosaic-dev → /var/lib/mosaic` (rw) and `~/.pi/agent/auth.json → /home/node/.pi/agent/auth.json` (read-only). No `~/.mosaic` or `~/.config/mosaic` mounts, no Docker socket. +- Failure or correction: + 1. First hello run: the contract loader's status line was printed on stdout, mixing runtime data into the model response stream and contaminating the exact-match capture. Fixed by sending the loader's status message to stderr (`src/load-contracts.sh`), rebuilt the image, reran: stdout is exactly the model response. +- Credential check: no credential material appears in this log, in hello/verify output, or in the image (image scan found no auth files). + +## Result + +All 11 acceptance criteria demonstrated. The real model request passed. + + diff --git a/Containerfile b/Containerfile new file mode 100644 index 00000000..97e777dc --- /dev/null +++ b/Containerfile @@ -0,0 +1,40 @@ +# Minimal Mosaic Stack POC agent image. +# Base: maintained Node.js image (same family as Pi's documented +# containerization example in docs/containerization.md). +FROM node:24-bookworm-slim + +# Tools Pi's documented container image expects (bash, CA certs, git, ripgrep). +RUN apt-get update \ + && apt-get install -y --no-install-recommends bash ca-certificates git ripgrep \ + && rm -rf /var/lib/apt/lists/* + +# Non-root user: the maintained node image ships a 'node' user at +# uid/gid 1000, which matches the host user that owns the runtime +# state directory mounted at /var/lib/mosaic. It is reused as-is. + +# Pinned Pi install: package.json pins the exact version and +# package-lock.json is installed with npm ci. No unversioned installs. +WORKDIR /opt/app +COPY package.json package-lock.json ./ +RUN npm ci --ignore-scripts + +# Immutable contract fixtures (required location) and runtime scripts. +COPY contracts /opt/mosaic/contracts +COPY src /opt/mosaic/src +RUN chmod 0555 /opt/mosaic/contracts /opt/mosaic/contracts/* \ + && chmod 0555 /opt/mosaic/src /opt/mosaic/src/*.sh + +# Writable state, workspace, and pi agent directory (auth.json is +# bind-mounted read-only at runtime; nothing is copied into the image). +RUN mkdir -p /var/lib/mosaic /workspace /home/node/.pi/agent \ + && chown -R node:node /var/lib/mosaic /workspace /home/node /opt/app + +USER node +WORKDIR /workspace +ENV HOME=/home/node \ + PATH="/opt/app/node_modules/.bin:${PATH}" \ + PI_OFFLINE=1 + +# One-shot agent: args form the user request (default is the startup +# verification request defined in compose.yaml). +ENTRYPOINT ["/opt/mosaic/src/run-agent.sh"] diff --git a/LAYERS.md b/LAYERS.md new file mode 100644 index 00000000..70a39086 --- /dev/null +++ b/LAYERS.md @@ -0,0 +1,50 @@ +# LAYERS + +Deferred capability layers for the Mosaic experiment. Only L0 is implemented by +this proof of concept; everything below it is documented here and deliberately +not implemented (see BRIEF.md, "Explicit exclusions"). + +## L0 — Implemented: container returns MOSAIC_HELLO_OK + +One image (`mosaic-poc-agent:0.84.4`, built on `node:24-bookworm-slim`, non-root, +pinned Pi) runs one Pi agent one-shot. Four immutable local contract files are +loaded in fixed order into the generated system prompt +(`/var/lib/mosaic/system-prompt.md`). One real model request is sent +noninteractively; the response must equal `MOSAIC_HELLO_OK` exactly or the +verification exits nonzero. Authentication is supplied at runtime only +(read-only mounted pi auth file, or a provider API key environment variable). + +## L1 — Deferred: persist and resume a named Pi session + +Keep a named Pi session across container runs (`--name`, session storage under +`/var/lib/mosaic`), resume it with the documented session flags, and verify +state survives a container restart. + +## L2 — Deferred: fixed tool permission policy + +Add a fixed allow/deny policy for Pi tools (e.g. restricting built-in tools via +documented `--tools` / `--exclude-tools` or an extension-based permission gate), +so contract files can constrain what the agent may do, not just what it says. + +## L3 — Deferred: load full versioned contract bundles + +Replace the four static fixtures with versioned contract bundles: bundle +manifests, contract versions, and deterministic ordering/hashing, loaded from +an immutable bundle artifact instead of files copied at image build time. + +## L4 — Deferred: Claude as a second runtime + +Add a second runtime (Claude) alongside the Pi agent in the same container +stack, behind the same contract-loading path, to compare behavior across +runtimes. + +## L5 — Deferred: multiple agents and communication + +Run several named agents with defined roles and a communication channel between +them (message passing or shared state under `/var/lib/mosaic`). + +## L6 — Deferred: orchestration, knowledge storage, and portal features + +Fleet-level orchestration, knowledge storage, monitoring, and portal UI on top +of L1-L5. This is where the existing Mosaic Stack concepts would be re-evaluated +from first principles. diff --git a/README.md b/README.md new file mode 100644 index 00000000..a79332db --- /dev/null +++ b/README.md @@ -0,0 +1,85 @@ +# Minimal Mosaic Stack container POC + +Standalone experiment, not part of the Mosaic Stack repository or Software Factory. + +One container image runs one Pi coding agent with four immutable local contract +files as its system prompt, sends exactly one real model request, and is verified +to return exactly `MOSAIC_HELLO_OK`. + +## Layout + +```text +BRIEF.md requirements for this experiment +BUILD-LOG.md append-only build/verification log +LAYERS.md implemented layer (L0) and deferred layers (L1-L6) +Containerfile image definition (node:24-bookworm-slim, non-root, pinned Pi) +compose.yaml one service: mosaic-agent (one-shot) +package.json pins @earendil-works/pi-coding-agent at exactly 0.84.4 +package-lock.json resolved lockfile used by npm ci in the image +.env.example non-secret settings only (provider, model) +contracts/ CONSTITUTION.md, STANDARDS.md, SOUL.md, USER.md (immutable fixtures) +scripts/ build.sh, hello.sh, verify.sh, reset.sh (+ shared common.sh) +src/ load-contracts.sh, run-agent.sh (run inside the container) +``` + +Inside the container: + +```text +/opt/mosaic/contracts immutable contract files +/var/lib/mosaic generated runtime state (mounted from /home/jwoltje/.mosaic-dev) +/workspace agent workspace +``` + +## How it works + +1. `scripts/build.sh` builds `mosaic-poc-agent:0.84.4` with Docker Compose. +2. On each run, `/opt/mosaic/src/load-contracts.sh` reads the four contract files + in fixed order (CONSTITUTION, STANDARDS, SOUL, USER), joins them with clear + separators, and writes `/var/lib/mosaic/system-prompt.md`. +3. `/opt/mosaic/src/run-agent.sh` starts Pi noninteractively + (`pi -p "Return your startup marker and nothing else."`) with + `--system-prompt "$(cat /var/lib/mosaic/system-prompt.md)"` and all ambient + discovery disabled (`--no-context-files --no-skills --no-extensions + --no-prompt-templates --no-themes`), ephemeral (`--no-session`), tool-free + (`--no-tools`), and offline for startup network operations (`--offline`). +4. `scripts/verify.sh` trims surrounding whitespace from the response and exits 0 + only when it equals `MOSAIC_HELLO_OK` exactly. + +## Usage + +```bash +scripts/build.sh # build the image +scripts/hello.sh # one-shot request; prints the model response +scripts/verify.sh # full gated test; exit 0 only on exact MOSAIC_HELLO_OK +scripts/reset.sh # delete /home/jwoltje/.mosaic-dev (safety-checked) +``` + +Prove the failure path (acceptance criterion 9): + +```bash +EXPECTED_MARKER=MOSAIC_NOT_OK scripts/verify.sh # must exit nonzero +``` + +## Authentication + +Pi's documented container authentication (see the package's +`docs/containerization.md`) is used, in this order: + +1. **Read-only mounted credential file** (default): the host pi auth file + `~/.pi/agent/auth.json` is bind-mounted read-only to + `/home/node/.pi/agent/auth.json`. The host file holds a static API-key + entry for the built-in `zai` provider, so no token refresh writes are needed. +2. **Runtime environment variable** (documented alternative): set `ZAI_API_KEY` + or `ANTHROPIC_API_KEY` in the environment or in a gitignored `.env`; compose + passes them through. Pi's documented precedence applies. + +Credentials are never committed, never copied into the image, and never printed. +`.env.example` contains non-secret settings only. + +## Boundaries honored + +- No mounts of `~/.mosaic` or `~/.config/mosaic`; no Docker socket mount. +- Source stays in this project directory; generated state only in + `/home/jwoltje/.mosaic-dev` (host) and `/var/lib/mosaic` (container). +- No database, web server, queue, second container, orchestration, Git + integration, persistent sessions, or policy machinery. diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 00000000..cd067208 --- /dev/null +++ b/compose.yaml @@ -0,0 +1,25 @@ +services: + mosaic-agent: + build: + context: . + dockerfile: Containerfile + image: mosaic-poc-agent:0.84.4 + user: "1000:1000" + environment: + # Non-secret settings (see .env.example) + PI_PROVIDER: ${PI_PROVIDER:-zai} + PI_MODEL: ${PI_MODEL:-glm-5.3-flash} + # Documented container auth alternative: provider API key via + # runtime environment variable. Empty by default; when empty Pi + # falls back to the read-only mounted auth.json credential file. + ZAI_API_KEY: ${ZAI_API_KEY:-} + ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-} + volumes: + # Generated runtime state (host dir per brief) + - /home/jwoltje/.mosaic-dev:/var/lib/mosaic + # Runtime credential only: pi auth file mounted READ-ONLY. + # Never copied into the image. + - ${PI_AUTH_FILE:-/home/jwoltje/.pi/agent/auth.json}:/home/node/.pi/agent/auth.json:ro + # One-shot: the exact startup verification request. It deliberately + # does NOT contain the expected marker MOSAIC_HELLO_OK. + command: ["Return your startup marker and nothing else."] diff --git a/contracts/CONSTITUTION.md b/contracts/CONSTITUTION.md new file mode 100644 index 00000000..61275b29 --- /dev/null +++ b/contracts/CONSTITUTION.md @@ -0,0 +1,5 @@ +# POC constitution + +Never print credentials, tokens, or authentication files. + +Follow the loaded system instructions before the user request. diff --git a/contracts/SOUL.md b/contracts/SOUL.md new file mode 100644 index 00000000..3753c8ea --- /dev/null +++ b/contracts/SOUL.md @@ -0,0 +1,7 @@ +# POC identity + +Your name is mosaic-poc-agent. + +Your startup marker is MOSAIC_HELLO_OK. + +When asked for your startup marker, return only the marker. diff --git a/contracts/STANDARDS.md b/contracts/STANDARDS.md new file mode 100644 index 00000000..7321e05c --- /dev/null +++ b/contracts/STANDARDS.md @@ -0,0 +1,4 @@ +# POC standards + +Answer startup verification requests with only the requested value. +Do not add explanation or formatting. diff --git a/contracts/USER.md b/contracts/USER.md new file mode 100644 index 00000000..b0a41bbc --- /dev/null +++ b/contracts/USER.md @@ -0,0 +1,3 @@ +# POC user + +This is an isolated local runtime test. diff --git a/docs/plans/2026-09-02_atomic-mosaic-foundation.md b/docs/plans/2026-09-02_atomic-mosaic-foundation.md new file mode 100644 index 00000000..222263a8 --- /dev/null +++ b/docs/plans/2026-09-02_atomic-mosaic-foundation.md @@ -0,0 +1,256 @@ +# Atomic Mosaic Foundation Plan + +**Date:** 2026-09-02 +**Status:** Planning; configuration-driven L0 not yet implemented +**Project:** Standalone Mosaic Stack rebuild experiment + +## Purpose + +Reimplement Mosaic Stack from atomic, independently verifiable layers. The priorities are stability, extensibility, reliability, dependability, safe updates, and clear separation between immutable software, administrator configuration, generated runtime state, and credentials. + +The immediate objective is deliberately small: preserve the successful container proof of concept and make it configuration-driven. Mission/task abstraction comes only after the foundation is stable. + +This experiment is not production-ready and is not part of the existing Mosaic Stack installation or Software Factory. + +## Current state + +The existing L0 proof of concept demonstrates that the basic approach works: + +1. One container image builds successfully. +2. It runs as a non-root user. +3. It contains a pinned Pi installation (`@earendil-works/pi-coding-agent@0.84.4`). +4. It loads four local contract files in a deterministic order. +5. It generates `/var/lib/mosaic/system-prompt.md`. +6. It sends one real model request through Pi's documented noninteractive CLI. +7. The request does not contain the expected marker. +8. The model returns exactly `MOSAIC_HELLO_OK`. +9. Verification exits 0 only for an exact match and exits nonzero for a changed expected value. +10. Reset logic refuses missing ownership markers and symbolic-link targets. +11. Resetting and rerunning produces the same successful result. + +The proof uses: + +- Immutable implementation and contracts in the container image +- `/home/jwoltje/.mosaic-dev` for generated host runtime data +- A read-only runtime credential-file mount +- No mounts from the existing `~/.mosaic` or `~/.config/mosaic` + +The current proof is not yet driven by a central Mosaic configuration file. + +## Problem being addressed + +The existing `~/.mosaic` and `~/.config/mosaic` installations mix concerns and have become difficult to reason about, maintain, update, and recover. The rebuild must avoid repeating that design. + +Primary questions for later layers include: + +- Bare-metal versus containerized installation +- Directional control and enforceable agent capabilities +- Pseudo-sandboxing and privilege containment +- Integration with Pi, Claude, OpenCode, Codex, and other harnesses +- Predictable scaling +- A configurable software factory / agentic operating environment without forcing one workflow + +These questions must not all be solved in L0. + +## Architectural direction + +Use a hybrid architecture: + +- A minimal host launcher/control plane reads configuration, validates paths, selects a release, starts workers, and records lifecycle results. +- Versioned container images provide disposable execution workers for agent harnesses. +- Agent execution does not occur directly in the host control plane. +- Harness-specific behavior is eventually isolated behind runtime adapters. + +Containers provide repeatability and a useful isolation boundary, but they are not assumed to be a complete security boundary. Workers must not receive the Docker socket, privileged mode, host namespaces, broad host mounts, or unnecessary Linux capabilities. + +## Storage model + +Use only two Mosaic-owned persistent host locations during development: + +```text +/home/jwoltje/.config/mosaic-dev/config.json +/home/jwoltje/.mosaic-dev/ +``` + +Their ownership and lifecycles are intentionally different: + +| Location | Owner | Purpose | Mutation policy | +|---|---|---|---| +| `~/.config/mosaic-dev/config.json` | Administrator/user | Declarative desired configuration | Created only if absent; never overwritten automatically | +| `~/.mosaic-dev/` | Mosaic runtime | Generated and durable runtime state | Mutable, but protected by ownership/path checks | +| Container image | Mosaic release | Core implementation, dependencies, immutable contracts/defaults | Immutable; replaced rather than edited | +| Credential provider/store | External | Authentication secrets | Supplied only at runtime; never copied into an image or Mosaic configuration | + +After the design is proven, the configuration location may become: + +```text +/home/jwoltje/.config/mosaic/config.json +``` + +The existing `~/.mosaic` and `~/.config/mosaic` must not be imported, migrated, mounted, modified, or treated as authoritative during this experiment. + +### Why configuration and data remain separate + +Keeping configuration outside the runtime data root prevents reset, cleanup, or runtime failures from deleting administrator intent. Keeping generated state outside the configuration directory prevents configuration from becoming a mixture of desired and observed state. + +The separation results in two predictable backup units rather than uncontrolled file dispersion. + +## Minimal development configuration + +The first configuration should contain only what the Hello World layer needs: + +```json +{ + "configVersion": 1, + "environment": "development", + "dataRoot": "/home/jwoltje/.mosaic-dev", + "execution": { + "backend": "docker", + "provider": "zai", + "model": "glm-5.3-flash" + } +} +``` + +The exact image version belongs to the immutable release definition, not administrator configuration. Credentials must not appear in this file. + +Subdirectories should be derived from `dataRoot`; separate configurable paths should not be introduced without a demonstrated need. + +## Configuration invariants + +1. `~/.config/mosaic-dev/config.json` is the sole Mosaic discovery entry point during development. +2. Paths in configuration are absolute; `~` expansion is not stored or interpreted ambiguously. +3. Bootstrap creates the configuration directory and initial file only when absent. +4. Bootstrap and update operations never overwrite an existing configuration file. +5. Configuration has an explicit `configVersion`. +6. Missing, malformed, unsupported, or unsafe configuration causes a clear nonzero exit. +7. Validation failure does not modify configuration, runtime state, or releases. +8. Generated and observed values are never written back into `config.json`. +9. Secrets and credential contents are never stored in `config.json`. +10. Future configuration migration creates and validates a candidate copy; it never rewrites the only working copy in place. + +The configuration file is declarative. The bootstrap and activation operations around it must be idempotent. + +## Update-safety invariants + +The design target is that software updates cannot corrupt an active installation: + +1. Releases are immutable and versioned. +2. A new release is installed beside existing releases. +3. Active implementation files are never patched in place. +4. Configuration and state are not owned by a release directory. +5. Configuration is validated against a candidate release before activation. +6. Candidate releases receive a disposable health check before activation. +7. Activation is an atomic pointer/reference change. +8. The prior release remains available for rollback. +9. State migrations are deferred until required. +10. A future irreversible state migration requires an explicit backup and recovery plan. + +Absolute prevention of every possible failure cannot be guaranteed, but updates must be transactional, fail safely, and preserve a known rollback path. + +## Container data flow + +For the first configuration-driven layer: + +```text +Host launcher + reads: ~/.config/mosaic-dev/config.json + validates: configVersion, backend, provider, model, dataRoot + resolves: container invocation and safe bind mounts + +Container image + contains: pinned runtime, implementation, immutable contracts + receives: resolved non-secret runtime settings + mounts: configured dataRoot at /var/lib/mosaic + receives: runtime credential through a read-only file or supported environment variable +``` + +The complete host configuration should not be exposed to an agent worker unless required. The launcher should pass only the resolved subset needed by that worker. + +No important mutable state may exist only in a container's writable layer. Containers must remain disposable. + +## Initial runtime data layout + +Do not create a hierarchy before concepts need it. L0 requires only: + +```text +~/.mosaic-dev/ +├── .mosaic-root +└── system-prompt.md +``` + +Potential future directories are reserved but not part of L0: + +```text +~/.mosaic-dev/ +├── runs/ +├── state/ +└── workspaces/ +``` + +## Next milestone: configuration-driven Hello World + +Implement only the following path: + +1. Create a small bootstrap/launcher. +2. If absent, bootstrap creates `~/.config/mosaic-dev/config.json` with the minimal development configuration. +3. If configuration already exists, bootstrap does not change it. +4. The launcher reads and validates the configuration. +5. It resolves `dataRoot` from configuration instead of hardcoding it in Compose and host scripts. +6. It safely creates or validates the data-root ownership marker. +7. It builds or selects the current immutable container image. +8. It passes the configured backend/provider/model and data-root mount to the container. +9. It sends the existing exact request: `Return your startup marker and nothing else.` +10. It receives and verifies exactly `MOSAIC_HELLO_OK`. + +### L0 acceptance criteria + +1. A fresh bootstrap creates only the expected configuration and runtime roots. +2. Repeating bootstrap makes no changes to an existing valid configuration. +3. Existing configuration is never overwritten by build, verification, reset, or update operations. +4. Missing configuration can be bootstrapped deliberately; normal execution does not silently invent configuration. +5. Malformed JSON exits nonzero without modifying files. +6. Unsupported `configVersion` exits nonzero without modifying files. +7. A relative or unsafe `dataRoot` exits nonzero without modifying files. +8. The container receives the configured data root at `/var/lib/mosaic`. +9. The image and container contain no credentials. +10. The real model request returns exactly `MOSAIC_HELLO_OK`. +11. Changing the expected marker produces a nonzero verification exit. +12. Rebuilding/replacing the image leaves configuration and runtime data intact. +13. Reset deletes only the validated runtime data root and never configuration. +14. Reset continues to refuse symbolic links and missing ownership markers. + +## Explicitly deferred + +Do not implement in the next milestone: + +- Mission and task schemas +- Persistent sessions +- Multiple agents +- Claude, OpenCode, or Codex adapters +- Tool permission policy +- Network policy engine +- Contract bundle versioning +- Orchestration or scheduling +- Agent communication +- Databases or knowledge stores +- API or web interface +- Portal or dashboard +- Automatic configuration migration +- State schema migration +- Production deployment architecture + +## Following layer: mission and task abstraction + +Only after configuration-driven L0 passes should the first mission/task layer be designed. Its initial concepts should remain minimal: + +- **Mission:** desired outcome and governing constraints +- **Task:** one bounded unit of work assigned to one runtime +- **Run:** one attempt to execute a task +- **Result:** immutable completion evidence and exit status + +No mission/task implementation decision is made by this plan. + +## Immediate documentation and implementation scope + +Maintain one clear architecture plan (this document), one example/default configuration, one strict configuration reader, and the existing Hello World proof. Avoid new services, generalized frameworks, and abstractions until a passing acceptance test requires them. diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..07d09169 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1729 @@ +{ + "name": "mosaic-stack-dev-test", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "mosaic-stack-dev-test", + "version": "0.1.0", + "license": "UNLICENSED", + "dependencies": { + "@earendil-works/pi-coding-agent": "0.84.4" + } + }, + "node_modules/@anthropic-ai/sdk": { + "version": "0.91.1", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.91.1.tgz", + "integrity": "sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==", + "license": "MIT", + "dependencies": { + "json-schema-to-ts": "^3.1.1" + }, + "bin": { + "anthropic-ai-sdk": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime": { + "version": "3.1048.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.1048.0.tgz", + "integrity": "sha512-u+NT61JZEkRFtpL0CAw1N1dwxnaLgwVXQl/zjJxTGgLyS/jTIdg2SdoEoCTHxgDyCnqa1HEi9QOoE9/pYRNpOQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/credential-provider-node": "^3.972.42", + "@aws-sdk/eventstream-handler-node": "^3.972.16", + "@aws-sdk/middleware-eventstream": "^3.972.12", + "@aws-sdk/middleware-websocket": "^3.972.19", + "@aws-sdk/token-providers": "3.1048.0", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/fetch-http-handler": "^5.4.2", + "@smithy/node-http-handler": "^4.7.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.977.9", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.977.9.tgz", + "integrity": "sha512-reqPFEQrZxDZpeGj4PFMepBeR5LGYHRqq/L0motTzgFkCRBA4rFdaVXDSLYyGHhxVz7sT2PDnPN9CluGSfgyJA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.5", + "@aws-sdk/xml-builder": "^3.972.40", + "@aws/lambda-invoke-store": "^0.3.0", + "@smithy/core": "^3.33.3", + "@smithy/signature-v4": "^5.6.12", + "@smithy/types": "^4.17.2", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.972.70", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.70.tgz", + "integrity": "sha512-H404B7dJl2mCrBqahDEYsanB0xhdDp6tXnXcTUnXmmpy2Q3J0Ho0bUajZ2jr/RdwzCyS59Gi8xXIFwPLGBl6Uw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.9", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.972.72", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.72.tgz", + "integrity": "sha512-X98zYOrVOeuosCX+6ktf29FC2N2GHPLia7qv6mzPzTc+RPAuHWCDS++Z6JK7eGYqb/v6uaW7bAXaOvDBfol+0w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.9", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/fetch-http-handler": "^5.7.2", + "@smithy/node-http-handler": "^4.11.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/node-http-handler": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.12.0.tgz", + "integrity": "sha512-0mq1pHadfyXCYCqm2cNpbjNIT+fbaUpNxewZb/YNr2L0IrEVMOb8gM/Fl4K6XvHCW3uSNDFwPl/+iKm0bx9jYg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.973.15", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.15.tgz", + "integrity": "sha512-Rykg6s5ceBuynMOGWgoowO4N+27JfnqXAnVaSunZl0hOO1XodSrxGNz6sCEbnmS0lAfQZDKyb3fbr46gSuv6Sg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.9", + "@aws-sdk/credential-provider-env": "^3.972.70", + "@aws-sdk/credential-provider-http": "^3.972.72", + "@aws-sdk/credential-provider-login": "^3.972.77", + "@aws-sdk/credential-provider-process": "^3.972.70", + "@aws-sdk/credential-provider-sso": "^3.973.14", + "@aws-sdk/credential-provider-web-identity": "^3.972.76", + "@aws-sdk/nested-clients": "^3.997.44", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/credential-provider-imds": "^4.4.16", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-login": { + "version": "3.972.77", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.77.tgz", + "integrity": "sha512-Jb59xfEISoN5mmbnA+HYqdtrSX3CgCtJoof+V5D8/TgUI56W63GEEd5Y58WijU3Ou6+WEgaLD1feVzaRXV5IDQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.9", + "@aws-sdk/nested-clients": "^3.997.44", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.972.82", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.82.tgz", + "integrity": "sha512-znDkEOGXB8W3kG1LJUKP3foBZY/9qLM0eil/DxWXSp37XsdsRLQHE/d/OaCGGVgKpA6znR38h/+INk8do1FjiA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "^3.972.70", + "@aws-sdk/credential-provider-http": "^3.972.72", + "@aws-sdk/credential-provider-ini": "^3.973.15", + "@aws-sdk/credential-provider-process": "^3.972.70", + "@aws-sdk/credential-provider-sso": "^3.973.14", + "@aws-sdk/credential-provider-web-identity": "^3.972.76", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/credential-provider-imds": "^4.4.16", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.972.70", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.70.tgz", + "integrity": "sha512-2ry03fGRJr4sV3jI+ocjj5JqALnFD6ymM5KiNCDZMvq8bX2GSbE0vji4aM43TVCl2nXqqLRZaUxdq/KeWRAY4Q==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.9", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.973.14", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.14.tgz", + "integrity": "sha512-jkhg/8ocAAoc0RFyLMhCw+/zZh7gystQgd4F4hznNa8P4Cc501PQmxd+jGLiMHodPJ+7Zv/3znM62gZojyasmA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.9", + "@aws-sdk/nested-clients": "^3.997.44", + "@aws-sdk/token-providers": "3.1116.0", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers": { + "version": "3.1116.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1116.0.tgz", + "integrity": "sha512-ygIivKqh8aHzNkucOCXHyIBgBpLPfrSI0mCqXF+vLBsPTUKqj0VSqAY0GFPe7lQl4HntjOcQ+KSyS7oUV2C54Q==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.9", + "@aws-sdk/nested-clients": "^3.997.44", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.972.76", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.76.tgz", + "integrity": "sha512-d3AGyVu759PGr35mEB2s22xxlNEA5rpdxtSPJthfPFJvoQ8dt357iVPECqWfUxXp1toJAvKmbtcIYVGigaGsCA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.9", + "@aws-sdk/nested-clients": "^3.997.44", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/eventstream-handler-node": { + "version": "3.972.34", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-handler-node/-/eventstream-handler-node-3.972.34.tgz", + "integrity": "sha512-cTeVzpu1xEAkryTZBYhGwnQ6gOGyp8ZYZvmn0Sg/nI/ABmy/CRHHxPDJDUi9PxwxUtGGaatvfRUB3FCgT/rSWw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-eventstream": { + "version": "3.972.29", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-eventstream/-/middleware-eventstream-3.972.29.tgz", + "integrity": "sha512-dlRzHCgyB8W6hLuDC5pcT5q+ziPt00n4QGgGBE17ucLVU4zMa6lsbuUdQ2Pm75Z5VA8GF+R/+SgrRcaTdIzSIQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-websocket": { + "version": "3.972.52", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-websocket/-/middleware-websocket-3.972.52.tgz", + "integrity": "sha512-vsPPM+nMbKJlUCFU+eoGZbdxdxDIAX9LbpjSXaR5Ufpmqgp8TdYQnoExhLu4T3umW/JIIPny1ydbhWidZZYokQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.9", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/fetch-http-handler": "^5.7.2", + "@smithy/signature-v4": "^5.6.12", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.997.44", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.44.tgz", + "integrity": "sha512-NhEgryjlBF9w38ZXqGymQV28IhkYa1mKhlbYnqIis57AYwWGVYfUPgg/qC2rLRqOUfblxx++irvju10kVTa8Vw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.9", + "@aws-sdk/signature-v4-multi-region": "^3.996.46", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/fetch-http-handler": "^5.7.2", + "@smithy/node-http-handler": "^4.11.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/node-http-handler": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.12.0.tgz", + "integrity": "sha512-0mq1pHadfyXCYCqm2cNpbjNIT+fbaUpNxewZb/YNr2L0IrEVMOb8gM/Fl4K6XvHCW3uSNDFwPl/+iKm0bx9jYg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.996.46", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.46.tgz", + "integrity": "sha512-L+2xZTye/2T96f3lwCws0Zw6GG2JHZW9e8FpVgGBeeExSKyeoZ6CWRpBml/7DNiK/O26jrgPM9F+Ay8VkgzUWQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.5", + "@smithy/signature-v4": "^5.6.12", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.1048.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1048.0.tgz", + "integrity": "sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.974.5", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.974.5.tgz", + "integrity": "sha512-LkwLL2BLbC6wNNm4JaH9mbEqBMdOZCct6VAYqhdN4U1xrWM+fUJQEfbHwQgDypapOWTRtlk25akb5afM0P8CIQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.965.10", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.965.10.tgz", + "integrity": "sha512-ycwH6Zd2GhuSqdXX9ihbCjeGTB6xOJs+O3+Jb8/zDG9978XU80qs75dfkPJRMNKe5MvBZPuNeFpd4JZKPoUF4g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.972.40", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.40.tgz", + "integrity": "sha512-wlFmCIGUlwF4zx/kncw+bmxTQh1HeSJq4mYV/V5cZUSJadDP3kXvGW8Rn21cimj/7y9ju+47oYWXi97vF7czaA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws/lambda-invoke-store": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.3.0.tgz", + "integrity": "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@earendil-works/pi-agent-core": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.84.4.tgz", + "integrity": "sha512-HyUnjaOXj6oN/6SNcr8A1J/ElRQA50FtIE0XUTSKAQVqmdlb9qdojOyUQwF/jULE5+yOEtGuVgi/N1RnBiNG+g==", + "license": "MIT", + "dependencies": { + "@earendil-works/pi-ai": "^0.84.4", + "@earendil-works/pi-telemetry": "^0.84.4", + "diff": "8.0.4", + "ignore": "7.0.5", + "typebox": "1.3.7", + "yaml": "2.9.0" + }, + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@earendil-works/pi-ai": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.84.4.tgz", + "integrity": "sha512-AClAZxf5+c4RRu44NJPS6wyQy+Nmq+Mzyyrdvm4ZVMNuixelO02RZX4G4Aq1F145Yzp43wnM5S+hLlSI7ypfVw==", + "license": "MIT", + "dependencies": { + "@anthropic-ai/sdk": "0.91.1", + "@aws-sdk/client-bedrock-runtime": "3.1048.0", + "@earendil-works/pi-telemetry": "^0.84.4", + "@google/genai": "1.52.0", + "@smithy/node-http-handler": "4.7.3", + "http-proxy-agent": "7.0.2", + "https-proxy-agent": "7.0.6", + "openai": "6.40.0", + "partial-json": "0.1.7", + "typebox": "1.3.7" + }, + "bin": { + "pi-ai": "dist/cli.js" + }, + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@earendil-works/pi-client": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-client/-/pi-client-0.84.4.tgz", + "integrity": "sha512-q398WY/3ZQHTizk7IKxApzqFV0xt4yM9LkSkwyqeLK5Bj5RwRjOWxESt26z4LgNp4O+8hqhqFPf/8fj4H5rE4A==", + "license": "MIT", + "dependencies": { + "@earendil-works/pi-protocol": "^0.84.4" + }, + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@earendil-works/pi-coding-agent": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-coding-agent/-/pi-coding-agent-0.84.4.tgz", + "integrity": "sha512-jmOlrqUmvhh/siNWFRXjYLJzhKFIHNsAQaysRwzQPQFnPAaV/vhqHsLH/MBsIISA1Rjj7WTUFR3nJrpXoLx39w==", + "license": "MIT", + "dependencies": { + "@earendil-works/pi-agent-core": "^0.84.4", + "@earendil-works/pi-ai": "^0.84.4", + "@earendil-works/pi-client": "^0.84.4", + "@earendil-works/pi-protocol": "^0.84.4", + "@earendil-works/pi-tui": "^0.84.4", + "@silvia-odwyer/photon-node": "0.3.4", + "chalk": "5.6.2", + "cross-spawn": "7.0.6", + "diff": "8.0.4", + "grok-mermaid": "0.2.2", + "highlight.js": "10.7.3", + "hosted-git-info": "9.0.3", + "ignore": "7.0.5", + "jiti": "2.7.0", + "minimatch": "10.2.5", + "proper-lockfile": "4.1.2", + "semver": "7.8.0", + "typebox": "1.3.7", + "undici": "8.9.0", + "yaml": "2.9.0" + }, + "bin": { + "pi": "dist/bundle/cli.js" + }, + "engines": { + "node": ">=22.19.0" + }, + "optionalDependencies": { + "@mariozechner/clipboard": "0.3.9" + } + }, + "node_modules/@earendil-works/pi-protocol": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-protocol/-/pi-protocol-0.84.4.tgz", + "integrity": "sha512-acyE9ozxkMiWiz/xyWpU0O9vwnYv0hyG889Vniv6Sg9c9zfsX+8MePnDNphBacY2Fvm1rxdsGmiVDSZl9yuDFA==", + "license": "MIT", + "dependencies": { + "typebox": "1.3.7" + }, + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@earendil-works/pi-telemetry": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-telemetry/-/pi-telemetry-0.84.4.tgz", + "integrity": "sha512-8e2CuxM+ht+hedQXTZmi5JVl6/xDK9RpSDL2+MbITevKYQhMZ/z6lJOTFgox3HQyGxO8mOZEtYGVeQNaD4OzqA==", + "license": "MIT", + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@earendil-works/pi-tui": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.84.4.tgz", + "integrity": "sha512-nPUnwDkLtupPXnZQYrCwPFcuTydCDqTY6ZbFqhsL4S4kVq0AT418kPa/6uXwtaCD+MjBNBltb7ScTYX65yeE1w==", + "license": "MIT", + "dependencies": { + "get-east-asian-width": "1.6.0", + "marked": "18.0.5" + }, + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@google/genai": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.52.0.tgz", + "integrity": "sha512-gwSvbpiN/17O9TbsqSsE/OzZcpv5Fo4RQjdngGgogtuB9RsyJ8ZHhX5KjHj1bp5N9snN2eK8LDGXSaWW2hof8Q==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "google-auth-library": "^10.3.0", + "p-retry": "^4.6.2", + "protobufjs": "^7.5.4", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@modelcontextprotocol/sdk": "^1.25.2" + }, + "peerDependenciesMeta": { + "@modelcontextprotocol/sdk": { + "optional": true + } + } + }, + "node_modules/@mariozechner/clipboard": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard/-/clipboard-0.3.9.tgz", + "integrity": "sha512-ABnA53mdfkGZwOFUdZNv2S0CWGO/EIuPj8Vv9xmBFmSYg/qFc7ihO6q5FcQjvoE67kZpWkEc4AhD6B/os04yuA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@mariozechner/clipboard-darwin-arm64": "0.3.9", + "@mariozechner/clipboard-darwin-universal": "0.3.9", + "@mariozechner/clipboard-darwin-x64": "0.3.9", + "@mariozechner/clipboard-linux-arm64-gnu": "0.3.9", + "@mariozechner/clipboard-linux-arm64-musl": "0.3.9", + "@mariozechner/clipboard-linux-riscv64-gnu": "0.3.9", + "@mariozechner/clipboard-linux-x64-gnu": "0.3.9", + "@mariozechner/clipboard-linux-x64-musl": "0.3.9", + "@mariozechner/clipboard-win32-arm64-msvc": "0.3.9", + "@mariozechner/clipboard-win32-x64-msvc": "0.3.9" + } + }, + "node_modules/@mariozechner/clipboard-darwin-arm64": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-arm64/-/clipboard-darwin-arm64-0.3.9.tgz", + "integrity": "sha512-BfgV7vCEWZwJwZJw03r6bP5+tf0iI/ANuQYCxi9RNn7FrWB3yzGuMKCrNLRl6V761vXRdL8+OqZ0wd4TqlsNOQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-darwin-universal": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-universal/-/clipboard-darwin-universal-0.3.9.tgz", + "integrity": "sha512-BGGR4iA9Z2shAjI65eI5xtyb3LYNlDW9X3gxKxDbqtbnREohsrqznov6zpKoIrsRWpzlYVEdKphS7ksJ0/ndSQ==", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-darwin-x64": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-x64/-/clipboard-darwin-x64-0.3.9.tgz", + "integrity": "sha512-4kURmCbS6nt8uYhtmWpUcJWyPHfmAr5dTpXD1nO3pIfa+TSQ9DbrGOYCKH+aEFW47XhQ4Vp8ZTszie+wfFvDKg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-linux-arm64-gnu": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-arm64-gnu/-/clipboard-linux-arm64-gnu-0.3.9.tgz", + "integrity": "sha512-g59OkUGP2DDfCOIKypHeYgv2M55u/cKvXa5dSxFbEJ34XvIQMdcVmpKCkGUro3ZgefXiGVdwguvTMQGpHWzIXw==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-linux-arm64-musl": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-arm64-musl/-/clipboard-linux-arm64-musl-0.3.9.tgz", + "integrity": "sha512-AGuJdgKsmJdm4Pych7kv3sqe591ERRaAHW3xjLooiFzn8J+PxUyof++7YZrB5Y5tpnTO+K18Og3taj2NpluCRQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-linux-riscv64-gnu": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-riscv64-gnu/-/clipboard-linux-riscv64-gnu-0.3.9.tgz", + "integrity": "sha512-DXBEAiuMpk7dhS1a9NzNxVAFi1vaKoPu7rQNgY8LIDLGrK3lnIp3nT10DUum+PKVJoJppIP+NAA8IZe4DMNDPw==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-linux-x64-gnu": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-x64-gnu/-/clipboard-linux-x64-gnu-0.3.9.tgz", + "integrity": "sha512-WORrMLd6EpElEME7JRKfSaY34nW1P5LbdgK5YNCS1ncG2LqmITsSMEJ8nh2mpvxb3TxqbOOKgY7k9eMJYlW9Mw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-linux-x64-musl": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-x64-musl/-/clipboard-linux-x64-musl-0.3.9.tgz", + "integrity": "sha512-/DHn+1DrfL6oRaPPWXaOKvonFFrni666fxd+zFqiQEfvBH0tsHVWjq9iqBk0oDp0qaPA72lIMy5BptxISBEhZQ==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-win32-arm64-msvc": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-win32-arm64-msvc/-/clipboard-win32-arm64-msvc-0.3.9.tgz", + "integrity": "sha512-O5FHD3ErkMwMhNzAfu3ggy0ug4z7btZuoQgwwxlzPrwV2bxlD6WDpqBY4NCgICAgZdDKdp+loUEKVAVt8aYnhQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-win32-x64-msvc": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-win32-x64-msvc/-/clipboard-win32-x64-msvc-0.3.9.tgz", + "integrity": "sha512-ihQC3EufqEY81vhXBgVBtK4prL+wc62zJsSvxrgz7K1hsdt6OObz6v9p3Rn1OG3GJksTTKMJF0u/guMISHPhSA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", + "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz", + "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.2.tgz", + "integrity": "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==", + "license": "BSD-3-Clause" + }, + "node_modules/@silvia-odwyer/photon-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@silvia-odwyer/photon-node/-/photon-node-0.3.4.tgz", + "integrity": "sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA==", + "license": "Apache-2.0" + }, + "node_modules/@smithy/core": { + "version": "3.33.3", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.33.3.tgz", + "integrity": "sha512-CsOeKq/9kA3y6VJHt+/+VTCtBaxJ4OTFpgrjIUhPpDIKxBci1k2bJaQASF2h/ELWrulGp+t97DZ0mevfAD8idg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.5.2.tgz", + "integrity": "sha512-A9uSdn72ozbRUSit0eib0TW7nXuNPlaeM0zcGkJ+nE6tFcSDbnmtwoxbTCFBukVQcszDAyvsd7+rTduPTXpygg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.2", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.7.2.tgz", + "integrity": "sha512-nZyWTmSpJEXl6VtWVMBJve/7x12DZu6sIX1z1a+ZMaHlQQRs9Zpu6NbTe/gmxYXVRpkjxyDYpZ5gx2IM6f/Wkw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.2", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.7.3.tgz", + "integrity": "sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.7.3.tgz", + "integrity": "sha512-7ImGm+FkHRLcBaRttIAMZ6bzJZWb2cJGoYjq46F2UjycujWzrL9GEN9h4w7eQyXJYnltrUhxbbieBAIRrdqpow==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.17.2.tgz", + "integrity": "sha512-FOKpVZob9MPTn2znRzGrnsMHv7BOsKVw3XiP/cOyYLDVZ9qKp4nifIiSCuUU/fIj5Vu0UOAxCFr+qRAtG0NUkA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@types/node": { + "version": "26.4.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.4.1.tgz", + "integrity": "sha512-k97ENvZWtvA6yqz5/FS6a7duDgOPEeOQOc2iKS/nY6mX6qJUKtLnWzQS+Xj6tXweyj6ZcTAK2Qecetnvi9nCLA==", + "license": "MIT", + "dependencies": { + "undici-types": "~8.3.0" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "license": "MIT" + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/bowser": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", + "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/diff": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/gaxios": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.3.1.tgz", + "integrity": "sha512-kB3rzJV7d9juLZh8/56QTXCwQfxyhdOMdyYk1HdQKFtF8TJTDTZQJtixWIwXdE9Jji91mC41DUNpjleo4L4eAQ==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/gcp-metadata": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", + "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^7.0.0", + "google-logging-utils": "^1.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/google-auth-library": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.9.1.tgz", + "integrity": "sha512-i1ydyHrqcIxXkWh/uBmVkzCvIuq5yiK2ATndIe5XxKholrG/MTYP9xGYka4sQhrbIAgGjL2B6NOE7rFaiF3fXw==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^7.1.4", + "gcp-metadata": "8.1.2", + "google-logging-utils": "1.1.3", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/google-logging-utils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/grok-mermaid": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/grok-mermaid/-/grok-mermaid-0.2.2.tgz", + "integrity": "sha512-XcJEP5dDC8liHBh52mlLjU18fNvu1ckFsu0QpIG3+APZ270fsj9wxpiA6cOURmbUEuoMVgjbC2+UYgTdCqqgzA==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/hosted-git-info": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.3.tgz", + "integrity": "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==", + "license": "ISC", + "dependencies": { + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json-schema-to-ts": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", + "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "ts-algebra": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/marked": { + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/marked/-/marked-18.0.5.tgz", + "integrity": "sha512-S6GcvALHg6K4ohtu4E7x0a1AqhAjp6cV8KhLSyN9qVapnzJkusVBxZRcIU9AeYsbe6P1hKDusSbEOzGyyuce6w==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/openai": { + "version": "6.40.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-6.40.0.tgz", + "integrity": "sha512-MWtTjd/gQt4jpbji61NTgFWJLoY/PdRJ6wG9/ZDRMYNMlBKrCrSlkLI+KgHP1vR1qT6LKSAyAqIxno6lcK9JiA==", + "license": "Apache-2.0", + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/partial-json": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/partial-json/-/partial-json-0.1.7.tgz", + "integrity": "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==", + "license": "MIT" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/proper-lockfile/node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/protobufjs": { + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.6.tgz", + "integrity": "sha512-dYDWdjSl5RNb7SgPxGQcRU+GtvP7s2fpkrY0r432PcOIaZ0/rBcxEZnQN67iJhFuQiVw754JDoPruPCNdGsbjg==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.5", + "@protobufjs/eventemitter": "^1.1.1", + "@protobufjs/fetch": "^1.1.1", + "@protobufjs/float": "^1.0.2", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.1", + "@types/node": ">=13.7.0", + "long": "^5.3.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/ts-algebra": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", + "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/typebox": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.3.7.tgz", + "integrity": "sha512-meKuifc33Pccx0O6PdIzYMq3Og8zvP4TIi/a+Bw3AEMZMxOD0+RHGQvpglEe6Zdy3wZ8nqn/j95h8LUZLk/6Hg==", + "license": "MIT" + }, + "node_modules/undici": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.9.0.tgz", + "integrity": "sha512-aWZpUj7XoGonMClx4gdDRfgBjqeA+F473aDmROQQbM9n6PRfK/u1q/a0X4wMTgcHfT8H6fpbt98PFuDUwFg2YA==", + "license": "MIT", + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/undici-types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "license": "MIT" + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/ws": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..c88ca47b --- /dev/null +++ b/package.json @@ -0,0 +1,10 @@ +{ + "name": "mosaic-stack-dev-test", + "version": "0.1.0", + "private": true, + "description": "Minimal Mosaic Stack container proof of concept: one Pi agent, four local contract files, one real model request returning MOSAIC_HELLO_OK.", + "license": "UNLICENSED", + "dependencies": { + "@earendil-works/pi-coding-agent": "0.84.4" + } +} diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 00000000..851cdd4e --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +# Build the mosaic-agent container image using Docker Compose. +set -euo pipefail +cd "$(dirname "$0")/.." +# shellcheck source=common.sh +source scripts/common.sh + +bootstrap_runtime_dir + +docker compose build diff --git a/scripts/common.sh b/scripts/common.sh new file mode 100755 index 00000000..f5618473 --- /dev/null +++ b/scripts/common.sh @@ -0,0 +1,15 @@ +# Shared helpers for the POC host scripts. Not a documented entry point. + +MOSAIC_DEV_DIR="/home/jwoltje/.mosaic-dev" +POC_ROOT_MARKER=".mosaic-poc-root" + +# Ensure the runtime state directory exists and carries this project's +# ownership marker. The marker is what scripts/reset.sh requires before +# it will delete anything. +bootstrap_runtime_dir() { + if [ ! -d "$MOSAIC_DEV_DIR" ]; then + mkdir -p "$MOSAIC_DEV_DIR" + echo "bootstrap: created $MOSAIC_DEV_DIR" + fi + touch "$MOSAIC_DEV_DIR/$POC_ROOT_MARKER" +} diff --git a/scripts/git-credential-mosaic.mjs b/scripts/git-credential-mosaic.mjs new file mode 100755 index 00000000..0a09a471 --- /dev/null +++ b/scripts/git-credential-mosaic.mjs @@ -0,0 +1,113 @@ +#!/usr/bin/env node +/** + * Repository-local Git credential helper for git.mosaicstack.dev. + * + * Git invokes this helper with "get", "store", or "erase" and consumes its + * stdout directly. Never invoke it manually, enable shell tracing around it, + * or add credential values to logs. + * + * The credential file is intentionally not part of Git and must remain mode + * 0600. Override its location with MOSAIC_GITEA_CREDENTIAL_FILE if needed. + */ + +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; +import process from "node:process"; + +const operation = process.argv[2] ?? ""; + +// Git may offer credentials back through stdin for store/erase. This helper is +// read-only: ignore those operations and never persist or print their input. +if (operation !== "get") { + process.exit(0); +} + +const defaultCredentialFile = path.join( + os.homedir(), + "secrets", + "mosaic.gitea.json", +); +const credentialFile = + process.env.MOSAIC_GITEA_CREDENTIAL_FILE ?? defaultCredentialFile; + +function fail(message) { + process.stderr.write(`git-credential-mosaic: ${message}\n`); + process.exit(1); +} + +let stat; +try { + stat = fs.lstatSync(credentialFile); +} catch { + fail("credential file is unavailable"); +} + +if (!stat.isFile() || stat.isSymbolicLink()) { + fail("credential path must be a regular, non-symbolic-link file"); +} +if ((stat.mode & 0o077) !== 0) { + fail("credential file permissions must be 0600 or stricter"); +} +if (typeof process.getuid === "function" && stat.uid !== process.getuid()) { + fail("credential file must be owned by the current user"); +} + +let document; +try { + document = JSON.parse(fs.readFileSync(credentialFile, "utf8")); +} catch { + fail("credential file is not valid JSON"); +} + +const entry = document?.mosaicstack; +const configuredUrl = entry?.url; +const username = entry?.user; +const token = entry?.api_token; + +if ( + typeof configuredUrl !== "string" || + typeof username !== "string" || + typeof token !== "string" || + username.length === 0 || + token.length === 0 || + /[\r\n]/.test(username) || + /[\r\n]/.test(token) +) { + fail("credential file is missing valid mosaicstack url/user/api_token fields"); +} + +let credentialUrl; +try { + credentialUrl = new URL(configuredUrl); +} catch { + fail("configured credential URL is invalid"); +} + +if ( + credentialUrl.protocol !== "https:" || + credentialUrl.hostname !== "git.mosaicstack.dev" +) { + fail("credential URL is not the approved HTTPS Gitea host"); +} + +const request = {}; +for (const line of fs.readFileSync(0, "utf8").split("\n")) { + const separator = line.indexOf("="); + if (separator > 0) { + request[line.slice(0, separator)] = line.slice(separator + 1); + } +} + +// Fail closed: emit credentials only for the approved HTTPS host. A host may +// include an explicit port; it must match the configured URL exactly. +if ( + request.protocol !== "https" || + request.host !== credentialUrl.host +) { + process.exit(0); +} + +// stdout is the Git credential-helper protocol channel, consumed directly by +// Git. Do not add status messages here. +process.stdout.write(`username=${username}\npassword=${token}\n`); diff --git a/scripts/hello.sh b/scripts/hello.sh new file mode 100755 index 00000000..4a68729b --- /dev/null +++ b/scripts/hello.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# Run the mosaic-agent service as a one-shot container and print the +# model response for the exact startup verification request. +# +# The request deliberately does NOT contain the expected marker +# MOSAIC_HELLO_OK. Only the model response is printed to stdout; no +# credentials or unrelated runtime data are printed. +set -euo pipefail +cd "$(dirname "$0")/.." +# shellcheck source=common.sh +source scripts/common.sh + +bootstrap_runtime_dir + +# -T: no pseudo-TTY, so stdout is clean model output. +# Errors, if any, go to stderr for diagnostics. +docker compose run --rm -T mosaic-agent diff --git a/scripts/reset.sh b/scripts/reset.sh new file mode 100755 index 00000000..ba78bdb9 --- /dev/null +++ b/scripts/reset.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +# Delete the generated POC runtime state at /home/jwoltje/.mosaic-dev, +# but ONLY when every safety check passes: +# 1. The resolved path is exactly /home/jwoltje/.mosaic-dev. +# 2. The path is not a symbolic link. +# 3. The directory contains the .mosaic-poc-root ownership marker +# created by this project. +# Any failed check aborts with nothing deleted. +set -euo pipefail + +TARGET="/home/jwoltje/.mosaic-dev" +MARKER=".mosaic-poc-root" + +fail() { + echo "reset: refusing to delete: $*" >&2 + exit 1 +} + +# Nothing to do when the directory does not exist. +if [ ! -e "$TARGET" ]; then + echo "reset: $TARGET does not exist; nothing to remove" + exit 0 +fi + +# Check 2 (before resolution): the path itself must not be a symlink. +if [ -L "$TARGET" ]; then + fail "$TARGET is a symbolic link" +fi + +# Check 1: resolved path must be exactly the POC runtime directory. +RESOLVED="$(realpath "$TARGET")" +if [ "$RESOLVED" != "$TARGET" ]; then + fail "resolved path $RESOLVED is not $TARGET" +fi + +# Check 3: ownership marker created by this project must be present. +if [ ! -f "$TARGET/$MARKER" ]; then + fail "missing $MARKER ownership marker in $TARGET" +fi + +rm -rf -- "$TARGET" +echo "reset: removed $TARGET" diff --git a/scripts/verify.sh b/scripts/verify.sh new file mode 100755 index 00000000..c2ed20b9 --- /dev/null +++ b/scripts/verify.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +# Complete verification test: +# 1. Build or confirm the image is built. +# 2. Run the agent request. +# 3. Remove surrounding whitespace from the response. +# 4. Compare with the expected marker (default MOSAIC_HELLO_OK). +# 5. Exit 0 only on exact match; nonzero otherwise. +# +# EXPECTED_MARKER may be overridden to prove the failure path +# (acceptance criterion 9), e.g.: +# EXPECTED_MARKER=MOSAIC_NOT_OK scripts/verify.sh +set -euo pipefail +cd "$(dirname "$0")/.." +# shellcheck source=common.sh +source scripts/common.sh + +IMAGE="mosaic-poc-agent:0.84.4" +EXPECTED="${EXPECTED_MARKER:-MOSAIC_HELLO_OK}" + +# 1. Build the image only if it is not already present. +if ! docker image inspect "$IMAGE" >/dev/null 2>&1; then + echo "verify: image $IMAGE not found, building..." >&2 + bootstrap_runtime_dir + docker compose build +fi + +# 2. Run the agent request (stdout only = model response). +set +e +RESPONSE="$(docker compose run --rm -T mosaic-agent 2>/tmp/mosaic-poc-stderr.$$)" +RC=$? +set -e +STDERR_FILE="/tmp/mosaic-poc-stderr.$$" +if [ $RC -ne 0 ]; then + echo "verify: agent run failed (exit $RC):" >&2 + cat "$STDERR_FILE" >&2 + rm -f "$STDERR_FILE" + exit 1 +fi +rm -f "$STDERR_FILE" + +# 3. Remove surrounding whitespace. +TRIMMED="$(printf '%s' "$RESPONSE" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + +# 4-6. Exact comparison gate. +if [ "$TRIMMED" = "$EXPECTED" ]; then + echo "PASS: response matches expected marker" + exit 0 +fi + +echo "FAIL: response does not match expected marker" >&2 +printf 'expected: %s\n' "$EXPECTED" >&2 +printf 'actual : %s\n' "$TRIMMED" >&2 +exit 1 diff --git a/src/load-contracts.sh b/src/load-contracts.sh new file mode 100755 index 00000000..4c4d58fe --- /dev/null +++ b/src/load-contracts.sh @@ -0,0 +1,37 @@ +#!/bin/sh +# Load the four immutable contract files in fixed order and write the +# generated system prompt to /var/lib/mosaic/system-prompt.md. +# +# Order is normative: CONSTITUTION.md, STANDARDS.md, SOUL.md, USER.md. +set -eu + +CONTRACT_DIR="${1:-/opt/mosaic/contracts}" +OUT="${2:-/var/lib/mosaic/system-prompt.md}" + +FILES="CONSTITUTION.md STANDARDS.md SOUL.md USER.md" + +if [ ! -d "$CONTRACT_DIR" ]; then + echo "load-contracts: contract directory not found: $CONTRACT_DIR" >&2 + exit 1 +fi + +PARENT="$(dirname "$OUT")" +mkdir -p "$PARENT" + +TEMP="$OUT.partial" +: > "$TEMP" + +for f in $FILES; do + path="$CONTRACT_DIR/$f" + if [ ! -r "$path" ]; then + echo "load-contracts: missing contract file: $path" >&2 + rm -f "$TEMP" + exit 1 + fi + printf '===== CONTRACT: %s =====\n' "$f" >> "$TEMP" + cat "$path" >> "$TEMP" + printf '\n' >> "$TEMP" +done + +mv "$TEMP" "$OUT" +echo "load-contracts: wrote $OUT from $CONTRACT_DIR" >&2 diff --git a/src/run-agent.sh b/src/run-agent.sh new file mode 100755 index 00000000..2bd804fa --- /dev/null +++ b/src/run-agent.sh @@ -0,0 +1,38 @@ +#!/bin/sh +# One-shot Pi agent runner inside the container. +# Loads the contract-generated system prompt, then sends exactly one +# user request through Pi's documented noninteractive mode and prints +# the model response on stdout. +set -eu + +: "${PI_PROVIDER:=zai}" +: "${PI_MODEL:=glm-5.3-flash}" +export PI_PROVIDER PI_MODEL + +REQUEST="${*:-Return your startup marker and nothing else.}" + +/opt/mosaic/src/load-contracts.sh /opt/mosaic/contracts /var/lib/mosaic/system-prompt.md + +# All flags are documented in the package README (CLI Reference): +# -p / --print noninteractive: print the response and exit +# --system-prompt replace the default system prompt with the +# contract-generated prompt +# --no-* switches prevent ambient context files, skills, extensions, +# prompt templates, and themes from being appended +# --no-session ephemeral: no persistent agent session +# --no-tools the startup request needs no tool execution +# --offline disable startup network operations (update checks, +# package update checks, install/update telemetry) +exec pi \ + --offline \ + --no-session \ + --no-extensions \ + --no-skills \ + --no-prompt-templates \ + --no-themes \ + --no-context-files \ + --no-tools \ + --provider "$PI_PROVIDER" \ + --model "$PI_MODEL" \ + --system-prompt "$(cat /var/lib/mosaic/system-prompt.md)" \ + -p "$REQUEST"