From dd8e40affabd3dda7146a867a24af2a703beb9d8 Mon Sep 17 00:00:00 2001 From: Cameron Cooke Date: Sat, 25 Apr 2026 20:48:41 +0100 Subject: [PATCH 1/2] chore: add AGENTS.md and document AI collaborator workflow Adds AGENTS.md for sub-agent contributors and expands CLAUDE.md with docs-authoring conventions used throughout the rest of this PR. --- AGENTS.md | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ CLAUDE.md | 18 ++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..34f0ac7 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,61 @@ +# Project Rules + +- Never use em dashes (—) in any content. Use commas, periods, colons, or parentheses instead. + +## Docs site + +### Audience +Two audiences share the public facing groups (Overview, Getting Started, Usage, Reference, Guides). Both sit on the public API side of XcodeBuildMCP: + +- **End user**: a developer using a coding agent (via their MCP client) or the CLI to build iOS or macOS apps. XcodeBuildMCP extends their agent's capabilities. +- **Agent / MCP client**: the tool integrating with the MCP server. + +Public docs cover the public API only: MCP spec features XcodeBuildMCP implements (structured content, resources, notifications, tool annotations, and so on), tools and what they do, MCP resources, configuration, session defaults, env vars, workflow management, CLI and its API, CLI and MCP output formats. Tool annotations (`readOnlyHint`, `destructiveHint`, `openWorldHint`) are part of the public MCP response, so document them in public pages, not Contributing. + +The **Contributing** group is for people modifying XcodeBuildMCP itself. In scope: tool manifest files, tool authoring, internal architecture a contributor needs to add, edit, or remove a tool or workflow (rendering pipeline, tool registration, schemas, testing strategy). Contributors only need internals inside their authoring domain. Other internals do not need a doc home. + +Placement rules when writing or moving content: + +- An end user or MCP client needs it to use XcodeBuildMCP: public group. +- Only a contributor adding, editing, or removing a tool, workflow, or manifest needs it: Contributing. +- Neither: delete, do not invent a home for it. +- Frame public docs by user visible outcome, not implementation. Never leak source code literals (for example `{ sentry: true }` in server code, internal type names, private function names) into public pages. +- When a spec feature is part of the public MCP response, it belongs in public docs regardless of how MCP literate the reader is. + +### Adding or editing a page + +Content lives at `app/docs/_content/.mdx`. To add a new page, also update: + +- `app/docs/_data/routes.ts`: add the slug to `DocSlug`, `PAGES_ORDER`, `PAGE_META`, and a `SIDEBAR_GROUPS` entry (top-level `items` or a `children` entry for sub-nav). +- `app/docs/_content/index.ts`: import the MDX and add it to `PAGE_COMPONENTS`. + +### Available in every MDX file (no imports needed) + +- `body` +- `... }, ...]} />` +- `` (full tool catalog) +- ``, ``, ``, ``, `` (inline values) +- ``, `` +- Fenced code blocks render with a copy button and language badge. + +### Import explicitly in MDX when needed + +- `` from `../_components/page-header` +- `` (intro only) from `../_components/hero` +- `` from `../_components/icons` + +### Dynamic data + +- Prefer `` etc. over hardcoding counts, workflow names, or versions. These pull from the latest release of `getsentry/XcodeBuildMCP` with a 1-hour revalidation window. +- Refresh the bundled fallback snapshot with `pnpm run docs:sync` when you need up-to-the-minute data during local development. + +### Routing + +- The introduction is served at `/docs`, not `/docs/introduction` (the latter 404s). +- Link to a heading with `/docs/#`. Heading ids are generated automatically. + +### Commands + +- `pnpm dev`: local dev server +- `pnpm build`: production build (static-generates every docs route) +- `pnpm run docs:sync`: refresh the bundled XcodeBuildMCP manifest snapshot diff --git a/CLAUDE.md b/CLAUDE.md index 4c818d4..34f0ac7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,6 +4,24 @@ ## Docs site +### Audience +Two audiences share the public facing groups (Overview, Getting Started, Usage, Reference, Guides). Both sit on the public API side of XcodeBuildMCP: + +- **End user**: a developer using a coding agent (via their MCP client) or the CLI to build iOS or macOS apps. XcodeBuildMCP extends their agent's capabilities. +- **Agent / MCP client**: the tool integrating with the MCP server. + +Public docs cover the public API only: MCP spec features XcodeBuildMCP implements (structured content, resources, notifications, tool annotations, and so on), tools and what they do, MCP resources, configuration, session defaults, env vars, workflow management, CLI and its API, CLI and MCP output formats. Tool annotations (`readOnlyHint`, `destructiveHint`, `openWorldHint`) are part of the public MCP response, so document them in public pages, not Contributing. + +The **Contributing** group is for people modifying XcodeBuildMCP itself. In scope: tool manifest files, tool authoring, internal architecture a contributor needs to add, edit, or remove a tool or workflow (rendering pipeline, tool registration, schemas, testing strategy). Contributors only need internals inside their authoring domain. Other internals do not need a doc home. + +Placement rules when writing or moving content: + +- An end user or MCP client needs it to use XcodeBuildMCP: public group. +- Only a contributor adding, editing, or removing a tool, workflow, or manifest needs it: Contributing. +- Neither: delete, do not invent a home for it. +- Frame public docs by user visible outcome, not implementation. Never leak source code literals (for example `{ sentry: true }` in server code, internal type names, private function names) into public pages. +- When a spec feature is part of the public MCP response, it belongs in public docs regardless of how MCP literate the reader is. + ### Adding or editing a page Content lives at `app/docs/_content/.mdx`. To add a new page, also update: From 3db4301959b0ac7051d0e2798a620a22667aa860 Mon Sep 17 00:00:00 2001 From: Cameron Cooke Date: Sat, 25 Apr 2026 20:49:08 +0100 Subject: [PATCH 2/2] feat(docs): rewrite contributor and end-user pages Two coordinated rewrites of the docs site, driven by the audit documents under docs/. Contributing / Architecture is now readable end-to-end without prior project knowledge. architecture.mdx is the canonical entry point with a Core terms glossary defining workflow, manifest, predicate, exposure, availability, runtime boundary, tool handler, fragment, structured output, next step, rendering, render session, daemon, and transport. Each architecture subpage opens with a plain-English orientation and a Terms-used-here recap that links back to the canonical glossary. contributing.mdx, tool-authoring.mdx, and testing.mdx received targeted define-before-use fixes. The Streaming tools section in tool-authoring was rewritten from one opaque example into three clearly scoped patterns: raw subprocess transcript (CLI raw mode only), typed domain fragments, and the xcodebuild pipeline; each helper in the pipeline table is explained, and a callout warns about ctx variable shadowing inside pipeline executors. End-user pages were polished per docs/reviews/docs-audit-end-user-vs- contributing.md: dropped the internal TypeScript interface and the XCODEBUILDMCP_CLI_OUTPUT_FORMAT section from output-formats.mdx, rewrote the tool-annotations passage in mcp-mode.mdx in user voice, and made small framing fixes across cli.mdx, xcode-ide.mdx, privacy.mdx, session-defaults.mdx, workflows.mdx, introduction.mdx, and setup.mdx. New pages: mcp-protocol-support.mdx declares which MCP protocol features XcodeBuildMCP implements, with full annotation key reference for power users. output-formats.mdx is rebuilt with cleaner separation of CLI output modes vs MCP structuredContent. Site infrastructure: new MermaidDiagram component for the diagrams in the architecture pages; routes.ts and index.ts updated to register all new pages and reorder the sidebar; small fixes to tabs.tsx, mdx-components.tsx, and scraps.css. The Contributing rewrite was validated by simulating six fresh-Claude readers asking realistic onboarding questions; all six landed correct answers, and the inconsistencies they surfaced (glossary gaps, a duplicate table cell, naming drift between final structured response and final envelope) have been patched. Audit documents under docs/ are checked in as supporting context for future passes; they are not published on the site. --- app/docs/_components/mermaid-diagram.tsx | 139 +++ app/docs/_components/tabs.tsx | 2 +- app/docs/_content/architecture-daemon.mdx | 123 +++ .../architecture-manifest-visibility.mdx | 104 +++ .../architecture-rendering-output.mdx | 129 +++ .../architecture-runtime-boundaries.mdx | 141 +++ .../_content/architecture-startup-config.mdx | 114 +++ .../_content/architecture-tool-lifecycle.mdx | 108 +++ app/docs/_content/architecture.mdx | 144 ++++ app/docs/_content/cli.mdx | 42 +- app/docs/_content/contributing.mdx | 235 +++++ app/docs/_content/index.ts | 24 + app/docs/_content/introduction.mdx | 2 +- app/docs/_content/mcp-mode.mdx | 58 +- app/docs/_content/mcp-protocol-support.mdx | 111 +++ app/docs/_content/output-formats.mdx | 320 +++++++ app/docs/_content/privacy.mdx | 2 +- app/docs/_content/session-defaults.mdx | 47 +- app/docs/_content/setup.mdx | 2 +- app/docs/_content/testing.mdx | 150 ++++ app/docs/_content/tool-authoring.mdx | 391 +++++++++ app/docs/_content/workflows.mdx | 61 +- app/docs/_content/xcode-ide.mdx | 2 +- app/docs/_data/routes.ts | 128 ++- app/docs/_styles/scraps.css | 3 + ...hitecture-doc-accuracy-audit-2026-04-25.md | 251 ++++++ .../docs-audit-end-user-vs-contributing.md | 293 +++++++ mdx-components.tsx | 11 +- package.json | 1 + pnpm-lock.yaml | 805 ++++++++++++++++++ 30 files changed, 3791 insertions(+), 152 deletions(-) create mode 100644 app/docs/_components/mermaid-diagram.tsx create mode 100644 app/docs/_content/architecture-daemon.mdx create mode 100644 app/docs/_content/architecture-manifest-visibility.mdx create mode 100644 app/docs/_content/architecture-rendering-output.mdx create mode 100644 app/docs/_content/architecture-runtime-boundaries.mdx create mode 100644 app/docs/_content/architecture-startup-config.mdx create mode 100644 app/docs/_content/architecture-tool-lifecycle.mdx create mode 100644 app/docs/_content/architecture.mdx create mode 100644 app/docs/_content/contributing.mdx create mode 100644 app/docs/_content/mcp-protocol-support.mdx create mode 100644 app/docs/_content/output-formats.mdx create mode 100644 app/docs/_content/testing.mdx create mode 100644 app/docs/_content/tool-authoring.mdx create mode 100644 docs/investigations/architecture-doc-accuracy-audit-2026-04-25.md create mode 100644 docs/reviews/docs-audit-end-user-vs-contributing.md diff --git a/app/docs/_components/mermaid-diagram.tsx b/app/docs/_components/mermaid-diagram.tsx new file mode 100644 index 0000000..e47fd52 --- /dev/null +++ b/app/docs/_components/mermaid-diagram.tsx @@ -0,0 +1,139 @@ +"use client" + +import { useEffect, useId, useMemo, useState } from "react" +import { Maximize2 } from "lucide-react" +import { + Dialog, + DialogContent, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog" + +interface MermaidDiagramProps { + source: string +} + +const baseConfig = { + startOnLoad: false, + theme: "default" as const, + fontSize: 16, + flowchart: { useMaxWidth: false, htmlLabels: true, padding: 16 }, + sequence: { useMaxWidth: false, actorFontSize: 15, noteFontSize: 14, messageFontSize: 14 }, + // @ts-expect-error mermaid types lag the runtime config surface + stateDiagram: { useMaxWidth: false }, +} + +// Mermaid renders text labels via + HTML, which inherit `color` +// from the page body. In dark-mode pages the body color is white, so the labels +// disappear against the diagram's light fills. Inject a scoped ` + +function fitSvg(svg: string): string { + return svg + .replace(/(]*?)\sstyle="([^"]*?)"/, (_match, prefix, style) => { + const cleaned = style + .replace(/max-width:\s*[^;]+;?/g, "") + .replace(/^\s*;\s*/, "") + .trim() + return cleaned ? `${prefix} style="${cleaned}"` : prefix + }) + .replace(/(]*?)\swidth="[^"]*"/, "$1") + .replace(/(]*?)\sheight="[^"]*"/, "$1") + .replace(/]*?>)/, `$1${colorLockStyle}`) +} + +export function MermaidDiagram({ source }: MermaidDiagramProps) { + const [svg, setSvg] = useState(null) + const [error, setError] = useState(null) + const [open, setOpen] = useState(false) + const baseId = useId() + + const diagramId = useMemo(() => baseId.replace(/[^a-zA-Z0-9_-]/g, ""), [baseId]) + + useEffect(() => { + let isMounted = true + + const renderDiagram = async () => { + try { + setSvg(null) + setError(null) + + const mermaid = (await import("mermaid")).default + mermaid.initialize(baseConfig) + + const { svg: rendered } = await mermaid.render(`mermaid-${diagramId}-${Date.now()}`, source) + if (isMounted) { + setSvg(fitSvg(rendered)) + } + } catch (renderError) { + if (isMounted) { + setError(renderError instanceof Error ? renderError.message : "Unable to render Mermaid diagram") + } + } + } + + if (!source.trim()) { + setSvg("") + return () => { + isMounted = false + } + } + + void renderDiagram() + + return () => { + isMounted = false + } + }, [diagramId, source]) + + if (error) { + return ( +
+

Diagram failed to render: {error}

+
+          {source}
+        
+
+ ) + } + + if (svg === null) { + return -
{tabs[i]?.content}
+
{tabs[i]?.content}
) } diff --git a/app/docs/_content/architecture-daemon.mdx b/app/docs/_content/architecture-daemon.mdx new file mode 100644 index 0000000..c5aac30 --- /dev/null +++ b/app/docs/_content/architecture-daemon.mdx @@ -0,0 +1,123 @@ +import { PageHeader } from "../_components/page-header" + + + +Some tool work has to outlive the shell command that started it — an active debug session, an in-progress video capture, an open Xcode bridge. The CLI process exits as soon as the shell command finishes, so that state has nowhere to live. This page is about the per-workspace background process that owns that kind of work, and the lifecycle that decides when it starts, what it owns, and when it shuts down. + +## Terms used here + +See the full glossary at [Core terms](/docs/architecture#core-terms). + +- **daemon** — The workspace-scoped background process (`xcodebuildmcp daemon`) that owns stateful tool work — debug sessions, video captures, long-running SwiftPM work, the Xcode IDE bridge — across short-lived CLI commands. +- **transport** — The wire a request travels on; for the daemon, that is a Unix socket scoped to the workspace. +- **tool handler** — The shared function the daemon hosts on behalf of stateful tools; the same function the in-process CLI would have called. +- **workspace root** — The project root that owns configuration and daemon state, used to derive a stable key for the daemon socket. + +## Why the daemon exists + +CLI processes are short-lived. That is good for scripts, but bad for work that needs state after the command exits. Debug sessions, video recording, background Swift Package work, log capture, and the Xcode IDE bridge all need an owner that survives one shell command. + +The daemon is that owner. The CLI still provides the user-facing command surface and output mode. The daemon owns stateful execution, streams fragments back to the CLI, and returns final structured output when the tool finishes or the stateful action reaches its response boundary. + +## Lifecycle + +```mermaid +stateDiagram-v2 + [*] --> NotRunning + + NotRunning --> AutoStarting: first stateful CLI invocation + AutoStarting --> Listening: daemon start succeeds + AutoStarting --> StartFailed: startup timeout or launch failure + StartFailed --> NotRunning: user retries or starts manually + + Listening --> HandlingRequest: tool.invoke or xcode-ide.invoke + HandlingRequest --> Streaming: fragments emitted + Streaming --> HandlingRequest: more fragments + HandlingRequest --> Listening: final result frame sent + + Listening --> IdleCandidate: idle timeout elapsed + IdleCandidate --> Listening: in-flight requests > 0 + IdleCandidate --> Listening: active runtime sessions remain + IdleCandidate --> GracefulShutdown: no in-flight requests and no active sessions + + Listening --> GracefulShutdown: daemon.stop + Listening --> GracefulShutdown: SIGTERM / SIGINT + + GracefulShutdown --> Cleanup: close server, remove registry, remove socket + Cleanup --> NotRunning + + NotRunning --> [*] +``` + +## Workspace scoping + +Each daemon is scoped to one workspace. XcodeBuildMCP derives the workspace identity from the project config location when `.xcodebuildmcp/config.yaml` exists. Otherwise it uses the current directory. That workspace root becomes a stable key for the daemon socket path. + +| Concept | Meaning | +|---------|---------| +| Workspace root | The project root that owns config and daemon state. | +| Workspace key | A stable derived key used to separate daemon instances. | +| Socket path | The local Unix socket the CLI uses to talk to that workspace daemon. | + +This avoids sharing debugger state, video sessions, or bridge state across unrelated projects. + +## Startup and routing + +A tool opts into daemon routing through manifest routing metadata. When the CLI invokes a stateful tool, the invoker checks whether the workspace daemon is already running. If it is not, the invoker starts it, waits for the socket, and then sends the tool invocation over the daemon protocol. + +The user-facing command does not change: + +```shell +xcodebuildmcp simulator record-video --simulator-id --output-path ./session.mp4 +``` + +The routing choice is internal. The shell still sees CLI output in the requested mode. + +## Protocol shape + +The daemon protocol has two jobs: + +1. Forward progress fragments back to the CLI while the daemon-owned handler runs. +2. Return the final structured output and next-step data when the invocation reaches a response boundary. + +That mirrors direct CLI invocation. The difference is process ownership: direct tools run in the CLI process, daemon-routed tools run in the workspace daemon and stream events back to the CLI client. + +## Idle shutdown + +The default idle timeout is 10 minutes. It can be overridden with `XCODEBUILDMCP_DAEMON_IDLE_TIMEOUT_MS`. + +The daemon shuts down only when all of these are true: + +| Gate | Why it matters | +|------|----------------| +| Idle timeout elapsed | Avoids stopping immediately between related commands. | +| No in-flight requests | Avoids killing an active invocation before it sends its final frame. | +| No active runtime sessions | Avoids killing stateful sessions that still own work. | + +This is stricter than just checking for an empty session list. It protects both active protocol requests and longer-lived runtime sessions. + +## Manual control + +The CLI exposes daemon commands for inspection and recovery: + +```shell +xcodebuildmcp daemon status +xcodebuildmcp daemon start +xcodebuildmcp daemon stop +xcodebuildmcp daemon restart +xcodebuildmcp daemon list +xcodebuildmcp daemon logs +``` + +Use manual control for debugging. Normal stateful tool calls auto-start the daemon and do not require setup. + +## Related + +- [CLI](/docs/cli#per-workspace-daemon), user-facing daemon behavior +- [Environment Variables](/docs/env-vars), daemon and startup overrides +- [Troubleshooting](/docs/troubleshooting), common local failures +- [Runtime Boundaries](/docs/architecture-runtime-boundaries#direct-vs-daemon-routed-tools), why daemon routing belongs to CLI diff --git a/app/docs/_content/architecture-manifest-visibility.mdx b/app/docs/_content/architecture-manifest-visibility.mdx new file mode 100644 index 0000000..58fa9c1 --- /dev/null +++ b/app/docs/_content/architecture-manifest-visibility.mdx @@ -0,0 +1,104 @@ +import { PageHeader } from "../_components/page-header" + + + +XcodeBuildMCP's MCP server, CLI, and daemon all need to know the same things about a tool — its protocol name, command name, description, output schema, and the conditions under which it should be visible. This page covers the two layers that handle that: the YAML files that declare tools, workflows, and resources without containing implementation code, and the rules that decide which of those declarations actually reach the caller. + +## Terms used here + +- **manifest** — A YAML file under `manifests/` that declares a tool, workflow, or resource as metadata, without containing the implementation. Example: `manifests/tools/list_sims.yaml` declares the `list_sims` tool's MCP and CLI names and its output schema reference, while the implementation lives separately in `src/mcp/tools/simulator/list_sims.ts`. +- **workflow** — A named group of related tools (such as simulator, device, or debugging) that callers can opt into so the advertised catalog stays small. +- **predicate** — A named runtime check that decides whether a manifest entry is eligible for the current process. Example: a tool tagged with the `debugEnabled` predicate stays hidden unless debug mode was enabled at startup. +- **exposure** — The final decision to advertise a tool or resource on a runtime, after workflow selection, predicates, and availability checks have all agreed. Example: `list_sims` is exposed on MCP only when the simulator workflow is selected, every predicate on the manifest passes, and `availability.mcp` is `true`. +- **availability** — A manifest field that declares whether a tool can be exposed on MCP, CLI, or both. + +For the canonical glossary, see [Core terms](/docs/architecture#core-terms). + +## Why metadata lives in manifests + +Tool metadata is consumed by more than one boundary. MCP registration needs protocol names, annotations, output schemas, and descriptions. CLI registration needs command names, workflow grouping, descriptions, and routing hints. Docs and generated references need the same source of truth. + +Keeping that metadata in YAML prevents each runtime from inventing its own catalog. The implementation file stays focused on input validation and work execution. The manifest explains how that implementation is exposed. + +## Manifest roles + +| Directory | Defines | Used by | +|-----------|---------|---------| +| `manifests/tools/` | Tool ID, implementation module, MCP and CLI names, description, annotations, availability, predicates, routing, next steps, output schema metadata. | MCP registration, CLI command generation, daemon catalog, generated docs, schema checks. | +| `manifests/workflows/` | Workflow ID and tool membership. | Workflow selection, sidebar grouping in generated references, MCP catalog trimming. | +| `manifests/resources/` | MCP resource metadata and module handler. | MCP resource registration. | + +Tool modules are imported only after the manifest has been loaded and filtered. A tool module must export named `schema` and `handler` values. Resource modules have their own contract and require a handler, so avoid treating the tool-module contract as universal. + +## Load, validate, import + +```mermaid +flowchart LR + ToolsYaml["manifests/tools/*.yaml"] + WorkflowsYaml["manifests/workflows/*.yaml"] + ResourcesYaml["manifests/resources/*.yaml"] + + ToolsYaml --> Load["loadYamlFiles()"] + WorkflowsYaml --> Load + ResourcesYaml --> Load + + Load --> Zod["Zod validation
schema.ts"] + Zod --> PredicateCheck["Validate predicate names
predicate-registry.ts"] + PredicateCheck --> RefCheck["Validate references
workflow tools + next-step toolIds"] + RefCheck --> Manifest["ResolvedManifest
tools + workflows + resources"] + + Manifest --> Select["Runtime selection
MCP requested/default/auto workflows"] + Select --> Exposure["Exposure filtering
availability + predicates"] + Exposure --> Import["importToolModule(module)"] + Import --> NamedExports["Require named exports
schema + handler"] + NamedExports --> ToolDefs["ToolDefinition[]"] + + ToolDefs --> MCPCatalog["MCP registry catalog"] + ToolDefs --> CLICatalog["CLI command catalog"] + ToolDefs --> DaemonCatalog["Daemon catalog"] +``` + +Validation happens before runtime exposure. The loader validates YAML shape, predicate names, workflow tool references, next-step tool references, and duplicate MCP names. Runtime catalog builders should be able to assume they are working from a coherent manifest graph. + +## Visibility layers + +Visibility is deliberately layered. Each layer answers a different question. + +| Layer | Question | Example | +|-------|----------|---------| +| Workflow selection | Which group of tools did the session ask for? | Default MCP exposure starts from the simulator workflow to keep agent context small. | +| Predicate filtering | Is this entry valid for the current runtime config? | Experimental workflow discovery appears only when its predicate passes. | +| Runtime availability | Is the entry available to MCP, CLI, or both? | A manifest can expose a tool to MCP, CLI, or both. | +| Daemon exposure | Should the daemon serve this stateful CLI call? | Daemon exposure is derived from CLI routing, not declared as a manifest availability flag. | + +Do not add a third manifest availability mode for daemon behavior. The daemon is a transport for stateful CLI tools, not a public runtime selector like MCP or CLI. + +## Workflow selection before predicates + +Workflow selection is the coarse catalog control. It keeps MCP sessions small and lets users enable only the capability groups they need. Predicate filtering is finer grained. It can hide tools that require debug mode, experimental workflow discovery, or a runtime environment that is not currently active. + +That order matters for contributors. Put durable product grouping in workflow manifests. Put conditional exposure in predicates. Put public runtime support in the `availability` object. + +## Authoring implications + +When adding or changing a tool, update the manifest first enough to make the intended exposure explicit: + +- Add the tool manifest once, even if multiple workflows reference it. +- Use workflow membership for discoverability and catalog size. +- Use predicates for conditional visibility. +- Use `availability` only for MCP and CLI exposure. +- Use routing metadata for stateful CLI transport. +- Keep manifest output schema metadata aligned with `ctx.structuredOutput`. + +See [Tool Authoring](/docs/tool-authoring) for the end-to-end checklist and [Tools Reference](/docs/tools) for the generated catalog. + +## Related + +- [Workflows](/docs/workflows), user-facing workflow selection +- [Configuration](/docs/configuration), config fields that affect exposure +- [Tool Authoring](/docs/tool-authoring), manifest fields and validation checklist +- [Tools Reference](/docs/tools), generated tool catalog diff --git a/app/docs/_content/architecture-rendering-output.mdx b/app/docs/_content/architecture-rendering-output.mdx new file mode 100644 index 0000000..322eef6 --- /dev/null +++ b/app/docs/_content/architecture-rendering-output.mdx @@ -0,0 +1,129 @@ +import { PageHeader } from "../_components/page-header" + + + +When a tool finishes, the caller might be a chat agent expecting MCP-formatted text, a developer reading their terminal, a script that wants one JSON object, a pipeline consuming JSONL events, or a debugger watching raw subprocess output. The tool itself does not pick. A separate layer collects everything the tool produced as it ran and turns it into the right shape on the way out. This page covers that layer, and the one naming distinction it forces contributors to keep straight. + +## Terms used here + +- **rendering** — The step that turns a call's fragments, attachments, next steps, and structured output into MCP text, CLI text, JSON, JSONL, or a raw transcript. +- **render session** — The per-call object that collects fragments and the final structured output as a handler runs, so the runtime boundary can format them appropriately on the way out. +- **render strategy** — Internal: how the render session formats the in-process transcript while the call is running (`text`, `cli-text`, or `raw`). Not selected directly by callers. +- **CLI output mode** — External: what the `xcodebuildmcp` CLI prints to stdout for a given invocation (`text`, `json`, `jsonl`, or `raw`). Selected by the caller via `--output`. +- **fragment** — A typed progress event the handler emits while work runs. +- **structured output** — The final canonical JSON result a handler sets at the end of a call. + +For the canonical glossary, see [Core terms](/docs/architecture#core-terms). + +## Why rendering is a boundary + +Tool handlers produce domain fragments, attachments, next steps, and one final structured result. They should not decide whether a caller wants MCP text, interactive CLI text, raw subprocess transcript, JSON, or JSONL. + +The render boundary keeps that decision outside the handler. MCP can return protocol-native content. CLI can stream text for humans, JSONL for pipelines, JSON for scripts, or raw transcript for debugging. + +## Render session lifecycle + +```mermaid +stateDiagram-v2 + [*] --> Created: createRenderSession(strategy) + + Created --> Collecting: tool invocation starts + + Collecting --> Collecting: emit(fragment) + Collecting --> Collecting: attach(image) + Collecting --> StructuredReady: setStructuredOutput(output) + StructuredReady --> StructuredReady: setNextSteps(steps, runtime) + Collecting --> ErrorTracked: error fragment emitted + StructuredReady --> ErrorTracked: structured result didError=true + + ErrorTracked --> Finalizing: finalize() + StructuredReady --> Finalizing: finalize() + Collecting --> Finalizing: finalize() + + Finalizing --> TextTranscript: strategy = text + Finalizing --> CliInteractive: strategy = cli-text + Finalizing --> RawTranscript: strategy = raw + + TextTranscript --> RuntimeBoundary: MCP content or batch text + CliInteractive --> RuntimeBoundary: CLI stdout + RawTranscript --> RuntimeBoundary: transcript stderr + final stdout + + RuntimeBoundary --> StructuredEnvelope: CLI json or MCP structuredContent + RuntimeBoundary --> JsonlEvents: CLI jsonl fragments + + StructuredEnvelope --> [*] + JsonlEvents --> [*] + RuntimeBoundary --> [*] +``` + +The render session is the collection point for the tool invocation. It receives fragments as work happens, stores attachments, stores the final structured output, stores next steps, tracks error state, and finalizes the transcript for the selected render strategy. + +## Render strategy vs CLI output mode + +These two terms sound similar and are easy to conflate. They are not the same. + +A **render strategy** is internal. It is how the render session shapes the in-process transcript as fragments arrive. There are three: `text` (buffered readable text used by MCP and batch CLI output), `cli-text` (streamed human-readable progress to stdout), and `raw` (subprocess-style transcript for debugging). Tool handlers do not choose a strategy; the runtime boundary picks one based on how it intends to deliver output. + +A **CLI output mode** is external. It is what the user typed after `--output` on the command line: `text`, `json`, `jsonl`, or `raw`. `--output text` maps to the `cli-text` render strategy, and `--output raw` maps to the `raw` render strategy. The CLI handles `json` and `jsonl` at the boundary (`json` waits for the final structured output and prints one final structured envelope; `jsonl` writes one NDJSON event (newline-delimited JSON) per emitted fragment and never prints the final structured envelope). + +Two practical consequences: + +- There is no `json` render strategy and no `jsonl` render strategy. Those are CLI output modes handled at the CLI boundary, not inside the render session. +- MCP has no output mode. MCP always returns text content plus, when present, `structuredContent`. + +## Render strategies + +| Strategy | Used for | Behavior | +|----------|----------|----------| +| `text` | MCP text content and buffered text rendering. | Collects fragments and finalizes a readable transcript. | +| `cli-text` | Interactive CLI text. | Streams human-readable progress to stdout as the tool runs. | +| `raw` | CLI raw mode. | Writes transcript fragments close to the underlying subprocess output and keeps final non-transcript text separate. | + +## CLI output modes + +CLI output modes decide what the shell receives after or during invocation. + +| Mode | Relationship to rendering | +|------|---------------------------| +| `text` | Uses the CLI text render path for readable progress and final text. | +| `json` | Waits for final structured output and prints one final structured envelope. | +| `jsonl` | Writes one NDJSON event per emitted fragment. It does not print the final structured envelope. | +| `raw` | Uses the raw render path for subprocess-oriented debugging. | + +For the public shapes, examples, and scripting guidance, see [Output Formats](/docs/output-formats). + +## MCP structured content + +MCP mode always returns normal text content. When a tool produced structured output, the MCP response also includes `structuredContent` in the same envelope shape used by CLI `--output json`. + +That means contributors should treat `ctx.structuredOutput` as the stable contract. Rendered text can change to improve readability. Structured output changes require schema, fixture, and generated-doc alignment. + +## Next steps at the render boundary + +Next steps are resolved after the handler completes and before final rendering. The runtime decides formatting: + +- MCP text gets MCP-appropriate follow-up text. +- CLI text gets command-shaped follow-ups. +- Structured envelopes carry the final result, not a separate rendered transcript. +- JSONL carries live fragments, not the final response. + +See [Tool Lifecycle](/docs/architecture-tool-lifecycle#next-step-resolution) for where next-step data comes from. + +## Contributor rules + +- Do not make handlers branch on CLI versus MCP output mode. +- Set `ctx.structuredOutput` for every tool that has a stable result contract. +- Emit fragments only for live progress, not as the only source of final data. +- Keep manifest output schema metadata aligned with the structured output envelope. +- Update fixtures when public rendering or structured output intentionally changes. + +## Related + +- [Output Formats](/docs/output-formats), public CLI and MCP response shapes +- [MCP Protocol Support](/docs/mcp-protocol-support), structured content and protocol features +- [CLI](/docs/cli), terminal usage and daemon behavior +- [Tool Lifecycle](/docs/architecture-tool-lifecycle), handler output contract diff --git a/app/docs/_content/architecture-runtime-boundaries.mdx b/app/docs/_content/architecture-runtime-boundaries.mdx new file mode 100644 index 0000000..789bd78 --- /dev/null +++ b/app/docs/_content/architecture-runtime-boundaries.mdx @@ -0,0 +1,141 @@ +import { PageHeader } from "../_components/page-header" + + + +A request to do Xcode work can arrive through three different front doors: the MCP server an agent connects to, the `xcodebuildmcp` command run directly in a shell, or that same CLI command quietly handing itself off to a long-running workspace process for stateful work. The three concrete entry points are the MCP stdio server (`xcodebuildmcp mcp`), the in-process CLI (`xcodebuildmcp ` running directly in the shell), and the same CLI command routed over a Unix socket to the per-workspace daemon. This page is about those front doors and how each one lines a request up to call the same shared tool function. + +## Terms used here + +See the full glossary at [Core terms](/docs/architecture#core-terms). + +- **runtime boundary** — The adapter where MCP, direct CLI, or daemon-routed CLI translates an incoming request into a call against the shared tool layer. +- **transport** — The wire the request travels on: MCP stdio, in-process CLI invocation, or a Unix-socket connection to the daemon. +- **tool handler** — The shared function that performs the validated action; it does not know which boundary called it. +- **daemon** — A workspace-scoped background process that owns stateful tool work across short-lived CLI commands. +- **workflow** — A named group of related tools, used here to scope which tools the MCP catalog advertises and how CLI tool commands are grouped. + +## Why runtime boundaries exist + +XcodeBuildMCP has two public entry points, MCP and CLI, because agents and shells have different constraints. The CLI then splits into in-process and daemon-routed execution for stateful work, so contributors maintain three runtime boundary surfaces inside those two public surfaces. + +MCP mode optimizes for agent context. It should advertise a small, relevant tool catalog, return MCP-native content, and attach structured results when available. CLI mode optimizes for discovery, scripting, and human debugging. It should expose top-level commands, workflow command groups, output modes, and daemon-backed state for long-running work. + +Both boundaries call the same tool handlers. + +## Boundary contracts + +| Boundary | Entry shape | Primary contract | +|----------|-------------|------------------| +| MCP | `xcodebuildmcp mcp` | Register MCP tools and resources, render text content, attach `structuredContent` when the tool produced structured output. | +| CLI top-level commands | `init`, `setup`, `upgrade`, `tools`, `daemon` | Provide setup, discovery, daemon control, and server startup commands outside the workflow tool tree. | +| CLI tool commands | `xcodebuildmcp [flags]` | Parse flags or JSON input, invoke a catalog tool, and choose a CLI output mode. | +| Daemon-routed CLI | Same CLI tool command shape | Preserve state across short-lived CLI processes for tools that declare stateful routing. | + +For user-facing syntax, see [CLI](/docs/cli) and [MCP Server Mode](/docs/mcp-mode). + +## MCP boundary + +MCP mode starts a stdio server, builds the MCP-visible catalog from enabled workflows, and registers tool callbacks with the MCP SDK. The callback creates a text render session, calls the shared handler, resolves next steps, finalizes text, and returns both MCP `content` and structured content when the handler set a structured result. + +```mermaid +sequenceDiagram + autonumber + participant Client as MCP client + participant Server as MCP server + participant Registry as tool-registry.ts + participant Session as RenderSession(text) + participant Handler as Tool handler + participant Post as postProcessSession() + participant Envelope as structured envelope + + Client->>Server: tools/call(name, args) + Server->>Registry: registered tool callback + Registry->>Session: createRenderSession("text") + Registry->>Handler: handler(args, ToolHandlerContext) + Handler-->>Session: ctx.emit(fragment) when needed + Handler-->>Registry: ctx.structuredOutput + Registry->>Session: setStructuredOutput(output) + Registry->>Post: resolve next-step templates and handler steps + Post->>Session: setNextSteps(steps, "mcp") + Registry->>Session: finalize() + Session-->>Registry: rendered text transcript + Registry->>Envelope: toStructuredEnvelope(result, schema, version) + Registry-->>Server: ToolResponse content + structuredContent + Server-->>Client: MCP tool result +``` + +The MCP boundary is also where workflow selection matters most. Keeping the advertised catalog small reduces agent context cost. See [Workflows](/docs/workflows) for the public workflow model and [MCP Protocol Support](/docs/mcp-protocol-support) for MCP features exposed at the protocol boundary. + +## CLI boundary + +The CLI builds a yargs command tree from the same manifest-backed catalog. Non-tool commands are registered as top-level commands. Tool commands are grouped by workflow so `xcodebuildmcp simulator build` and `xcodebuildmcp device install` stay discoverable in shells and scripts. + +CLI invocation has one extra decision that MCP mode does not need: whether the tool can run in the current process or needs daemon transport. + +```mermaid +sequenceDiagram + autonumber + participant User as Shell / agent + participant CLI as yargs CLI + participant Commands as register-tool-commands.ts + participant Invoker as DefaultToolInvoker + participant Session as RenderSession + participant Handler as Tool handler + participant DaemonClient as DaemonClient + participant Daemon as Per-workspace daemon + + User->>CLI: xcodebuildmcp [flags] + CLI->>Commands: parse flags, --json, --output, --profile + Commands->>Session: createRenderSession(strategy) + Commands->>Invoker: invokeDirect(tool, args, InvokeOptions) + + alt stateless tool + Invoker->>Handler: handler(args, ToolHandlerContext) + Handler-->>Session: fragments, attachments, structured output + Invoker->>Session: setStructuredOutput() + Invoker->>Session: setNextSteps() + else stateful tool + Invoker->>DaemonClient: isRunning() + opt daemon not running + Invoker->>DaemonClient: ensureDaemonRunning(socket, workspaceRoot) + end + Invoker->>DaemonClient: invokeTool(tool, args, onFragment) + DaemonClient->>Daemon: tool.invoke frame + Daemon->>Handler: handler(args, daemon ToolHandlerContext) + Handler-->>Daemon: emitted fragments + Daemon-->>DaemonClient: progress frames + DaemonClient-->>Session: session.emit(fragment) + Daemon-->>DaemonClient: structuredOutput + nextStep data + DaemonClient-->>Invoker: ToolInvokeResult + Invoker->>Session: setStructuredOutput() + Invoker->>Session: setNextSteps() + end + + alt --output json + Commands-->>User: final structured JSON envelope + else --output jsonl + Commands-->>User: NDJSON fragments only + else --output text or raw + Commands->>Session: finalize() + Session-->>User: rendered output + end +``` + +## Direct vs daemon-routed tools + +Stateless tools run directly in the CLI process. Listing simulators, reading project metadata, and similar short operations do not need background state. + +Stateful tools route through the per-workspace daemon. Debug sessions, video recording, long-running Swift Package work, and Xcode IDE bridge calls need process state that outlives one CLI command. The CLI still owns argument parsing and output formatting, but the daemon owns the active session. + +See [Daemon Lifecycle](/docs/architecture-daemon) for daemon transport details and [Rendering & Output](/docs/architecture-rendering-output) for how the result is presented after either path completes. + +## Related + +- [CLI](/docs/cli), direct terminal access and output modes +- [MCP Server Mode](/docs/mcp-mode), server startup and advertised surface +- [MCP Protocol Support](/docs/mcp-protocol-support), MCP feature support +- [Daemon Lifecycle](/docs/architecture-daemon), stateful CLI transport diff --git a/app/docs/_content/architecture-startup-config.mdx b/app/docs/_content/architecture-startup-config.mdx new file mode 100644 index 0000000..9543bb9 --- /dev/null +++ b/app/docs/_content/architecture-startup-config.mdx @@ -0,0 +1,114 @@ +import { PageHeader } from "../_components/page-header" + + + +When you run any `xcodebuildmcp` command, the process has to decide how much setup to do before it can answer. Printing a version or running `init` should not load every manifest in the project; the MCP server has to load almost everything because an agent will keep asking. This page is about that decision — what the early bootstrap step does, what each runtime initializes after it, and where configuration values come from. + +## Terms used here + +See the full glossary at [Core terms](/docs/architecture#core-terms). + +- **bootstrap** — The early startup step (`bootstrapRuntime()`) that initializes the project configuration store and, for MCP mode, hydrates session defaults before any tool runs. +- **session-default store** — The MCP-only in-process record of agent-set values (workspace, scheme, simulator, profile) so later tool calls in the same session can omit them. +- **runtime boundary** — The adapter that turns an incoming request into a call against the shared tool layer; this page covers what each boundary loads at startup. +- **workflow** — A named group of related tools; workflow-selection inputs decide which tools the MCP boundary advertises after bootstrap. + +## Why startup is split + +Not every command needs the full runtime. Setup commands should start quickly and avoid manifest catalog work. MCP mode needs a live session store because agents can set defaults during a session. Normal CLI tool calls are short-lived, so they resolve config for the invocation instead of hydrating the MCP session-default store. + +That split keeps command startup predictable while still giving every runtime the same resolved project configuration. + +## Startup paths + +```mermaid +sequenceDiagram + autonumber + participant Process as node build/cli.js + participant CLI as cli.ts + participant Bootstrap as bootstrapRuntime() + participant Config as config-store.ts + participant Catalog as tool-catalog.ts + participant Yargs as yargs-app.ts + participant MCP as startMcpServer() + + Process->>CLI: main() + CLI->>CLI: findTopLevelCommand(argv) + + alt command is mcp + CLI->>MCP: startMcpServer() + MCP->>Bootstrap: bootstrapRuntime({ runtime: "mcp" }) + Bootstrap->>Config: initConfigStore(cwd, fs) + Config-->>Bootstrap: resolved config + Bootstrap->>Bootstrap: hydrate MCP session defaults + MCP->>MCP: register workflows and resources + else command is init/setup/upgrade + CLI->>CLI: build lightweight yargs app + CLI->>Yargs: register only requested command + else normal CLI command + CLI->>Bootstrap: bootstrapRuntime({ runtime: "cli", disableSessionDefaults: true }) + Bootstrap->>Config: initConfigStore(cwd, fs) + Config-->>Bootstrap: resolved config + CLI->>CLI: resolve workspaceRoot, socketPath, workspaceKey + CLI->>Catalog: buildCliToolCatalog() + Catalog-->>CLI: ToolCatalog + CLI->>Yargs: buildYargsApp(catalog, runtimeConfig) + Yargs-->>Process: parseAsync() + end +``` + +| Path | Why it is separate | What it initializes | +|------|--------------------|---------------------| +| MCP server | Agents need a persistent server session. | Config store, MCP session defaults, resources, MCP-visible workflows and tools. | +| Lightweight setup commands | They should not pay for catalog construction. | Only the requested top-level command. | +| Normal CLI commands | Scripts need deterministic one-shot execution. | Config store, workspace identity, socket path, CLI catalog, yargs tool tree. | +| Daemon process | Stateful CLI work needs a background owner. | Daemon catalog, socket server, activity tracking, idle shutdown. | + +The daemon path is intentionally linked, not duplicated, here. See [Daemon Lifecycle](/docs/architecture-daemon) for transport and shutdown behavior. + +## Configuration precedence + +Configuration is layered so each source has a clear job. Runtime values win because they represent the active session. Project config is the repo-scoped source of truth. Environment variables are best for MCP clients and process bootstrap. + +```mermaid +flowchart TB + Highest["Highest precedence"] --> Runtime["Runtime overrides
session_set_defaults and explicit runtime overrides"] + Runtime --> File["Project config
.xcodebuildmcp/config.yaml"] + File --> Env["Environment variables
XCODEBUILDMCP_* and related env vars"] + Env --> Defaults["Built-in defaults"] + + Runtime -. "Used for active session choices" .-> SessionDefaults["Session defaults store"] + File -. "Repo-scoped canonical config" .-> ProjectConfig["Project configuration"] + Env -. "Client bootstrap and flat startup values" .-> Bootstrap["Bootstrap inputs"] + + classDef rank fill:#bfdbfe,stroke:#1d4ed8,stroke-width:2px; + class Highest,Runtime,File,Env,Defaults rank; +``` + +For the full user-facing schema, see [Configuration](/docs/configuration). For flat environment inputs, see [Environment Variables](/docs/env-vars). + +## Session-default hydration + +MCP mode hydrates session defaults during bootstrap because the server is long-lived. Once an agent sets workspace, scheme, simulator, or profile values, later tool calls can omit repeated parameters. + +CLI mode uses the same config file and profile concepts, but each invocation is a new process. It resolves defaults for that command instead of treating the session-default store as shared process state. That distinction matters when debugging startup: MCP has live in-process defaults, while CLI has deterministic per-command inputs. + +See [Session Defaults](/docs/session-defaults) for the public behavior and [Workflows](/docs/workflows) for the workflow-selection inputs that influence the advertised catalog. + +## Design rules for contributors + +- Keep early commands lightweight unless they genuinely need the runtime catalog. +- Keep config precedence visible. Hidden fallback behavior makes agent sessions hard to reason about. +- Put persistent state in the daemon, not in a short-lived CLI process. +- Treat MCP session defaults as MCP runtime state, not as a global source that every boundary must hydrate. + +## Related + +- [Configuration](/docs/configuration), config file and precedence +- [Session Defaults](/docs/session-defaults), shared workspace, scheme, simulator, and profile values +- [Environment Variables](/docs/env-vars), process bootstrap inputs +- [Workflows](/docs/workflows), enabled workflow selection diff --git a/app/docs/_content/architecture-tool-lifecycle.mdx b/app/docs/_content/architecture-tool-lifecycle.mdx new file mode 100644 index 0000000..9094f02 --- /dev/null +++ b/app/docs/_content/architecture-tool-lifecycle.mdx @@ -0,0 +1,108 @@ +import { PageHeader } from "../_components/page-header" + + + +A tool in XcodeBuildMCP is one user-visible action — listing simulators, building a scheme, running a test, capturing a screenshot. Each tool is a small module responsible for three things: validating its input, doing the actual Xcode work, and producing one canonical result. Anything to do with how that result gets formatted for an MCP client, a terminal, or a JSON pipeline lives outside the tool. This page is the contract for that small module. + +## Terms used here + +- **tool handler** — The function inside a tool module that performs one validated action and writes its outcome onto the call context. +- **schema** — The Zod (a TypeScript schema-validation library) shape exported alongside the handler that validates input and feeds generated docs and CLI argument metadata. +- **fragment** — A typed progress event the handler emits while work is still running (a log line, a transcript chunk, an attachment); not the final result. +- **structured output** — The single canonical JSON result the handler sets at the end of a call, validated against a published schema. +- **next step** — A follow-up suggestion attached to the call, normally taken from a manifest template and optionally filled in with runtime values. + +For the canonical glossary, see [Core terms](/docs/architecture#core-terms). + +## Why the tool contract is narrow + +A tool should express three things clearly: accepted input, work execution, and canonical structured output. Runtime-specific concerns belong outside the handler. That separation lets the MCP registry, CLI invoker, daemon server, renderers, and tests all call the same implementation without duplicating behavior. + +## Tool module contract + +| Export | Purpose | +|--------|---------| +| `schema` | Zod schema shape used for runtime validation, generated docs, and command argument metadata. | +| `handler` | Runtime-agnostic function created by a typed factory. It receives validated params and a tool context. | + +Handlers are normally created with one of the typed factories: + +- `createTypedTool(...)` +- `createTypedToolWithContext(...)` +- `createSessionAwareTool(...)` +- `createSessionAwareToolWithContext(...)` + +Use the session-aware factories when the public schema can omit values supplied by session defaults. Use the simpler factories when the tool can validate its public input directly. + +## Handler context + +Document the context as the author-facing contract, not as every internal flag currently present in the TypeScript interface. + +```ts +interface ToolHandlerContext { + emit: (fragment: AnyFragment) => void + attach: (image: ImageAttachment) => void + nextStepParams?: NextStepParamsMap + nextSteps?: NextStep[] + structuredOutput?: StructuredToolOutput +} +``` + +| Field | Use | +|-------|-----| +| `emit` | Send live domain fragments for streaming tools. | +| `attach` | Add image attachments that the runtime can return. | +| `nextStepParams` | Provide runtime values for manifest next-step templates. | +| `nextSteps` | Provide explicit dynamic follow-ups when templates cannot express the result. | +| `structuredOutput` | Set the final canonical result, schema ID, and schema version. | + +The omitted progress flags are internal boundary controls. They exist in source today, but the public docs intentionally do not teach tool authors to branch on them. + +## Fragments versus structured output + +A handler produces two different things, and they serve different readers. Fragments are live progress and transcript material — log lines, build output, attachments — that callers and pipelines consume while the work is running. Structured output is the one final canonical result the handler sets at the end of the call. Fragments are never the final result; the structured output is what powers CLI `--output json`, MCP `structuredContent`, schema validation, fixtures, and stable integrations. + +| Type | Lifetime | Reader | +|------|----------|--------| +| Domain fragment | Emitted during execution. | Humans, agents, and pipelines watching live progress. | +| Domain result | Set once at the end. | JSON consumers, MCP structured content, generated schema contracts, renderers. | + +A streaming tool can emit many fragments and still produce one final result. A non-streaming tool normally produces no fragments and only sets the final result. + +## Streaming vs non-streaming tools + +Choose the simpler non-streaming shape unless the user benefits from live progress. + +| Shape | Handler behavior | Good fit | +|-------|------------------|----------| +| Non-streaming | Do the work, then set `ctx.structuredOutput` once. Do not emit fragments. | Listing, discovery, metadata, cleanup, session defaults. | +| Streaming | Emit domain fragments while work runs, then set one final `ctx.structuredOutput`. | Build, test, debugging, video, long-running Swift Package commands. | + +## Next-step resolution + +Follow-up instructions normally come from manifest templates. That keeps common suggestions consistent across MCP text, CLI text, and generated references. + +Handlers should prefer `ctx.nextStepParams` when the follow-up is template-shaped but needs runtime values. Use explicit `ctx.nextSteps` only for dynamic cases that cannot be represented by a manifest template. + +| Source | Use it when | Example | +|--------|-------------|---------| +| Manifest next-step template | The suggestion is stable for the tool. | After listing simulators, suggest a build command using the selected simulator. | +| `ctx.nextStepParams` | The template needs values discovered at runtime. | Fill simulator ID, app path, bundle ID, or log path. | +| `ctx.nextSteps` | The suggestion depends on a dynamic branch the manifest cannot model. | Suggest a different recovery command for a specific failure mode. | + +## Rendering handoff + +The handler does not decide whether output is MCP text, CLI text, JSON, JSONL, or raw transcript. It sets fragments, attachments, next-step data, and structured output. The runtime boundary and render session decide presentation. + +See [Rendering & Output](/docs/architecture-rendering-output) for that boundary. See [Output Formats](/docs/output-formats) for the public CLI and MCP response shapes. + +## Related + +- [Tool Authoring](/docs/tool-authoring), step-by-step tool changes +- [Testing](/docs/testing), fixtures and schema validation +- [Output Formats](/docs/output-formats), public JSON, JSONL, and MCP structured content +- [Tools Reference](/docs/tools), generated catalog diff --git a/app/docs/_content/architecture.mdx b/app/docs/_content/architecture.mdx new file mode 100644 index 0000000..0494813 --- /dev/null +++ b/app/docs/_content/architecture.mdx @@ -0,0 +1,144 @@ +import { PageHeader } from "../_components/page-header" + + + +XcodeBuildMCP is one project that does Xcode work — building, running, debugging, simulator and device control, UI automation, scaffolding — and exposes that work through several front doors at once. AI agents reach it over the Model Context Protocol. Humans and scripts reach it through a `xcodebuildmcp` command-line tool. Some commands need state that has to outlive a single shell process, so they hand work off to a background process scoped to the project workspace. + +All three paths run the same implementation. This page is the entry point to how that shared implementation is organized. Read it once before the architecture subpages — it defines the vocabulary the rest of the section uses. + +## Core terms + +These are the canonical terms used throughout the architecture docs. Every other architecture page links back here on first use. + +- **workflow** — A named group of related Xcode tools (for example, simulator, device, debugging, project scaffolding) that contributors curate together so callers can opt into a small, relevant slice of the catalog. +- **manifest** — A YAML file under `manifests/` that declares a tool, workflow, or resource as metadata — name, description, schema reference, visibility rules — without containing the implementation code. +- **predicate** — A named runtime check (such as "Xcode is installed" or "running on Apple Silicon") that decides whether a manifest entry is eligible for the current process. +- **availability** — A field on a tool manifest declaring which runtimes (MCP, CLI, or both) may advertise the tool, while daemon exposure is derived from routing metadata rather than declared here. +- **exposure** — The final decision to advertise a tool or resource on a given runtime, after workflow selection, predicates, and availability checks have all agreed. +- **runtime boundary** — The adapter layer where a request enters the system — through the Model Context Protocol (MCP) server, the local CLI, or a CLI command routed to the daemon — and is translated into a call against the shared tool layer. +- **tool handler** — The function inside a tool module that performs one validated action and writes its outcome onto the call context; everything user-visible is downstream of it. +- **fragment** — A typed progress event that a handler emits while work is still running, such as a log line, a transcript chunk, or an attachment; it is not the final result. +- **next step** — A follow-up suggestion attached to a tool result, usually resolved from a manifest template and optionally filled with runtime values from the handler. +- **structured output** — The single canonical JSON result a handler produces for a tool call, validated against a schema under `schemas/structured-output/`. +- **rendering** — The step that turns a call's fragments, attachments, next steps, and structured output into MCP text, CLI text, JSON, JSONL, or a raw transcript. +- **render session** — The per-call object that collects fragments and the final structured output as a handler runs, so the runtime boundary can format them appropriately on the way out. +- **daemon** — A workspace-scoped background process (`xcodebuildmcp daemon`) that owns tool state — debug sessions, video captures, long-running SwiftPM work, the Xcode IDE bridge — that has to survive across short-lived CLI commands. +- **transport** — The wire a request travels on to reach a handler: MCP stdio (the standard input/output pipes the MCP server reads and writes), in-process CLI invocation, or a Unix-socket connection (a local interprocess pipe) to the daemon. + +## Request flow + +A request moves through the system in roughly the same shape regardless of which front door it came in. + +1. **A caller asks for work.** An agent issues an MCP tool call, or a human or script runs an `xcodebuildmcp` subcommand. +2. **A runtime boundary receives it.** The MCP server, the local CLI, or a daemon-routed CLI command is the first layer to touch the request and is responsible for translating it into a call against the shared tool layer. +3. **Visibility decides what is even reachable.** Before the call can resolve, the system applies the active workflow selection, evaluates predicates, and checks availability. The combination determines exposure — which tools the runtime will advertise and accept. +4. **The tool handler runs.** The handler is the same function regardless of front door. It validates inputs, performs the Xcode action, and writes its outcome onto the call context. +5. **The handler does its work and produces a structured output.** Streaming tools emit fragments (log lines, transcript chunks, attachments) into the render session as work progresses. Either way, the handler sets one canonical structured output when it finishes. +6. **Rendering chooses the output shape.** The render session is read by the runtime boundary on the way out. MCP gets text and `structuredContent`; CLI gets text, JSON, JSONL, or a raw transcript depending on the requested mode. +7. **Stateful work goes through the daemon.** When a CLI command needs state to outlive the foreground process — an active debug session, a running video capture, an open Xcode bridge — the CLI uses the daemon transport instead of running the handler in-process. The daemon executes the same handler; only the transport changes. + +## Overview component diagram + +```mermaid +flowchart TB + Agent["Agent or human"] --> MCPClient["MCP client"] + Agent --> Shell["Shell / script"] + + MCPClient --> MCPMode["xcodebuildmcp mcp"] + Shell --> CLIMode["xcodebuildmcp CLI"] + + subgraph RuntimeBoundaries["Runtime boundaries"] + MCPMode --> MCPRegistry["MCP tool registry"] + CLIMode --> Yargs["Yargs command tree"] + Yargs --> Invoker["DefaultToolInvoker"] + end + + subgraph Metadata["Manifest metadata"] + ToolManifests["manifests/tools/*.yaml"] + WorkflowManifests["manifests/workflows/*.yaml"] + ResourceManifests["manifests/resources/*.yaml"] + Visibility["Workflow selection + predicates + availability"] + ToolManifests --> Visibility + WorkflowManifests --> Visibility + ResourceManifests --> Visibility + end + + Visibility --> MCPRegistry + Visibility --> Yargs + + subgraph SharedToolLayer["Shared tool layer"] + Catalog["ToolCatalog"] + Importer["importToolModule()"] + Handler["Tool handler"] + DomainResult["Domain result"] + DomainFragments["Domain fragments"] + Catalog --> Importer --> Handler + Handler --> DomainFragments + Handler --> DomainResult + end + + MCPRegistry --> Catalog + Invoker --> Catalog + + Invoker --> Direct["Direct invocation"] + Invoker --> DaemonClient["Daemon client for stateful tools"] + DaemonClient --> Daemon["Per-workspace daemon"] + Daemon --> Handler + Direct --> Handler + MCPRegistry --> Handler + + subgraph Rendering["Rendering boundary"] + RenderSession["RenderSession"] + Text["MCP text / CLI text"] + Structured["structuredContent / CLI JSON"] + Jsonl["CLI JSONL fragments"] + Raw["Raw transcript"] + RenderSession --> Text + RenderSession --> Structured + RenderSession --> Jsonl + RenderSession --> Raw + end + + DomainFragments --> RenderSession + DomainResult --> RenderSession +``` + +## Design pressures + +- Constraint: agents need small, relevant MCP catalogs. Consequence: workflow selection, predicates, and runtime availability filter what the MCP server advertises. +- Constraint: humans and scripts need a discoverable command surface. Consequence: the CLI builds a yargs command tree from the same manifest metadata. +- Constraint: every tool needs one canonical result shape. Consequence: handlers set `ctx.structuredOutput`, and text, JSON, JSONL, and MCP `structuredContent` are derived at runtime boundaries. +- Constraint: long-running work needs live progress. Consequence: streaming tools emit domain fragments while still producing a final structured result. +- Constraint: stateful CLI work must survive the foreground command. Consequence: stateful CLI tools route through a per-workspace daemon instead of running directly in the CLI process. + +## Page map + +- [Runtime Boundaries](/docs/architecture-runtime-boundaries) — read this next when you want to see how the same handler is reachable from MCP, direct CLI, and daemon-routed CLI without each path re-implementing the work. +- [Startup & Configuration](/docs/architecture-startup-config) — read this next when you need to follow how a process boots, applies configuration precedence, hydrates session defaults, and prepares workflow inputs. +- [Manifests & Visibility](/docs/architecture-manifest-visibility) — read this next when you need to declare a tool, workflow, or resource in YAML and control whether it shows up in a given runtime. +- [Tool Lifecycle](/docs/architecture-tool-lifecycle) — read this next when you are writing or modifying a handler and need the contract from validated input through fragments, structured output, and next steps. +- [Rendering & Output](/docs/architecture-rendering-output) — read this next when you want to know how fragments and structured output become MCP text, CLI text, JSON, JSONL, or a raw transcript. +- [Daemon Lifecycle](/docs/architecture-daemon) — read this next when you are touching stateful work — debugging, video capture, long-running SwiftPM, or the Xcode IDE bridge — and need the daemon's transport and lifecycle behavior. + +## Build pipeline + +`npm run build` runs the Wireit (an npm task runner) build target, which calls `npm run build:tsup`. + +Build steps: + +1. `tsup` (a TypeScript bundler) compiles `src/**/*.ts` into unbundled ESM files in `build/`. +2. The build rewrites `.ts` import specifiers to `.js` for Node runtime execution. +3. The build marks `build/cli.js`, `build/doctor-cli.js`, and `build/daemon.js` as executable. +4. Manifests and structured-output schemas ship as package assets, so runtime code reads them from the package root. + +## Related + +- [Output Formats](/docs/output-formats), CLI output modes and MCP `structuredContent` +- [Tools Reference](/docs/tools), generated catalog of exposed tools +- [Tool Authoring](/docs/tool-authoring), adding implementation, manifest, schema, fixtures, and docs +- [Testing](/docs/testing), unit, snapshot, and schema fixture rules +- [Workflows](/docs/workflows), user-facing workflow selection diff --git a/app/docs/_content/cli.mdx b/app/docs/_content/cli.mdx index da7a471..9e252fa 100644 --- a/app/docs/_content/cli.mdx +++ b/app/docs/_content/cli.mdx @@ -4,7 +4,7 @@ import { PageHeader } from "../_components/page-header" ## Synopsis @@ -115,25 +115,31 @@ xcodebuildmcp simulator record-video \ --output-path ./session.mp4 ``` - - Every command accepts --output json for JSONL event streams, suitable for CI pipelines and scripting. - +## Streaming output and live progress + +Long-running tool calls (builds, tests, video recording, debugging sessions) emit progress in real time. The calling shell, script, or agent sees continuous activity instead of waiting for the whole operation to finish. Even between semantic milestones, raw subprocess stdout and stderr stream as the underlying tool emits them, which acts as a continuous liveness signal during long operations. + +What you get depends on `--output`: + +- **`text`** (default): human-readable progress lines stream to stdout as they happen. Build phases, test pass / fail, raw subprocess output, and runtime status messages all appear live. +- **`jsonl`**: one NDJSON event per fragment. Same content as `text` mode in a structured shape that agents and scripts can parse line by line. Each event has a `kind` (for example `build`, `test`, `transcript`, `infrastructure`) and a `fragment` field describing what happened. +- **`json`**: does not stream. The CLI waits for the tool to reach its terminal state, then emits a single structured final result. + +For agents driving long operations through the shell, `jsonl` is usually the right choice: the calling agent can react to events as they arrive (surface a test failure the moment it appears, abort a build that has gone past a budget, forward live progress to the user). `text` is best for humans and for agents that only need to confirm the call is alive while it runs. + +See Output Formats for the envelope and event shapes. ## Per-workspace daemon -The CLI auto-starts a daemon only when needed. Stateless tools (`build`, `test`, `list`, discovery) run in-process. Stateful tools route through the daemon: +Some XcodeBuildMCP tools need to keep state between commands (for example log capture, video recording, LLDB debugging, and background Swift Package runs). To do that, XcodeBuildMCP uses a background process. -- Log capture -- Video recording -- LLDB debugging -- Background Swift Package processes +XcodeBuildMCP auto-starts a small scoped background process (a daemon) the first time one of those tools runs. That daemon survives between CLI invocations, so follow-up commands can continue the same stateful session. -Daemon behavior: +Lifecycle and scope: -- **Workspace identity**: derived from the location of `.xcodebuildmcp/config.yaml`, or falls back to the current directory. -- **Socket**: each daemon runs on a Unix socket at `~/.xcodebuildmcp/daemons//daemon.sock`. -- **Auto-start**: on first stateful tool invocation; no manual setup. -- **Auto-shutdown**: after 10 minutes idle, only when no active stateful sessions. +- **Auto-start**: starts on the first stateful tool call. No manual setup required. +- **Auto-shutdown**: stops after 10 minutes of idle time. +- **Workspace scoping**: each daemon is scoped per workspace. If `.xcodebuildmcp/config.yaml` exists, XcodeBuildMCP uses that file's project location to identify the workspace. If not, it uses your current directory. ### Daemon commands @@ -144,8 +150,14 @@ xcodebuildmcp daemon stop xcodebuildmcp daemon restart xcodebuildmcp daemon list xcodebuildmcp daemon list --json +xcodebuildmcp daemon logs ``` +Reference details: + +- **Socket path**: `~/.xcodebuildmcp/daemons//daemon.sock` +- **Workspace identity key**: `` is derived from the workspace root path. + ### Troubleshooting the daemon ```shell @@ -166,7 +178,7 @@ chmod -R 700 ~/.xcodebuildmcp/daemons |---|-----|---------------------------| | Invocation | Direct terminal | MCP client over stdio | | Session state | Stateless direct + daemon for stateful tools | In-process | -| Use case | Scripts, CI, manual | AI-assisted development | +| Use case | Scripts, CI, manual checks, agents composing tool calls via shell | MCP clients and agents | | Configuration | Same `config.yaml` | Same `config.yaml` | Both share the same tool implementations. diff --git a/app/docs/_content/contributing.mdx b/app/docs/_content/contributing.mdx new file mode 100644 index 0000000..5e2565b --- /dev/null +++ b/app/docs/_content/contributing.mdx @@ -0,0 +1,235 @@ +import Link from "next/link" +import { PageHeader } from "../_components/page-header" + + + +XcodeBuildMCP lives at [getsentry/XcodeBuildMCP](https://github.com/getsentry/XcodeBuildMCP). Use the issue tracker for bugs, proposals, and larger changes that need design discussion before code. + +## Prerequisites + +| Requirement | Notes | +|-------------|-------| +| macOS | XcodeBuildMCP shells out to Apple developer tools, so development is macOS-only. | +| Xcode | Install Xcode and make sure Command Line Tools point at the Xcode you use for testing. | +| Node.js 18+ | The package targets Node 18 and later. | +| npm | Used for install, build, test, and local scripts. | +| AXe (optional) | Required only if you work on UI automation or simulator capture tools. Bundle it locally with `npm run bundle:axe`. The script downloads pre-built artifacts into `bundled/axe`, which the server resolves automatically at runtime. | + +```shell +npm run bundle:axe +``` + +If you prefer a system-wide install on `PATH`, `brew tap cameroncooke/axe && brew install axe` also works, the resolver falls back to `PATH` after checking `bundled/`. + +## Clone, install, build + +```shell +git clone https://github.com/getsentry/XcodeBuildMCP.git +cd XcodeBuildMCP +npm install +npm run hooks:install +npm run build + +# Verify the build via the CLI +node build/cli.js --help + +# Or start the MCP server (stdio) +node build/cli.js mcp +``` + +`npm run hooks:install` configures the repository-managed git hooks from `.githooks/`. + +## Point your MCP client at the dev build + +Use the built `cli.js` directly while developing. Replace the path with your checkout path. + +```json +{ + "mcpServers": { + "XcodeBuildMCP": { + "command": "node", + "args": ["/path/to/XcodeBuildMCP/build/cli.js", "mcp"], + "env": { + "XCODEBUILDMCP_DEBUG": "true" + } + } + } +} +``` + +## Iterating + +Most XcodeBuildMCP code is shared between the CLI and MCP server: the tools themselves, the manifests that describe them, the runtime layer that receives a request, and the rendering layer that turns its output into text or JSON. That means most tool behavior is testable through the CLI without an MCP client in the loop: + +```shell +node build/cli.js simulator list +node build/cli.js simulator build --scheme MyApp --project-path ./MyApp.xcodeproj +``` + +Reach for the tools below only when you are validating MCP-specific behavior: tool advertising in `tools/list`, the structured content envelope, annotations, the server lifecycle, or anything the CLI surface does not exercise. + +### Testing the MCP layer + +When an MCP client launches the server, it spawns the server as a long-lived subprocess at startup. The running Node process holds the build that was on disk when it spawned, so rebuilding does not affect it. To pick up changes you have to kill and respawn the server, which drops the client's MCP connection and forces a reconnect (a manual click or a full editor restart, depending on the client). Three patterns avoid that loop: + + +

Run npm run inspect for the MCP Inspector interactive UI. Browser-based MCP client where you can list tools, call them with form inputs, view structured responses, and (importantly) see the server's stderr logs that real MCP clients usually hide.

+

Best for human exploration and debugging when you want the full server-side picture.

+ +{`npm run inspect`} + + + ) }, + { label: "Inspector CLI", content: ( + <> +

The Inspector also runs non-interactively. Each invocation spawns a fresh server subprocess, so there is no long-lived process to manage and no plumbing into your real client. The inspector CLI acts as a transient MCP client per call.

+

Best for AI agents contributing to XcodeBuildMCP that want to verify MCP integration after each rebuild.

+ +{`npx @modelcontextprotocol/inspector@latest --cli node build/cli.js mcp \\ + --method tools/list + +npx @modelcontextprotocol/inspector@latest --cli node build/cli.js mcp \\ + --method tools/call \\ + --tool-name discover_projs \\ + --tool-arg workspaceRoot=/path/to/sample/project`} + + +

Each invocation starts a fresh MCP server, so all in-process state (session defaults, log capture sessions, debug sessions, video recording, any running processes the server is tracking) dies the moment the call returns. You cannot test multi-call stateful flows with the Inspector CLI alone. Use the Reloaderoo tab to keep a long-lived server across calls, or exercise the stateful flow through the CLI runtime instead, where the per-workspace daemon owns that state and survives across invocations.

+
+ + ) }, + { label: "Reloaderoo", content: ( + <> +

Use Reloaderoo when you need to drive the dev server through your real MCP client (Claude Code, Cursor, etc.) and keep the connection alive across rebuilds. Reloaderoo proxies MCP traffic and exposes a restart_server tool the agent calls after each rebuild.

+ +{`npm install -g reloaderoo`} + + +{`{ + "mcpServers": { + "XcodeBuildMCP": { + "command": "reloaderoo", + "args": ["--", "node", "/path/to/XcodeBuildMCP/build/cli.js", "mcp"], + "env": { "XCODEBUILDMCP_DEBUG": "true" } + } + } +}`} + + + ) }, +]} /> + +Run `npm run dev:tsup` in your terminal so the build rebuilds on save. The Inspector flows pick up the latest build on the next call (fresh subprocess); Reloaderoo needs an explicit `restart_server` call after each rebuild. + +## Pre-commit checks + +If you ran `npm run hooks:install`, the git pre-commit hook automatically runs `npm run format:check`, `npm run lint`, `npm run build`, and `npm run docs:check` when you commit. That is a safety net, not a substitute for development-time checks. Catching problems while you iterate is faster than catching them at commit time, and the hook does not run `typecheck`, `lint:fix`, or `test`. + +Full checklist to run yourself during development: + +```shell +npm run lint:fix +npm run typecheck +npm run format +npm run build +npm run docs:check +npm test +``` + + + Do not commit TypeScript errors. Fix the type issue instead of suppressing it with unsafe casts, any, @ts-ignore, or @ts-nocheck. + + +## Making a change + +Start from an up-to-date `main` branch and create a focused branch: + +```shell +git checkout main +git pull origin main +git checkout -b feature/issue-123-add-simulator-filter +``` + +Common branch prefixes: + +| Prefix | Use it for | +|--------|------------| +| `feature/issue-123-description` | New behavior. | +| `bugfix/issue-456-description` | Bug fixes. | +| `hotfix/critical-description` | Urgent production fixes. | +| `docs/update-topic` | Documentation-only work. | +| `refactor/improve-topic` | Internal restructuring without behavior changes. | + +Keep commits atomic. Each commit should explain one logical change. If your change affects users, add a `CHANGELOG.md` entry under `## [Unreleased]` in the correct section: `Added`, `Changed`, `Fixed`, or `Removed`. + +Follow the existing TypeScript patterns: + +- Use Zod schemas for runtime validation. +- Keep tool logic testable through injected executors when it orchestrates external commands. +- Test logic functions, not handler functions. +- Do not add formatted output by hand. Use the domain result and rendering model described in [Architecture](/docs/architecture). + +## Submitting + +Open a pull request from your branch and include: + +| Section | What reviewers need | +|---------|---------------------| +| Summary | What changed and why. | +| Background or details | Context, issue links, and important constraints. | +| Solution | The implementation approach and key tradeoffs. | +| Testing | Commands you ran and any manual validation. | +| Notes | Risk, follow-up work, or reviewer focus areas. | + +Link related issues. For major features or risky behavior changes, open an issue first and get alignment before spending time on implementation. + +## Project templates + +The scaffolding tools pull iOS and macOS templates from separate repositories: + +- [XcodeBuildMCP-iOS-Template](https://github.com/getsentry/XcodeBuildMCP-iOS-Template) +- [XcodeBuildMCP-macOS-Template](https://github.com/getsentry/XcodeBuildMCP-macOS-Template) + +Use local template overrides when developing template changes: + +```shell +export XCODEBUILDMCP_IOS_TEMPLATE_PATH=/path/to/XcodeBuildMCP-iOS-Template +export XCODEBUILDMCP_MACOS_TEMPLATE_PATH=/path/to/XcodeBuildMCP-macOS-Template +``` + +Optional version overrides: + +| Env var | Scope | +|---------|-------| +| `XCODEBUILD_MCP_TEMPLATE_VERSION` | Shared fallback for both templates. | +| `XCODEBUILD_MCP_IOS_TEMPLATE_VERSION` | iOS template only. | +| `XCODEBUILD_MCP_MACOS_TEMPLATE_VERSION` | macOS template only. | + +When testing through an MCP client, put the same env vars in that client's `mcpServers.XcodeBuildMCP.env` block. + +## Related + +- [Architecture](/docs/architecture), how the runtime, manifests, and rendering model fit together +- [Tool Authoring](/docs/tool-authoring), adding or changing tools end to end +- [Testing](/docs/testing), test structure and snapshot rules +- [GitHub repo](https://github.com/getsentry/XcodeBuildMCP), source, issues, and pull requests diff --git a/app/docs/_content/index.ts b/app/docs/_content/index.ts index cec4c00..98cc04a 100644 --- a/app/docs/_content/index.ts +++ b/app/docs/_content/index.ts @@ -8,6 +8,8 @@ import CLIPage from "./cli.mdx" import MCPModePage from "./mcp-mode.mdx" import WorkflowsPage from "./workflows.mdx" import ToolsPage from "./tools.mdx" +import MCPProtocolSupportPage from "./mcp-protocol-support.mdx" +import OutputFormatsPage from "./output-formats.mdx" import ConfigurationPage from "./configuration.mdx" import SessionDefaultsPage from "./session-defaults.mdx" import EnvVarsPage from "./env-vars.mdx" @@ -19,6 +21,16 @@ import MigrationV2Page from "./migration-v2.mdx" import PrivacyPage from "./privacy.mdx" import TroubleshootingPage from "./troubleshooting.mdx" import ChangelogPage from "./changelog.mdx" +import ContributingPage from "./contributing.mdx" +import ArchitecturePage from "./architecture.mdx" +import ArchitectureRuntimeBoundariesPage from "./architecture-runtime-boundaries.mdx" +import ArchitectureStartupConfigPage from "./architecture-startup-config.mdx" +import ArchitectureManifestVisibilityPage from "./architecture-manifest-visibility.mdx" +import ArchitectureToolLifecyclePage from "./architecture-tool-lifecycle.mdx" +import ArchitectureRenderingOutputPage from "./architecture-rendering-output.mdx" +import ArchitectureDaemonPage from "./architecture-daemon.mdx" +import ToolAuthoringPage from "./tool-authoring.mdx" +import TestingPage from "./testing.mdx" export const PAGE_COMPONENTS: Record = { introduction: IntroductionPage, @@ -29,6 +41,8 @@ export const PAGE_COMPONENTS: Record = { "mcp-mode": MCPModePage, workflows: WorkflowsPage, tools: ToolsPage, + "mcp-protocol-support": MCPProtocolSupportPage, + "output-formats": OutputFormatsPage, configuration: ConfigurationPage, "session-defaults": SessionDefaultsPage, "env-vars": EnvVarsPage, @@ -40,4 +54,14 @@ export const PAGE_COMPONENTS: Record = { privacy: PrivacyPage, troubleshooting: TroubleshootingPage, changelog: ChangelogPage, + contributing: ContributingPage, + architecture: ArchitecturePage, + "architecture-runtime-boundaries": ArchitectureRuntimeBoundariesPage, + "architecture-startup-config": ArchitectureStartupConfigPage, + "architecture-manifest-visibility": ArchitectureManifestVisibilityPage, + "architecture-tool-lifecycle": ArchitectureToolLifecyclePage, + "architecture-rendering-output": ArchitectureRenderingOutputPage, + "architecture-daemon": ArchitectureDaemonPage, + "tool-authoring": ToolAuthoringPage, + testing: TestingPage, } diff --git a/app/docs/_content/introduction.mdx b/app/docs/_content/introduction.mdx index d4ed81e..1ab19b2 100644 --- a/app/docs/_content/introduction.mdx +++ b/app/docs/_content/introduction.mdx @@ -106,7 +106,7 @@ The MCP server speaks [Model Context Protocol](https://modelcontextprotocol.io/) Agents shelling out to xcodebuild get brittle, verbose, and inconsistent results. XcodeBuildMCP gives them: - **Stable tool names and flags**, versioned per release. -- **Structured outputs** with pre-parsed build diagnostics, durable preflight/footer sections, and JSONL streams on demand. +- **Structured outputs** with pre-parsed build diagnostics, durable preflight/footer sections, and NDJSON streams on demand. - **Session defaults** that eliminate repeated scheme/project/simulator boilerplate across tool calls. - **Two optional agent skills** (`xcodebuildmcp init`) that prime Claude Code, Cursor, and Codex with the right conventions. - **Per-workspace daemon** for stateful operations (log capture, debugging, video) with automatic start/stop. diff --git a/app/docs/_content/mcp-mode.mdx b/app/docs/_content/mcp-mode.mdx index 61f1829..bc8074f 100644 --- a/app/docs/_content/mcp-mode.mdx +++ b/app/docs/_content/mcp-mode.mdx @@ -34,15 +34,7 @@ The server advertises **tools** and **resources** to the client. Tool surface is ## Session defaults -Session defaults are enabled by default and are the single biggest token saver. The agent calls `session_set_defaults` once, and every subsequent tool call reuses the values: - -```json -{"name":"session_set_defaults","arguments":{ - "workspacePath":"/repo/MyApp.xcworkspace", - "scheme":"MyApp", - "simulatorName":"iPhone 17 Pro" -}} -``` +Session defaults are enabled by default and are the single biggest token saver. Tell your agent which workspace (or project), scheme, and simulator to use, and the server stores those values. Every subsequent tool call reuses them automatically, so you do not need to repeat them and your agent does not have to re-state them on every call. Defaults can also be: @@ -50,32 +42,21 @@ Defaults can also be: - Set from env vars (`XCODEBUILDMCP_WORKSPACE_PATH`, `XCODEBUILDMCP_SCHEME`, etc.) - Persisted to disk by passing `persist: true` on `session_set_defaults` -Tool schemas adjust automatically. When a default is set, the corresponding parameter becomes optional (and is filled from the default). Pass `disableSessionDefaults: true` to restore the legacy behavior where every parameter is required on every call. +Once a default is set, tools can be called without that parameter and the server fills it in. To require every parameter on every call, set `disableSessionDefaults: true` in `.xcodebuildmcp/config.yaml` (or `XCODEBUILDMCP_DISABLE_SESSION_DEFAULTS=true`). See [Session Defaults](/docs/session-defaults) for the full schema. ### Named profiles -For monorepos, keep separate defaults for each sub-project: - -```json -{"name":"session_use_defaults_profile","arguments":{"profile":"ios","persist":true}} -{"name":"session_set_defaults","arguments":{ - "workspacePath":"/repo/MyApp.xcworkspace", - "scheme":"MyApp-iOS", - "simulatorName":"iPhone 17 Pro", - "persist":true -}} -``` - -Switch profiles mid-session with `session_use_defaults_profile`. Profiles are strictly isolated, they don't inherit from `global`. +For monorepos, keep a separate defaults profile for each sub-project (for example one for the iOS app, one for the watchOS companion). Tell your agent to switch profiles, and it loads the defaults you stored for that profile. Each profile is strictly isolated; they do not inherit from `global`. ## Workflow selection -Load only the workflows your agent needs. Each dropped workflow saves tool-list tokens at boot. +The MCP server advertises only the tools in your enabled workflows. The default is just `simulator` to keep your agent's context window lean. See [Reference > Workflows](/docs/workflows) for the catalog of available workflows and what each one contains. + +Add more workflows in `.xcodebuildmcp/config.yaml`: ```yaml -# .xcodebuildmcp/config.yaml schemaVersion: 1 enabledWorkflows: - simulator @@ -83,7 +64,7 @@ enabledWorkflows: - ui-automation ``` -Or via env (for clients with limited workspace context): +Or via env (useful for clients that don't read your project's config file): ```json { @@ -93,6 +74,10 @@ Or via env (for clients with limited workspace context): } ``` + + Cutting from the full catalog to simulator,debugging drops advertised tool count from to + (minus overlaps), saving roughly 70% of the tool catalog tokens your agent has to keep in context. + + ### Custom workflows Define your own named workflow with an explicit tool list: @@ -106,18 +91,23 @@ customWorkflows: - screenshot ``` -Unknown tool names are ignored and logged. Custom workflow names are normalized to lowercase. +Notes: + +- Session-management tools are always auto-included. +- The `doctor` workflow is auto-included when `debug: true`. +- Custom workflow names are normalized to lowercase. +- Unknown tool names are ignored and logged as warnings. ### Experimental workflow discovery -Opt into the `manage-workflows` tool so the agent can add/remove workflows at runtime: +Opt into the `manage-workflows` tool so the agent can add or remove workflows at runtime: ```yaml experimentalWorkflowDiscovery: true ``` - - At the time of writing, Cursor, Claude Code, and Codex do not surface tools/list_changed notifications, so runtime workflow changes won't reflect until the session restarts. + + Some clients (including Cursor, Claude Code, and Codex at the time of writing) do not surface MCP tools/list_changed notifications, so runtime workflow changes won't reflect until the session is restarted. ## Xcode IDE bridge @@ -126,10 +116,6 @@ Enable `xcode-ide` to expose Xcode 26+'s `xcrun mcpbridge` tools through XcodeBu ## Tool annotations -Every tool declares read-only, destructive, and open-world hints. MCP clients that respect annotations (Codex, recent Claude Code) use them to reduce unnecessary confirmation prompts. +Every tool declares read-only, destructive, and open-world hints so MCP clients that respect annotations can skip unnecessary confirmation prompts for lower-risk calls and keep prompts for risky ones. -| Annotation | Meaning | -|------------|---------| -| `readOnlyHint: true` | Tool does not modify state. | -| `destructiveHint: true` | Tool may delete or overwrite. | -| `openWorldHint: true` | Tool makes network/filesystem requests beyond the project. | +See [MCP Protocol Support](/docs/mcp-protocol-support) for the full list of MCP features XcodeBuildMCP implements. diff --git a/app/docs/_content/mcp-protocol-support.mdx b/app/docs/_content/mcp-protocol-support.mdx new file mode 100644 index 0000000..a1e6da1 --- /dev/null +++ b/app/docs/_content/mcp-protocol-support.mdx @@ -0,0 +1,111 @@ +import { PageHeader } from "../_components/page-header" + + + +The [Model Context Protocol](https://modelcontextprotocol.io/specification) has many optional features. This page documents what XcodeBuildMCP actually implements, so MCP-literate users and MCP clients can evaluate coverage without reading source. Each section links out to the relevant part of the MCP specification. + +## Tools + +XcodeBuildMCP implements the [MCP tools surface](https://modelcontextprotocol.io/specification/2025-11-25/server/tools): + +- `tools/list` returns the active tool set for the current workflow configuration. +- `tools/call` invokes a registered tool and returns MCP content blocks, plus `structuredContent` when the tool has structured output. + +Workflow selection controls which tools appear. By default, only the simulator workflow is enabled. You can enable more workflows through configuration or `XCODEBUILDMCP_ENABLED_WORKFLOWS`. + +When `experimentalWorkflowDiscovery` is enabled, the `manage-workflows` tool can add or remove workflows during an MCP session. That changes the active registered tool set. + +## Tool annotations + +XcodeBuildMCP includes tool annotations in the MCP `tools/list` response. These are client hints, not security boundaries. See the [MCP Tools specification](https://modelcontextprotocol.io/specification/2025-11-25/server/tools) for how compliant clients are expected to use them. + +| Annotation key | User outcome in a compliant client | +|----------------|------------------------------------| +| `title` | Clients can show a readable name instead of only the machine name. | +| `readOnlyHint` | Read only tools can be treated as lower risk, and clients may reduce extra confirmations. | +| `destructiveHint` | Destructive tools can stay behind stronger confirmations. | +| `idempotentHint` | Tools where calling repeatedly with the same arguments produces the same effect can be safely retried by clients on transient failures. | +| `openWorldHint` | Clients can treat tools as local operations, not open world operations. | + +XcodeBuildMCP currently sets `title`, `readOnlyHint`, `destructiveHint`, and `openWorldHint` on every tool. `idempotentHint` is supported by the spec but is not currently set on any XcodeBuildMCP tool. + +## Structured content + +XcodeBuildMCP tools return MCP [`structuredContent`](https://modelcontextprotocol.io/specification/2025-11-25/server/tools#structured-content) using a consistent envelope. + +Every tool call also returns human-readable text content, which is what your agent reads in its conversation ("Build succeeded", a list of simulators, an error message). Structured content is sent alongside that text as a parallel JSON object, so the agent or any automation can consume the result programmatically without parsing prose. Text is for the agent's narrative; structured content is for branching, chaining, and automation. + +The envelope wraps every tool's structured payload in the same shape, so consumers can branch on `didError` and read `data` against the named `schema`: + +```json +{ + "schema": "xcodebuildmcp.output.simulator-list", + "schemaVersion": "1", + "didError": false, + "error": null, + "data": {} +} +``` + +The envelope fields are documented in [Output Formats](/docs/output-formats). Canonical JSON schemas live in [`schemas/structured-output/`](https://github.com/getsentry/XcodeBuildMCP/tree/main/schemas/structured-output). Tools advertise their output schema in `tools/list`. + +The one exception is the [Xcode IDE bridge](/docs/xcode-ide): bridge tools forward calls to Xcode's own MCP service, so their output shape comes from Xcode and does not use the XcodeBuildMCP envelope. + +## Resources + +XcodeBuildMCP exposes the following [MCP resources](https://modelcontextprotocol.io/specification/2025-11-25/server/resources): + +| URI | Availability | Contents | +|-----|--------------|----------| +| `xcodebuildmcp://simulators` | Normal MCP sessions | Available iOS simulators with UUIDs and states. | +| `xcodebuildmcp://devices` | Normal MCP sessions | Connected physical Apple devices with UUIDs, names, and connection status. | +| `xcodebuildmcp://doctor` | Normal MCP sessions | Development environment diagnostics and configuration status. | +| `xcodebuildmcp://session-status` | Normal MCP sessions | Runtime session state for log capture and debugging. | +| `xcodebuildmcp://xcode-ide-state` | Xcode agent sessions only | Current Xcode IDE selection, including scheme and simulator state when available. | + +The server advertises resource subscriptions and resource list changes during initialize. Current source does not emit runtime resource update or resource list change notifications after startup. + +## Notifications + +XcodeBuildMCP advertises `tools.listChanged` support during initialize. See the MCP spec for [tools/list_changed](https://modelcontextprotocol.io/specification/2025-11-25/server/tools#list-changed-notification). + +The Xcode IDE bridge explicitly emits tool list changed notifications when proxied Xcode tools are synced, cleared, or disconnected. + +Not implemented today: + +- MCP progress notifications for long running tool calls. +- MCP log-message notifications from the server logger. +- Runtime resource update notifications. + +## Prompts + +XcodeBuildMCP does not currently register [MCP prompts](https://modelcontextprotocol.io/specification/2025-11-25/server/prompts). There is no `prompts/list` or `prompts/get` support in the server. + +## Server capabilities (initialize) + +The server advertises this [capability shape](https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle) on initialize: + +```json +{ + "tools": { + "listChanged": true + }, + "resources": { + "subscribe": true, + "listChanged": true + }, + "logging": {} +} +``` + +The server also sets MCP server instructions that tell agents to prefer XcodeBuildMCP tools for Apple platform tasks and explain default workflow expectations. + +## Related + +- [Tools Reference](/docs/tools), complete tool catalog. +- [Output Formats](/docs/output-formats), structured content envelope details. +- [MCP Server Mode](/docs/mcp-mode), running the server from MCP clients. diff --git a/app/docs/_content/output-formats.mdx b/app/docs/_content/output-formats.mdx new file mode 100644 index 0000000..fd35f48 --- /dev/null +++ b/app/docs/_content/output-formats.mdx @@ -0,0 +1,320 @@ +import Link from "next/link" +import { PageHeader } from "../_components/page-header" + + + +XcodeBuildMCP exposes the same tool results through the CLI and MCP server. The CLI controls presentation with `--output text|json|jsonl|raw`. MCP clients receive the rendered text block, and tools with structured results also attach `structuredContent`. + +## CLI output modes + +Every CLI tool accepts `--output`. The default is `text`. + +```shell +xcodebuildmcp simulator list --output json +xcodebuildmcp simulator build --scheme MyApp --project-path ./MyApp.xcodeproj --output jsonl +``` + +| Mode | What you get | Use it when | +|------|--------------|-------------| +| `text` | Human-readable CLI output, with live progress for long-running tools. | An agent or person is reading the result. | +| `json` | One structured JSON response printed to stdout after the tool finishes. | A script, CI job, or custom integration needs stable fields. | +| `jsonl` | Newline-delimited JSON (NDJSON), one JSON object per line as fragments arrive. | A pipeline needs live progress without parsing terminal text. | +| `raw` | Raw subprocess transcript on stderr, with final rendered text on stdout. | You are debugging the underlying `xcodebuild`, `xcrun`, or helper process. | + + + --output json and --output jsonl are not supported for xcode-ide tools yet. The CLI rejects those combinations before it calls the tool. + + +## `--output text` + +`text` is the default. It uses the interactive CLI renderer in terminals, so build and test tools can stream progress while the command is running. In non-interactive contexts it still returns readable text. + +```shell +xcodebuildmcp simulator list +``` + +```text +Available iOS Simulators: + +• iPhone 17 Pro (Booted) + UDID: 11111111-2222-3333-4444-555555555555 + Runtime: iOS 26.0 + +Next steps: + xcodebuildmcp simulator build --scheme YOUR_SCHEME --simulator-id 11111111-2222-3333-4444-555555555555 +``` + +Use `text` for normal agent workflows. Agents can read summaries, diagnostics, and next-step commands without needing a JSON parser. + +## `--output json` + +`json` prints a structured JSON response to stdout after the tool finishes. It does not stream progress. Use it when you need stable fields for scripts or CI. + +The response has these fields: + +| Field | Type | Meaning | +|-------|------|---------| +| `schema` | `string` | Schema identifier, for example `xcodebuildmcp.output.build-result`. | +| `schemaVersion` | `string` | Version of that schema contract. | +| `didError` | `boolean` | Whether the tool reported a domain error. | +| `error` | `string \| null` | Human-readable error text when `didError` is true. | +| `data` | `object \| null` | Tool-specific data. | + +```json +{ + "schema": "xcodebuildmcp.output.simulator-list", + "schemaVersion": "1", + "didError": false, + "error": null, + "data": { + "simulators": [ + { + "name": "iPhone 17 Pro", + "simulatorId": "A1B2C3D4-E5F6-7890-ABCD-EF0123456789", + "state": "Booted", + "isAvailable": true, + "runtime": "iOS 26.4" + }, + { + "name": "iPad Pro 13-inch (M5)", + "simulatorId": "0F1E2D3C-4B5A-6978-8190-1122334455AA", + "state": "Shutdown", + "isAvailable": true, + "runtime": "iOS 26.4" + } + ] + } +} +``` + +`data` can be `null` when a tool succeeds but has no structured payload. If a tool does not produce structured output for `--output json`, the CLI emits an error response with `schema: "xcodebuildmcp.output.error"`, `didError: true`, and exits with a non-zero status. + +## `--output jsonl` + +`jsonl` streams newline-delimited JSON (NDJSON) to stdout, one JSON object per line, written as the tool produces it. Each line has this shape: + +```json +{"event":"build-result.build-stage","operation":"BUILD","stage":"COMPILING","message":"Compiling MyApp"} +``` + +The final structured response is not emitted in `jsonl` mode. Your pipeline consumes fragments as the source of truth for live progress. + +```jsonl +{"event":"build-result.invocation","operation":"BUILD","request":{"scheme":"CalculatorApp","workspacePath":"example_projects/iOS_Calculator/CalculatorApp.xcworkspace","configuration":"Debug","platform":"iOS Simulator","simulatorName":"iPhone 17"}} +{"event":"build-result.build-stage","operation":"BUILD","stage":"RESOLVING_PACKAGES","message":"Resolving packages"} +{"event":"build-result.build-stage","operation":"BUILD","stage":"COMPILING","message":"Compiling CalculatorApp"} +{"event":"build-result.build-summary","operation":"BUILD","status":"SUCCEEDED","durationMs":3421} +``` + +Use `jsonl` when the user benefits from live progress, but your caller still wants machine-readable records. + +## `--output raw` + +`raw` is for debugging subprocess behavior. Transcript fragments, such as the command line and raw process output, are written to stderr as the tool produces them. The final non-transcript rendering still goes to stdout. + +```shell +xcodebuildmcp simulator build \ + --scheme MyApp \ + --project-path ./MyApp.xcodeproj \ + --output raw +``` + +```text +$ xcodebuild -project ./MyApp.xcodeproj -scheme MyApp -destination platform=iOS Simulator,name=iPhone 17 Pro build +CompileSwift normal arm64 /repo/MyApp/ContentView.swift +Ld /tmp/DerivedData/MyApp.app/MyApp normal arm64 +``` + +Do not script against `raw`. The transcript is intentionally close to the underlying tools, so it can change when Xcode changes. + +## Structured content for MCP clients + +MCP mode always returns the normal `content` array. When a tool sets structured output, XcodeBuildMCP also attaches [`structuredContent`](https://modelcontextprotocol.io/specification/2025-11-25/server/tools#structured-content) with the same shape as `--output json`. + +```json +{ + "content": [ + { + "type": "text", + "text": "Build and run succeeded for CalculatorApp." + } + ], + "structuredContent": { + "schema": "xcodebuildmcp.output.build-run-result", + "schemaVersion": "1", + "didError": false, + "error": null, + "data": { + "request": { + "scheme": "CalculatorApp", + "workspacePath": "example_projects/iOS_Calculator/CalculatorApp.xcworkspace", + "configuration": "Debug", + "platform": "iOS Simulator", + "simulatorName": "iPhone 17" + }, + "summary": { + "status": "SUCCEEDED", + "durationMs": 3421, + "target": "simulator" + }, + "artifacts": { + "appPath": "~/Library/Developer/XcodeBuildMCP/DerivedData/Build/Products/Debug-iphonesimulator/CalculatorApp.app", + "bundleId": "io.sentry.calculatorapp", + "processId": 91827, + "simulatorId": "A1B2C3D4-E5F6-7890-ABCD-EF0123456789", + "buildLogPath": "~/Library/Developer/XcodeBuildMCP/logs/build_run_sim_20260424.log", + "runtimeLogPath": "~/Library/Developer/XcodeBuildMCP/logs/io.sentry.calculatorapp_20260424.log" + }, + "diagnostics": { + "warnings": [], + "errors": [] + } + } + } +} +``` + +Tools that declare an [output schema](https://modelcontextprotocol.io/specification/2025-11-25/server/tools#output-schema) also advertise it during MCP registration. Clients can use that schema to validate `structuredContent` or render typed UI. + +## Response schema reference + +Canonical JSON schemas live in the source repository under [`schemas/structured-output/`](https://github.com/getsentry/XcodeBuildMCP/tree/main/schemas/structured-output). Concrete examples: + +- [`xcodebuildmcp.output.simulator-list/1.schema.json`](https://github.com/getsentry/XcodeBuildMCP/blob/main/schemas/structured-output/xcodebuildmcp.output.simulator-list/1.schema.json) +- [`xcodebuildmcp.output.build-result/1.schema.json`](https://github.com/getsentry/XcodeBuildMCP/blob/main/schemas/structured-output/xcodebuildmcp.output.build-result/1.schema.json) + +## Examples + + +{`{ + "schema": "xcodebuildmcp.output.simulator-list", + "schemaVersion": "1", + "didError": false, + "error": null, + "data": { + "simulators": [ + { + "name": "iPhone 17 Pro", + "simulatorId": "A1B2C3D4-E5F6-7890-ABCD-EF0123456789", + "state": "Booted", + "isAvailable": true, + "runtime": "iOS 26.4" + }, + { + "name": "iPad Pro 13-inch (M5)", + "simulatorId": "0F1E2D3C-4B5A-6978-8190-1122334455AA", + "state": "Shutdown", + "isAvailable": true, + "runtime": "iOS 26.4" + } + ] + } +}`} + + ) }, + { label: "build_sim JSON", content: ( + +{`{ + "schema": "xcodebuildmcp.output.build-result", + "schemaVersion": "1", + "didError": false, + "error": null, + "data": { + "request": { + "scheme": "CalculatorApp", + "workspacePath": "example_projects/iOS_Calculator/CalculatorApp.xcworkspace", + "configuration": "Debug", + "platform": "iOS Simulator", + "simulatorName": "iPhone 17" + }, + "summary": { + "status": "SUCCEEDED", + "durationMs": 3421, + "target": "simulator" + }, + "artifacts": { + "buildLogPath": "~/Library/Developer/XcodeBuildMCP/logs/build_sim_20260424.log" + }, + "diagnostics": { + "warnings": [], + "errors": [] + } + } +}`} + + ) }, + { label: "build_sim NDJSON", content: ( + +{`{"event":"build-result.invocation","operation":"BUILD","request":{"scheme":"CalculatorApp","workspacePath":"example_projects/iOS_Calculator/CalculatorApp.xcworkspace","configuration":"Debug","platform":"iOS Simulator","simulatorName":"iPhone 17"}} +{"event":"build-result.build-stage","operation":"BUILD","stage":"RESOLVING_PACKAGES","message":"Resolving packages"} +{"event":"build-result.build-stage","operation":"BUILD","stage":"COMPILING","message":"Compiling CalculatorApp"} +{"event":"build-result.build-summary","operation":"BUILD","status":"SUCCEEDED","durationMs":3421}`} + + ) }, +]} /> + +## Related + +- [CLI](/docs/cli), direct terminal access to tools +- [MCP Server Mode](/docs/mcp-mode), stdio server behavior +- [Tools Reference](/docs/tools), generated tool catalog +- [Rendering & Output](/docs/architecture-rendering-output), contributor-level rendering model +- [Tool Authoring](/docs/tool-authoring), adding schemas and structured results diff --git a/app/docs/_content/privacy.mdx b/app/docs/_content/privacy.mdx index 8276e9e..e9fdd95 100644 --- a/app/docs/_content/privacy.mdx +++ b/app/docs/_content/privacy.mdx @@ -12,7 +12,7 @@ XcodeBuildMCP uses [Sentry](https://sentry.io) for internal error monitoring. Th ## What's sent - **Internal XcodeBuildMCP failures only**: for example, daemon or MCP runtime faults, unexpected exceptions in server code. -- **Internal operational logs** only when explicitly marked for Sentry (`{ sentry: true }` in server code). Standard console logs are not auto-forwarded. +- **Internal operational logs** only when the server explicitly tags an event for Sentry. Standard console logs are not auto-forwarded. - **Redacted event payloads**: user home paths become `/Users//...`, request/user context is scrubbed before send. ## What's never sent diff --git a/app/docs/_content/session-defaults.mdx b/app/docs/_content/session-defaults.mdx index 5311337..65dd215 100644 --- a/app/docs/_content/session-defaults.mdx +++ b/app/docs/_content/session-defaults.mdx @@ -13,27 +13,16 @@ Session defaults are **on by default**. ## How it works -1. The agent calls `session_set_defaults` once at the start of the session (or you seed them in config). -2. Every tool call with a matching parameter uses the default if not explicitly passed. -3. The agent can call `session_show_defaults` to inspect the current values at any time. -4. The agent can call `session_clear_defaults` when switching contexts. +1. At the start of a session, the agent stores your defaults (workspace, scheme, simulator, etc.) via `session_set_defaults`, or picks them up from `.xcodebuildmcp/config.yaml`. +2. Every subsequent tool call uses those stored values when a matching parameter is missing. +3. Ask your agent to show the current defaults at any time. It reads them via `session_show_defaults`. +4. When you switch projects or context, ask the agent to clear or replace the defaults. It uses `session_clear_defaults` or another `session_set_defaults` call. ## Setting defaults ### From the agent (runtime) -```json -{ - "name": "session_set_defaults", - "arguments": { - "workspacePath": "/repo/MyApp.xcworkspace", - "scheme": "MyApp", - "simulatorName": "iPhone 17 Pro" - } -} -``` - -By default these live in memory only. Pass `persist: true` to write them back to `.xcodebuildmcp/config.yaml`, patch-only, so only the keys in that call are updated. +Tell your agent which workspace (or project), scheme, and simulator to use; it will store those values via `session_set_defaults`. By default these live in memory only. Ask your agent to persist them and they will be saved to `.xcodebuildmcp/config.yaml`, patch-only, so only the keys you set are updated. ### From config (startup) @@ -106,31 +95,7 @@ sessionDefaultsProfiles: activeSessionDefaultsProfile: ios ``` -The agent switches profiles with `session_use_defaults_profile`: - -```json -{ - "name": "session_use_defaults_profile", - "arguments": { "profile": "watch", "persist": true } -} -``` - -Pass `global: true` to switch back to the unnamed global profile. Pass `createIfNotExists: true` on `session_set_defaults` to create a new profile in one call. - -### Recommended startup flow (monorepo) - -Copy/paste for an agent starting a new session: - -```json -{"name":"session_use_defaults_profile","arguments":{"profile":"ios","persist":true}} -{"name":"session_set_defaults","arguments":{ - "workspacePath":"/repo/MyApp.xcworkspace", - "scheme":"MyApp-iOS", - "simulatorName":"iPhone 17 Pro", - "persist":true -}} -{"name":"session_show_defaults","arguments":{}} -``` +Tell your agent to switch profiles ("use the watch profile") and it will load that profile via `session_use_defaults_profile`. Ask it to persist the switch if you want the profile selection to survive restarts. To return to the unnamed global profile, ask the agent to switch back to global. To create a new profile on the fly, ask the agent to set defaults under a new profile name. ## Opting out diff --git a/app/docs/_content/setup.mdx b/app/docs/_content/setup.mdx index e7af1c3..8447c80 100644 --- a/app/docs/_content/setup.mdx +++ b/app/docs/_content/setup.mdx @@ -44,7 +44,7 @@ Non-interactive mode is available for CI and scripts (`xcodebuildmcp setup --hel ## 3. (Optional) Install an agent skill -If you're using Claude Code, Cursor, or Codex, installing the agent skill helps your agent use XcodeBuildMCP effectively without burning tokens rediscovering conventions: +If you're using Codex, Cursor or another client, installing the agent skill helps your agent use XcodeBuildMCP effectively without burning tokens rediscovering conventions: ```shell xcodebuildmcp init diff --git a/app/docs/_content/testing.mdx b/app/docs/_content/testing.mdx new file mode 100644 index 0000000..961d1be --- /dev/null +++ b/app/docs/_content/testing.mdx @@ -0,0 +1,150 @@ +import Link from "next/link" +import { PageHeader } from "../_components/page-header" + + + +Tests should prove behavior without reaching real Apple tools unless the suite is explicitly an integration, smoke, or snapshot suite. Unit tests stay fast by injecting executors and filesystem dependencies at the tool logic boundary. + +A few terms used throughout this page: a **handler** is the function inside a tool module that performs one validated action and writes its result onto the call context; a **fixture** is a checked-in expected output stored under `src/snapshot-tests/__fixtures__/`; a **snapshot test** runs a tool and compares its output against the matching fixture, failing if they diverge; a **structured JSON response** is the tool's canonical machine-readable result, validated against a published schema and used by both MCP `structuredContent` and CLI `--output json`. See [Core terms](/docs/architecture#core-terms) for the broader architecture vocabulary. + +## Test runner + +| Concern | Current setup | +|---------|---------------| +| Runner | Vitest 3.x. | +| Unit config | `vitest.config.ts`. | +| Snapshot config | `vitest.snapshot.config.ts`. | +| Smoke config | `vitest.smoke.config.ts`. | +| Test files | `src/**/*.test.ts`, commonly under `__tests__/`. | +| Default command | `npm test`, which runs `vitest run`. | + +Use focused Vitest runs while developing, then run the relevant full commands before handoff. + +```shell +npm test -- src/mcp/tools/simulator/__tests__/list_sims.test.ts +npm test -- --reporter=verbose +``` + +## The core rule + +Use dependency injection for complex tool logic. Use normal Vitest mocks for simple utility modules and in-memory collaborators. + +| Case | Use | Why | +|------|-----|-----| +| Tool logic that orchestrates `xcodebuild`, `xcrun`, AXe, filesystem writes, or multi-step subprocesses | Inject `CommandExecutor`, `FileSystemExecutor`, or another explicit dependency. | Keeps tests deterministic and prevents real external calls. | +| Simple utility modules or internal collaborators | `vi.fn`, `vi.mock`, `vi.spyOn`, and normal in-memory test doubles. | Simpler code is better when the dependency is not a complex process boundary. | +| Handlers | Do not test handlers directly. Test the logic function or executor factory underneath. | Handlers are runtime wrappers around validation, context setup, and rendering. | +| External systems | Never hit real `xcodebuild`, `xcrun`, AXe, devices, simulators, or uncontrolled filesystem paths in unit tests. | Unit tests must not depend on local machine state. | + +## Three dimensions + +Every tool test should cover three dimensions. + +| Dimension | What to test | Good assertion style | +|-----------|--------------|----------------------| +| Input validation | Valid params, invalid params, missing required params, mutually exclusive params, and session-default requirements. | Parse the exported Zod `schema`, or exercise the logic path that produces validation text without reaching external systems. | +| Command generation | The tool builds the right command and handles path, scheme, platform, and option combinations. | Verify behavior through the response, structured output, or a narrow executor callback when the command itself is the behavior under test. | +| Output processing | Success payloads, command failures, executor throws, parsing errors, diagnostics, next-step params, and structured output. | Assert rendered text and `ctx.structuredOutput`, not incidental implementation details. | + +Do not use command-spying as a substitute for behavior assertions. If a test only proves that an array was assembled but never proves the user-visible result, it is too shallow. + +## Mock executors + +Use the shared helpers from `src/test-utils/mock-executors.ts`. + +| Helper | Use it for | +|--------|------------| +| `createMockExecutor(...)` | Return a successful command response, a failed command response, or throw an error. | +| `createMockFileSystemExecutor(...)` | Override filesystem behavior such as `existsSync`, `readFile`, `writeFile`, `stat`, or `mkdtemp`. | +| `createNoopExecutor()` | Fail the test if a command path should never be reached. | +| `createNoopFileSystemExecutor()` | Fail the test if filesystem access should never be reached. | +| `createCommandMatchingMockExecutor(...)` | Return different responses for tools that run multiple commands. | +| `createMockInteractiveSpawner(...)` | Test interactive process flows without spawning a real process. | + +A small logic-function test should look like this: + +```ts +import { expect, it } from 'vitest'; +import { createMockExecutor } from '../../../../test-utils/mock-executors.ts'; +import { runToolLogic } from '../../../../test-utils/test-helpers.ts'; +import { list_simsLogic } from '../list_sims.ts'; + +it('renders listed simulators', async () => { + const executor = createMockExecutor({ success: true, output: '{"devices":{"iOS 17.0":[]}}' }); + const { result } = await runToolLogic(() => list_simsLogic({ enabled: true }, executor)); + expect(result.text()).toContain('List Simulators'); +}); +``` + +Use `createNoopExecutor()` when the test is about validation or early exits. If it fires, the code reached an external boundary unexpectedly. + +## Snapshot tests + +Snapshot tests lock the public output contracts. They are slower and more environment-sensitive than unit tests. + +| Fixture tree | Validates | +|--------------|-----------| +| `src/snapshot-tests/__fixtures__/mcp/` | MCP text returned through `ToolResponse.content`. | +| `src/snapshot-tests/__fixtures__/cli/` | CLI `--output text` output. | +| `src/snapshot-tests/__fixtures__/json/` | Structured JSON response used by MCP `structuredContent` and CLI JSON output. | + +Run snapshots with full output preserved: + +```shell +npm run test:snapshots 2>&1 | tee /tmp/snapshot-results.txt +``` + +Regenerate snapshots only for intentional output changes: + +```shell +npm run test:snapshots:update 2>&1 | tee /tmp/snapshot-update.txt +``` + + + If a snapshot changes unexpectedly, assume the code is wrong before blaming the fixture. Review every fixture diff before committing it. + + +JSON fixtures must also validate against the canonical structured-output schemas: + +```shell +npm run test:schema-fixtures +``` + +## Pre-commit flow + +Follow the command list in [Contributing](/docs/contributing#pre-commit-checks). Do not invent a shorter local checklist for tool work. + +The installed pre-commit hook covers format check, lint, build, and docs check. It does not replace targeted tests, snapshot tests, schema fixture validation, or manual validation for runtime behavior. + +## Running the full suite + +Use these commands as the baseline for contributor handoff: + +```shell +npm test +npm run test:snapshots +npm run test:schema-fixtures +``` + +Snapshot tests may need a physical device ID when device fixtures are involved: + +```shell +DEVICE_ID= npm run test:snapshots 2>&1 | tee /tmp/snapshot-results.txt +``` + + + For long suites, always tee the full output to a log file under /tmp. Do not pipe directly through tail or grep, because that loses context you may need to debug failures. + + +The snapshot suite baseline is about seven minutes. Treat runs longer than about ten minutes as a likely hang. + +## Related + +- [Architecture](/docs/architecture), how tool logic, fragments, results, and rendering fit together +- [Contributing](/docs/contributing#pre-commit-checks), setup and required local checks +- [Tool Authoring](/docs/tool-authoring), adding implementation, manifests, schemas, and fixtures +- [Output Formats](/docs/output-formats), structured JSON responses and MCP `structuredContent` diff --git a/app/docs/_content/tool-authoring.mdx b/app/docs/_content/tool-authoring.mdx new file mode 100644 index 0000000..63fa531 --- /dev/null +++ b/app/docs/_content/tool-authoring.mdx @@ -0,0 +1,391 @@ +import Link from "next/link" +import { PageHeader } from "../_components/page-header" + + + +A tool change usually touches more than one file. Keep the implementation, manifest metadata, structured output schema, fixtures, and generated docs aligned in the same change. + +If you are new to the architecture, this page leans on a few terms that are defined in full in [Core terms](/docs/architecture#core-terms). The short version: a **tool** is one user-visible action exposed through MCP and CLI; the **handler** is the function that performs the work and writes its outcome onto the call context; the **manifest** is the YAML file that declares the tool's metadata (names, schema reference, exposure rules) without containing the implementation; **fragments** are progress events the handler emits while running; the **structured output** is the canonical JSON result the handler sets at the end of the call. + +## Mental model + +| Layer | Location | What must stay true | +|-------|----------|---------------------| +| Implementation | `src/mcp/tools//.ts` | Exports `schema` and `handler`, validates input with Zod, executes the work, and sets `ctx.structuredOutput`. | +| Tool manifest | `manifests/tools/.yaml` | Defines tool ID, module path, MCP and CLI names, description, annotations, availability, predicates, routing, and output schema metadata. | +| Workflow manifest | `manifests/workflows/.yaml` | References the tool ID so the tool appears in one or more workflows. | +| Output schema | `schemas/structured-output//.schema.json` | Validates the structured JSON response returned through MCP `structuredContent` and CLI JSON output. | +| Fixtures | `src/snapshot-tests/__fixtures__/{mcp,cli,json}/...` | Lock the MCP text, CLI text, and JSON response contracts. | +| Generated docs | `docs/TOOLS.md`, `docs/TOOLS-CLI.md` | Generated from manifests and schemas. Do not edit them by hand. | + +The final structured result is the canonical output. Rendered text is derived from that result, fragments, and runtime-specific rendering rules. See [Tool Lifecycle](/docs/architecture-tool-lifecycle#streaming-vs-non-streaming-tools) for the runtime model and [Output Formats](/docs/output-formats) for the response shape. + +## Adding a new tool + +### 1. Pick streaming or non-streaming + +| Tool shape | Use it when | Examples | Rule | +|------------|-------------|----------|------| +| Non-streaming | The tool computes one result and returns. | Listing, discovery, metadata, cleanup, session defaults. | Do not emit fragments. Set `ctx.structuredOutput` once. | +| Streaming | The user benefits from live progress while the tool runs. | Build, build-and-run, test, long-running SwiftPM commands. | Emit progress fragments, then set the final structured result. | + +Use the simpler non-streaming path unless the user needs live progress. Do not add a streaming path for a short query just because another tool uses one. + +### 2. Create the implementation + +Create the implementation under `src/mcp/tools//.ts`. A normal tool exports a Zod schema shape and a handler created with `createTypedTool(...)`. + +Minimal non-streaming shape: + +```ts +import * as z from 'zod'; +import type { NonStreamingExecutor } from '../../../types/tool-execution.ts'; +import type { CommandExecutor } from '../../../utils/execution/index.ts'; +import { getDefaultCommandExecutor } from '../../../utils/execution/index.ts'; +import { createTypedTool, getHandlerContext } from '../../../utils/typed-tool-factory.ts'; + +const listWidgetsSchema = z.object({ + enabled: z.boolean().optional(), +}); + +type ListWidgetsParams = z.infer; +type WidgetListResult = { + kind: 'widget-list'; + didError: boolean; + error: string | null; + widgets: Array<{ name: string }>; +}; + +export function createListWidgetsExecutor( + executor: CommandExecutor, +): NonStreamingExecutor { + return async () => { + const response = await executor(['xcrun', 'widgetctl', 'list', '--json'], 'List Widgets', false); + + if (!response.success) { + return { kind: 'widget-list', didError: true, error: response.error ?? 'List failed', widgets: [] }; + } + + return { kind: 'widget-list', didError: false, error: null, widgets: JSON.parse(response.output) }; + }; +} + +export async function list_widgetsLogic( + params: ListWidgetsParams, + executor: CommandExecutor, +): Promise { + const ctx = getHandlerContext(); + const result = await createListWidgetsExecutor(executor)(params); + + ctx.structuredOutput = { + result, + schema: 'xcodebuildmcp.output.widget-list', + schemaVersion: '1', + }; +} + +export const schema = listWidgetsSchema.shape; +export const handler = createTypedTool(listWidgetsSchema, list_widgetsLogic, getDefaultCommandExecutor); +``` + +For session-default-aware tools, follow the existing `createSessionAwareTool(...)` pattern used by build and test tools. The public schema can hide parameters that session defaults provide, while the internal schema still validates the fully merged argument set. + +### 3. Define or reuse the domain result + +Prefer an existing domain result when it fits. Common schema IDs include: + +| Result | Schema ID | +|--------|-----------| +| Build result | `xcodebuildmcp.output.build-result` | +| Build and run result | `xcodebuildmcp.output.build-run-result` | +| Test result | `xcodebuildmcp.output.test-result` | +| Simulator list | `xcodebuildmcp.output.simulator-list` | +| App path | `xcodebuildmcp.output.app-path` | +| UI action | `xcodebuildmcp.output.ui-action-result` | + +Create a new schema only when no existing schema accurately describes the payload. The schema validates the full structured response, not only the `data` object. Published schema versions use integer strings such as `"1"` and `"2"`. + +### 4. Create the tool manifest + +Create `manifests/tools/.yaml`. The `id` must match the filename without `.yaml`, and `module` points to the implementation path under `src/` without an extension. + +```yaml +id: list_widgets +module: mcp/tools/simulator/list_widgets +names: + mcp: list_widgets + cli: list-widgets +description: List available widgets. +availability: + mcp: true + cli: true +annotations: + title: List Widgets + readOnlyHint: true + destructiveHint: false + openWorldHint: false +outputSchema: + schema: xcodebuildmcp.output.widget-list + version: "1" +``` + +| Field | Required | Notes | +|-------|----------|-------| +| `id` | Yes | Unique tool ID, usually `snake_case`, matching the filename. | +| `module` | Yes | Package-relative module path, for example `mcp/tools/simulator/list_sims`. | +| `names.mcp` | Yes | MCP protocol name. This is what agents call. | +| `names.cli` | No | CLI command name. If omitted, the MCP name is converted to kebab-case. | +| `description` | No | Shown in generated tool docs and catalogs. | +| `annotations` | No | MCP hints such as `readOnlyHint`, `destructiveHint`, `idempotentHint`, and `openWorldHint`. | +| `outputSchema` | No | Required when the tool sets `ctx.structuredOutput`. Advertised to MCP clients per the [MCP output schema spec](https://modelcontextprotocol.io/specification/2025-11-25/server/tools#output-schema). Must match the emitted schema and version. | +| `availability` | No | Controls MCP and CLI exposure. Defaults to available. | +| `predicates` | No | Visibility gates such as `debugEnabled` or `hideWhenXcodeAgentMode`. | +| `routing.stateful` | No | Set to `true` for CLI tools that must route through the daemon. | + +### 5. Register the tool in a workflow + +Add the tool ID to one or more workflow manifests: + +```yaml +id: simulator +tools: + - list_sims + - list_widgets +``` + +A tool can appear in multiple workflows, but it should have one tool manifest. Workflow selection and predicates decide which runtimes expose it. + +### 6. Regenerate docs and validate schemas + +If you add, remove, or change tool metadata, run: + +```shell +npm run docs:update +npm run docs:check +``` + +If the tool produces structured output, also run: + +```shell +npm run test:schema-fixtures +npx vitest run src/core/__tests__/structured-output-schema.test.ts +``` + +`npm run docs:update` updates generated tool reference files. Do not hand-edit generated tool docs. + +### 7. Add fixtures + +Add or update representative fixtures under: + +| Fixture tree | Validates | +|--------------|-----------| +| `src/snapshot-tests/__fixtures__/mcp/` | MCP text output. | +| `src/snapshot-tests/__fixtures__/cli/` | CLI text output. | +| `src/snapshot-tests/__fixtures__/json/` | Structured JSON response. | + +Regenerate snapshots only after you understand the behavior change: + +```shell +npm run test:snapshots:update 2>&1 | tee /tmp/snapshot-update.txt +``` + + + Do not update fixtures just to make a failing test pass. If a fixture changes unexpectedly, assume the implementation is wrong until you prove the fixture should change. + + +## Streaming tools + +A streaming tool emits live progress fragments while it runs, then sets one canonical `ctx.structuredOutput` at the end. The mechanism is `ctx.emit(fragment)`, where `fragment` is one of the kinds in the closed `AnyFragment` union defined in `src/types/domain-fragments.ts`: + +| Fragment family | `kind` value(s) | Used by | +|-----------------|-----------------|---------| +| Transcript | `'transcript'` | Any subprocess that wants raw stdout/stderr replay. | +| Build-like | `'build-result'`, `'build-run-result'`, `'test-result'` | The xcodebuild pipeline (build, build-run, and test tools). | +| Runtime status | See `src/types/runtime-status.ts`. | Runtime infrastructure messages. | + +`ctx.emit` is typed against this union. If your tool needs a streaming shape that does not fit any existing fragment, you have to add it: define the new fragment interfaces in `src/types/domain-fragments.ts`, extend `AnyFragment`, and update the renderer to format the new shape. That is a real architectural change, not a per-tool concern. Reach for it only after confirming an existing fragment family does not fit. + +Three patterns cover every streaming tool currently in the codebase. Pick the one that matches what your tool is doing. + +### Pattern 1: Raw subprocess transcript (CLI raw mode only) + +When the value of a streaming tool is replaying a subprocess's stdout/stderr in real time (for example, `simctl log stream`) and nothing more, the standard executor (`getDefaultCommandExecutor()`) emits `TranscriptFragment` events automatically via async-local storage. The handler does not call `ctx.emit` itself. Structurally it looks identical to a non-streaming handler: + +```ts +import * as z from 'zod'; +import type { CommandExecutor } from '../../../utils/execution/index.ts'; +import { getDefaultCommandExecutor } from '../../../utils/execution/index.ts'; +import { createTypedTool, getHandlerContext } from '../../../utils/typed-tool-factory.ts'; + +const watchLogsSchema = z.object({ + simulatorId: z.string(), +}); + +type WatchLogsParams = z.infer; +type WatchLogsResult = { + kind: 'log-stream'; + didError: boolean; + error: string | null; + exitCode: number | null; +}; + +export async function watch_logsLogic( + params: WatchLogsParams, + executor: CommandExecutor, +): Promise { + const ctx = getHandlerContext(); + const response = await executor( + ['xcrun', 'simctl', 'spawn', params.simulatorId, 'log', 'stream'], + 'Watch Simulator Logs', + false, + ); + + ctx.structuredOutput = { + result: { + kind: 'log-stream', + didError: !response.success, + error: response.error ?? null, + exitCode: response.exitCode ?? null, + }, + schema: 'xcodebuildmcp.output.log-stream', + schemaVersion: '1', + }; +} + +export const schema = watchLogsSchema.shape; +export const handler = createTypedTool(watchLogsSchema, watch_logsLogic, getDefaultCommandExecutor); +``` + +The catch: the transcript-emitter context is **only registered by CLI `--output raw` mode** (`src/cli/register-tool-commands.ts`). In CLI text, JSON, JSONL, and MCP modes, the executor's transcript emissions are silently dropped. Use this pattern when raw subprocess replay in raw mode is genuinely all the tool needs to do — typically debugging-oriented tools. + +### Pattern 2: Typed domain fragments + +When the user benefits from structured progress events that work across all output modes — phase markers, warnings, test failures — the handler emits existing fragment shapes directly through `ctx.emit`: + +```ts +ctx.emit({ + kind: 'test-result', + fragment: 'test-failure', + operation: 'TEST', + test: 'MyAppTests.testLoginFlow', + message: 'Expected status 200, got 401', + durationMs: 1240, +}); +``` + +Each `kind` has a fixed set of `fragment` discriminators in `src/types/domain-fragments.ts`. The render layer already knows how to format each shape for MCP text, CLI text, and JSONL. + +Streaming output from a still-running subprocess is a separate concern: the standard `executor()` awaits the subprocess to completion before returning, so it does not expose live output to the handler. To read stdout/stderr line-by-line as it arrives, use `getDefaultInteractiveSpawner()` from `src/utils/execution/`. The spawner returns an `InteractiveProcess` whose `process.stdout` / `process.stderr` streams the handler can attach to and emit fragments from as output is parsed. + +### Pattern 3: The xcodebuild pipeline (build, build-run, and test tools only) + +Tools that wrap `xcrun xcodebuild` — `build_sim`, `build_device`, `build_macos`, the `build_run_*` family, `test_sim`, `test_device`, `test_macos`, and the Swift Package equivalents — go through a shared pipeline in `src/utils/xcodebuild-pipeline.ts`. The pipeline spawns `xcodebuild`, parses its stdout into typed `BuildStageFragment`, `CompilerDiagnosticFragment`, and `BuildSummaryFragment` events, captures the full build log to disk, and aggregates the run into a canonical domain result. Each tool plugs into it through five helpers: + +```ts +export async function build_widgetLogic( + params: BuildWidgetParams, + executor: CommandExecutor, +): Promise { + const ctx = getHandlerContext(); + const prepared = await prepareBuildWidgetExecution(params, executor); + + ctx.emit(createBuildInvocationFragment('build-result', 'BUILD', prepared.invocationRequest)); + + const executionContext = createStreamingExecutionContext(ctx); + const executeBuildWidget = createBuildWidgetExecutor(executor, prepared); + const result = await executeBuildWidget(params, executionContext); + + setXcodebuildStructuredOutput(ctx, 'build-result', result); +} +``` + +| Helper | What it does | +|--------|--------------| +| `prepareBuildExecution(params, executor)` | Tool-specific. Resolves user params (workspace, scheme, configuration, target) into a concrete `BuildInvocationRequest` plus any preflight side-effects such as resolving a simulator UUID or derived-data path. | +| `createBuildInvocationFragment(kind, op, request)` | Returns the leading `BuildInvocationFragment` that announces what is about to run. Emit it once before the executor starts so the renderer has full invocation context for the rest of the stream. | +| `createStreamingExecutionContext(ctx)` | Adapts the handler's `ctx.emit` into the callback shape the pipeline's executor expects. The pipeline pushes parsed fragments back to the handler context through this adapter. | +| `createBuildExecutor(executor, prepared)` | Tool-specific. Returns the async function that actually invokes `xcrun xcodebuild` with the prepared request, streams its stdout through the pipeline's parser, and returns the canonical domain result. The real subprocess call lives here. | +| `setXcodebuildStructuredOutput(ctx, kind, result)` | Sets `ctx.structuredOutput` with the canonical schema ID (`xcodebuildmcp.output.build-result`, `…build-run-result`, or `…test-result`) and the current schema version. | + +Build-like results must include `request` in the final result. Do not rely on the streamed invocation fragment for final rendering, `--output json`, or MCP `structuredContent`. + +Working reference: `src/mcp/tools/simulator/build_sim.ts`. + + + Inside an xcodebuild-pipeline executor (the function returned by createBuild<Tool>Executor) the variable named ctx is the streaming execution context, not the handler context, and its method is emitFragment(...) rather than emit(...). In your top-level <tool>Logic function, ctx is always the handler context with emit(...). They are different objects with different APIs; do not conflate them. + + +Use this pipeline only when the tool wraps `xcodebuild`. For any other long-running subprocess tool, use Pattern 1 or Pattern 2. + +## Modifying a tool + + +

Change manifests/tools/<tool>.yaml first. Metadata includes descriptions, names, annotations, availability, predicates, routing, next-step templates, and output schema metadata.

+

Run npm run docs:update and npm run docs:check. If a name changes, update tests, fixtures, and any next-step references that call the old name.

+ + ) }, + { label: "Input schema", content: ( + <> +

Input parameters live in the implementation Zod schema. Update descriptions, required fields, mutually exclusive checks, session-default requirements, and tests together.

+

Run docs generation because CLI and MCP docs are generated from the schema and manifest.

+ + ) }, + { label: "Output schema", content: ( + <> +

Keep ctx.structuredOutput.schema, ctx.structuredOutput.schemaVersion, manifest outputSchema, canonical schema files, and JSON fixtures aligned.

+

Compatible optional additions can stay on the same version. Breaking changes need a new versioned file such as 2.schema.json.

+ + ) }, +]} /> + +| Change | Required follow-up | +|--------|--------------------| +| Metadata only | Regenerate generated docs and update fixture text if descriptions or names are visible. | +| Input schema | Update Zod schema, parameter tests, generated docs, and any snapshots affected by validation text. | +| Compatible output addition | Update the existing schema, implementation, JSON fixtures, and schema fixture tests. | +| Breaking output change | Add `schemas/structured-output//2.schema.json`, emit `schemaVersion: '2'`, update manifest `outputSchema.version`, and update fixtures. | +| Runtime behavior | Update logic tests, MCP text fixtures, CLI text fixtures, JSON fixtures, and changelog if user-facing. | + + + Use integer string versions. Do not use semver-style schema versions such as "1.1" or "2.0". + + +## Deleting a tool + +Use a deletion checklist. Tool removal affects user-visible surfaces. + +1. Remove the tool ID from every workflow manifest. +2. Delete `manifests/tools/.yaml`. +3. Delete the implementation file if no other code imports it. +4. Delete tests that only cover that tool. +5. Delete MCP, CLI, and JSON fixtures for that tool. +6. Run `npm run docs:update` and `npm run docs:check`. +7. Run `npm run typecheck`, `npm test`, and `npm run test:schema-fixtures`. + +Do not delete a shared schema just because one tool stopped using it. Schemas are published contracts. Remove one only when it is unpublished or clearly unused after checking consumers. + +## Common mistakes + +- Adding an implementation without a matching tool manifest. +- Adding a tool manifest without adding the tool ID to a workflow manifest. +- Setting `ctx.structuredOutput` without manifest `outputSchema` metadata. +- Emitting fragments from a non-streaming tool. +- Using `createStreamingExecutionContext(...)` in a non-streaming tool. +- Relying on streamed fragments for final JSON data. +- Changing JSON payload shape without updating schemas and JSON fixtures. +- Hand-editing generated tool docs. +- Updating snapshots before understanding why they changed. +- Preserving legacy fallback behavior instead of making the requested path canonical. + +## Related + +- [Tool Lifecycle](/docs/architecture-tool-lifecycle#streaming-vs-non-streaming-tools), streaming, fragments, results, and rendering +- [Output Formats](/docs/output-formats), CLI JSON and MCP `structuredContent` responses +- [Testing](/docs/testing), unit, snapshot, schema, and pre-commit rules +- [Tools Reference](/docs/tools), generated catalog of exposed tools diff --git a/app/docs/_content/workflows.mdx b/app/docs/_content/workflows.mdx index 6e1028e..5758c45 100644 --- a/app/docs/_content/workflows.mdx +++ b/app/docs/_content/workflows.mdx @@ -2,26 +2,20 @@ import Link from "next/link" import { PageHeader } from "../_components/page-header" -By default only the `simulator` workflow is enabled. Enable more via `.xcodebuildmcp/config.yaml`: +## What workflows are -```yaml -schemaVersion: 1 -enabledWorkflows: - - simulator - - debugging - - ui-automation -``` +A workflow is a named group of related tools (`simulator`, `debugging`, `ui-automation`, etc.). Workflows exist to control which tools the MCP server advertises in `tools/list`. Every advertised tool consumes context tokens in your agent, so picking only the workflows you need keeps the tool catalog lean. -Or via env var (comma-separated): +By default only the `simulator` workflow is enabled. To enable more (or define your own), see [MCP Server Mode → Workflow selection](/docs/mcp-mode#workflow-selection) for the full configuration surface, including custom workflows and experimental runtime discovery. -```shell -export XCODEBUILDMCP_ENABLED_WORKFLOWS="simulator,debugging,ui-automation" -``` + + The CLI does not gate by enabled workflows. Every workflow's commands are always available as `xcodebuildmcp `. The CLI does not pay an upfront context cost because agents and humans discover commands progressively via `--help`; `enabledWorkflows` only affects what the MCP server advertises. + ## Available workflows @@ -29,39 +23,8 @@ This list is generated live from the latest [getsentry/XcodeBuildMCP](https://gi -## Custom workflows - -Define your own workflow in `config.yaml` with an explicit tool list: - -```yaml -schemaVersion: 1 -enabledWorkflows: ["my-workflow"] -customWorkflows: - my-workflow: - - build_run_sim - - record_sim_video - - screenshot -``` - -Notes: - -- Session-management tools are always auto-included. -- The `doctor` workflow is auto-included when `debug: true`. -- Custom workflow names are normalized to lowercase. -- Unknown tool names are ignored and logged as warnings. - -## Experimental: workflow discovery +## Related -Expose a `manage-workflows` tool so agents can add/remove workflows at runtime: - -```yaml -experimentalWorkflowDiscovery: true -``` - - - This depends on MCP `tools/list_changed` notifications. Cursor, Claude Code, and Codex do not support this at the time of writing; a session restart is required for changes to take effect. - - - - Cutting from the full catalog to simulator,debugging drops advertised tool count from to + (minus overlaps), saving roughly 70% of tool-list tokens on agent boot. - +- [MCP Server Mode → Workflow selection](/docs/mcp-mode#workflow-selection): how to enable, customize, and override workflows. +- [Tools Reference](/docs/tools): every tool by name, with the workflow it belongs to. +- [Configuration](/docs/configuration): full config schema for `.xcodebuildmcp/config.yaml`. diff --git a/app/docs/_content/xcode-ide.mdx b/app/docs/_content/xcode-ide.mdx index 4324e89..3089669 100644 --- a/app/docs/_content/xcode-ide.mdx +++ b/app/docs/_content/xcode-ide.mdx @@ -43,7 +43,7 @@ When `xcode-ide` is enabled and `mcpbridge` is available, XcodeBuildMCP exposes These two tools are stable and always present when the workflow is enabled. The actual tool catalog they proxy depends on your Xcode version, expect the set to grow as Xcode ships new IDE-facing tools. -The CLI continues to use dynamic `xcode_tools_*` proxy naming. +In CLI mode, proxied Xcode tools are exposed under dynamic `xcode_tools_*` names instead of the two gateway tools above. ## Trust prompts diff --git a/app/docs/_data/routes.ts b/app/docs/_data/routes.ts index c6d8bfb..a81ac6e 100644 --- a/app/docs/_data/routes.ts +++ b/app/docs/_data/routes.ts @@ -9,6 +9,8 @@ export type DocSlug = | "mcp-mode" | "workflows" | "tools" + | "mcp-protocol-support" + | "output-formats" | "configuration" | "session-defaults" | "env-vars" @@ -20,6 +22,16 @@ export type DocSlug = | "privacy" | "troubleshooting" | "changelog" + | "contributing" + | "architecture" + | "architecture-runtime-boundaries" + | "architecture-startup-config" + | "architecture-manifest-visibility" + | "architecture-tool-lifecycle" + | "architecture-rendering-output" + | "architecture-daemon" + | "tool-authoring" + | "testing" export interface DocRoute { slug: DocSlug @@ -47,8 +59,10 @@ export const PAGES_ORDER: DocSlug[] = [ "clients", "cli", "mcp-mode", - "workflows", "tools", + "workflows", + "mcp-protocol-support", + "output-formats", "configuration", "session-defaults", "env-vars", @@ -60,6 +74,16 @@ export const PAGES_ORDER: DocSlug[] = [ "privacy", "troubleshooting", "changelog", + "contributing", + "architecture", + "architecture-runtime-boundaries", + "architecture-startup-config", + "architecture-manifest-visibility", + "architecture-tool-lifecycle", + "architecture-rendering-output", + "architecture-daemon", + "tool-authoring", + "testing", ] export const PAGE_META: Record = { @@ -105,8 +129,8 @@ export const PAGE_META: Record = { workflows: { slug: "workflows", title: "Workflows", - group: "Usage", - description: "Tools grouped into workflow packages. Load only what your agent needs.", + group: "Reference", + description: "The catalog of tool groups XcodeBuildMCP exposes through MCP, and what each one contains.", }, tools: { slug: "tools", @@ -114,6 +138,18 @@ export const PAGE_META: Record = { group: "Reference", description: "All tools XcodeBuildMCP advertises, synced live from the latest release.", }, + "mcp-protocol-support": { + slug: "mcp-protocol-support", + title: "MCP Protocol Support", + group: "Reference", + description: "Which features of the MCP protocol XcodeBuildMCP implements.", + }, + "output-formats": { + slug: "output-formats", + title: "Output Formats", + group: "Reference", + description: "Machine-readable CLI output and MCP structuredContent envelopes.", + }, configuration: { slug: "configuration", title: "Configuration", @@ -182,6 +218,67 @@ export const PAGE_META: Record = { group: "Guides", description: "Notable changes in each release.", }, + contributing: { + slug: "contributing", + title: "Contributing", + group: "Contributing", + description: "How to set up, build, and submit changes to XcodeBuildMCP.", + }, + architecture: { + slug: "architecture", + title: "Architecture Overview", + group: "Contributing", + description: + "Why XcodeBuildMCP is split into manifests, runtime boundaries, tool handlers, rendering, and daemon transport.", + }, + "architecture-runtime-boundaries": { + slug: "architecture-runtime-boundaries", + title: "Runtime Boundaries", + group: "Contributing", + description: "How MCP, CLI, direct invocation, and daemon-routed invocation share one tool layer.", + }, + "architecture-startup-config": { + slug: "architecture-startup-config", + title: "Startup & Configuration", + group: "Contributing", + description: "How runtime bootstrap, config precedence, workflow inputs, and session defaults fit together.", + }, + "architecture-manifest-visibility": { + slug: "architecture-manifest-visibility", + title: "Manifests & Visibility", + group: "Contributing", + description: "How manifests define tools, workflows, resources, availability, predicates, and lazy imports.", + }, + "architecture-tool-lifecycle": { + slug: "architecture-tool-lifecycle", + title: "Tool Lifecycle", + group: "Contributing", + description: "The contract between tool modules, handlers, domain results, fragments, and next steps.", + }, + "architecture-rendering-output": { + slug: "architecture-rendering-output", + title: "Rendering & Output", + group: "Contributing", + description: "How render sessions turn fragments and structured results into MCP and CLI output.", + }, + "architecture-daemon": { + slug: "architecture-daemon", + title: "Daemon Lifecycle", + group: "Contributing", + description: "Why stateful CLI tools use a per-workspace daemon and how its transport lifecycle works.", + }, + "tool-authoring": { + slug: "tool-authoring", + title: "Tool Authoring", + group: "Contributing", + description: "Add, modify, or remove a tool end to end.", + }, + testing: { + slug: "testing", + title: "Testing", + group: "Contributing", + description: "How XcodeBuildMCP tests tools, fixtures, snapshots, and schema contracts.", + }, } export const SIDEBAR_GROUPS: SidebarGroup[] = [ @@ -198,13 +295,16 @@ export const SIDEBAR_GROUPS: SidebarGroup[] = [ { label: "Usage", icon: "Terminal", - items: [{ slug: "cli" }, { slug: "mcp-mode" }, { slug: "workflows" }], + items: [{ slug: "cli" }, { slug: "mcp-mode" }], }, { label: "Reference", icon: "Book", items: [ { slug: "tools" }, + { slug: "workflows" }, + { slug: "mcp-protocol-support" }, + { slug: "output-formats" }, { slug: "configuration", children: ["session-defaults", "env-vars"], @@ -225,6 +325,26 @@ export const SIDEBAR_GROUPS: SidebarGroup[] = [ { slug: "changelog" }, ], }, + { + label: "Contributing", + icon: "Github", + items: [ + { slug: "contributing" }, + { + slug: "architecture", + children: [ + "architecture-runtime-boundaries", + "architecture-startup-config", + "architecture-manifest-visibility", + "architecture-tool-lifecycle", + "architecture-rendering-output", + "architecture-daemon", + ], + }, + { slug: "tool-authoring" }, + { slug: "testing" }, + ], + }, ] export function isDocSlug(value: string): value is DocSlug { diff --git a/app/docs/_styles/scraps.css b/app/docs/_styles/scraps.css index 7fa9012..afd9b92 100644 --- a/app/docs/_styles/scraps.css +++ b/app/docs/_styles/scraps.css @@ -1079,6 +1079,9 @@ html[data-docs-theme='dark'] .docs-root .codeblock { border-bottom-color: var(--fg-accent); font-weight: 500; } +.docs-root .tabs-content { + padding-top: 18px; +} /* -------- Callouts -------- */ .docs-root .callout { diff --git a/docs/investigations/architecture-doc-accuracy-audit-2026-04-25.md b/docs/investigations/architecture-doc-accuracy-audit-2026-04-25.md new file mode 100644 index 0000000..e49dae5 --- /dev/null +++ b/docs/investigations/architecture-doc-accuracy-audit-2026-04-25.md @@ -0,0 +1,251 @@ +# Investigation: Architecture doc accuracy audit + +## Summary + +`xcodebuildmcp.com/app/docs/_content/architecture.mdx` is overwhelmingly accurate. Six concrete corrections were identified and **all six have been applied** as of 2026-04-25: + +1. CLI entry pattern was too narrow (omitted top-level commands). Fixed. +2. Manifest availability did not actually include daemon mode. Fixed. +3. Tool factory list missed session-aware variants. Fixed. +4. Next-step "tools do not hand-write follow-up instructions" claim was too absolute. Fixed. +5. Daemon idle-shutdown wording was too narrow. Fixed. +6. `liveProgressEnabled` and `streamingFragmentsEnabled` were undocumented booleans on `ToolHandlerContext`. Fields removed from the doc; code-level removal tracked in [getsentry/XcodeBuildMCP#360](https://github.com/getsentry/XcodeBuildMCP/issues/360). + +All other claims (manifest layout, workflow selection, rendering strategies, streaming taxonomy, build pipeline) checked out against the code and required no changes. + +## Symptoms + +The architecture page makes many specific code-level claims (module paths, function names, type shapes, manifest fields, runtime behavior, build steps). Some had drifted as the codebase evolved. + +## Background / Prior Research + +Not needed. This audit is entirely in-workspace verification of doc claims against `XcodeBuildMCP/` source. + +## Investigator Findings + +### Verified accurate (no change needed) + +- Two runtimes share one tool implementation layer. Same `toolModule.handler` is used by MCP and CLI/daemon. (`src/utils/tool-registry.ts:288-301`, `src/runtime/tool-catalog.ts:124-149`) +- `xcodebuildmcp mcp` is the MCP entry. (`src/cli.ts:82-87`, `src/cli/commands/mcp.ts:6-10`) +- Manifest dirs and field schemas: `manifests/tools/`, `manifests/workflows/`, `manifests/resources/` with the exact field sets the doc lists. (`src/core/manifest/load-manifest.ts:64-69,166-169`, `src/core/manifest/schema.ts:80-119,144-168,188-220`) +- `loadManifest()` reads YAML and validates with Zod. (`src/core/manifest/load-manifest.ts:28-48,72-117,169-198`) +- `importToolModule()` lazily imports tool modules from manifest `module` paths. (`src/core/manifest/import-tool-module.ts:26-45`) +- The YAML manifest example matches the actual schema. (`manifests/tools/list_sims.yaml:1-8` against `src/core/manifest/schema.ts:80-119`) +- Three-layer visibility model: workflow selection / predicate filtering / runtime availability. (`src/utils/tool-registry.ts:198-241`, `src/visibility/exposure.ts:147-175`) +- Default workflow is `simulator`. (`manifests/workflows/simulator.yaml:1-7`) +- `session-management` is auto-included. (`manifests/workflows/session-management.yaml:1-10`, `src/visibility/exposure.ts:157-162`) +- `workflow-discovery` is auto-included only when its experimental predicate passes. (`manifests/workflows/workflow-discovery.yaml:1-10`, `src/visibility/predicate-registry.ts:17-19`) +- Tool modules export `schema` and `handler`. Importer enforces named exports. (`src/core/manifest/import-tool-module.ts:43-51`) +- `ToolHandlerContext` shape exactly matches doc: `emit`, `attach`, `liveProgressEnabled`, `streamingFragmentsEnabled`, `nextStepParams?`, `nextSteps?`, `structuredOutput?`. (`src/rendering/types.ts:37-45`) +- All eight named example tools (streaming and non-streaming) exist with matching executor types. (`src/mcp/tools/...`, manifests under `manifests/tools/`) +- Domain fragments and results live where the doc says. (`src/types/domain-fragments.ts:37-182`, `src/types/domain-results.ts:1-31,385-415`) +- Structured output shape `{ result, schema, schemaVersion }` lives in `src/rendering/types.ts:30-35`. (Doc also accurately notes the optional `renderHints?` is part of this type, though it is not called out.) +- Rendering strategies are `text`, `cli-text`, `raw`. (`src/rendering/types.ts:5`, `src/rendering/render.ts:160-171`) Behaviors match: `text` buffers and finalizes (lines 100-109), `cli-text` streams with TTY-aware progress (lines 146-157, plus `src/cli/register-tool-commands.ts:302-306`), `raw` writes transcript fragments to stderr and final non-transcript text to stdout (`src/rendering/render.ts:111-143`). +- `json` and `jsonl` are CLI boundary modes, not render strategies. (`src/cli/output.ts:1`, `src/cli/register-tool-commands.ts:302-360`) +- MCP `--output json` waits for structured output before printing; `jsonl` writes fragments as they arrive without final response. (`src/cli/register-tool-commands.ts:347-358`) +- `postProcessSession()` resolves templates after handler completes, filters success/failure, merges runtime params, normalizes names, attaches steps. (`src/runtime/tool-invoker.ts:25-194,464-469`) +- CLI vs MCP next-step formatting differs at the runtime boundary. (`src/runtime/tool-invoker.ts:193-194,463-468`, `src/utils/tool-registry.ts:306-312`) +- Daemon socket path is `~/.xcodebuildmcp/daemons//daemon.sock`, overridable by `XCODEBUILDMCP_SOCKET`. (`src/daemon/socket-path.ts:6-13,26-38,48-58`) +- Daemon auto-starts on first stateful invocation. (`src/runtime/tool-invoker.ts:389-441`, `src/cli/daemon-control.ts:113-144`) +- Workspace identity derived from project config location or cwd. (`src/daemon/socket-path.ts:14-24`) +- 10-minute default idle timeout. (`src/daemon/idle-shutdown.ts:3-4`) +- Daemon streams fragments back to CLI then returns structured output and next-step data. (`src/daemon/daemon-server.ts:160-197`, `src/daemon/protocol.ts:42-52`) +- Build pipeline: `npm run build` → Wireit `build` target → `build:tsup` → `generate:version` + `tsup`. (`package.json:18-21,101-104`) +- `tsup` produces unbundled ESM in `build/`; rewrites `.ts`→`.js` import specifiers; chmods `cli.js`, `doctor-cli.js`, `daemon.js`. (`tsup.config.ts:8-27,35-66`) +- Manifests and structured-output schemas are package assets read at runtime, not generated loaders. (`package.json:70-76`, `src/core/resource-root.ts:64-77`, `src/core/manifest/load-manifest.ts:64-72`) + +### Inaccuracies (require correction) + +#### Finding 1: CLI entry pattern omits top-level commands + +**Claim:** "CLI: `xcodebuildmcp `" + +**Reality:** The CLI registers the workflow command tree alongside several non-workflow top-level commands. Verified in `src/cli/yargs-app.ts:75-95`: + +```typescript +registerMcpCommand(app); // mcp +registerInitCommand(app, ...); // init +registerSetupCommand(app); // setup +registerUpgradeCommand(app); // upgrade +registerToolsCommand(app); // tools +registerToolCommands(...); // +registerDaemonCommands(...); // daemon +``` + +Top-level commands include `mcp`, `init`, `setup`, `upgrade`, `tools`, and `daemon`. The ` ` pattern is only for tool invocations. + +**Correction:** Reframe the CLI runtime row to acknowledge both shapes. **Status (2026-04-25): applied.** + +#### Finding 2: Manifest availability does not include daemon + +**Claim:** "Whether a manifest entry is exposed to MCP, CLI, or daemon mode." + +**Reality:** Manifest `availability` is a Zod object with only two flags: + +```typescript +// src/core/manifest/schema.ts:10-15 +export const availabilitySchema = z + .object({ + mcp: z.boolean().default(true), + cli: z.boolean().default(true), + }) + .strict(); +``` + +Daemon exposure is special-cased in code (`src/visibility/exposure.ts:18-24,46-52`). Daemon serves CLI-routed stateful tools rather than appearing as a manifest availability flag. + +**Correction:** Drop "daemon" from the manifest availability description; note daemon exposure is derived, not declared. **Status (2026-04-25): applied.** + +#### Finding 3: Tool factory list omits session-aware variants + +**Claim:** "A handler created with `createTypedTool(...)` or `createTypedToolWithContext(...)`." + +**Reality:** Two more factories exist and are used by many tools: + +```typescript +// src/utils/typed-tool-factory.ts:186, :202 +export function createSessionAwareTool(opts: { ... }) +export function createSessionAwareToolWithContext(opts: { ... }) +``` + +Real tool examples using `createSessionAwareTool`: `src/mcp/tools/simulator/build_sim.ts:224-232`, `src/mcp/tools/project-discovery/show_build_settings.ts:141-150`. These are the factories that integrate session-default merging into validation. + +**Correction:** Add the session-aware variants to the export row in the tool contract table. **Status (2026-04-25): applied.** + +#### Finding 4: Next-step framing is too absolute + +**Claim:** "Tools do not hand-write follow-up instructions. Next steps come from two places: 1. Static templates in the tool manifest. 2. Runtime params from `ctx.nextStepParams` or explicit `ctx.nextSteps`." + +**Reality:** The two-bullet list itself is right, but the leading sentence ("Tools do not hand-write follow-up instructions") contradicts bullet 2. Handlers can set explicit `ctx.nextSteps` (`src/rendering/types.ts:42-44`), and `postProcessSession()` honors them (`src/runtime/tool-invoker.ts:148-190`). Manifests are the preferred and most common path; explicit handler steps are the escape hatch for dynamic follow-ups manifest templates cannot represent. + +**Correction:** Rephrase the lede to reflect the preference + escape hatch rather than an absolute prohibition. **Status (2026-04-25): applied.** + +#### Finding 5: Daemon idle shutdown wording is too narrow + +**Claim:** "The daemon shuts down after 10 minutes idle by default, when no stateful sessions are active." + +**Reality:** The idle check requires three conditions, verified in `src/daemon.ts:336-360`: + +```typescript +if (idleForMs < idleTimeoutMs) return; // (1) idle time elapsed +if (inFlightRequests > 0) return; // (2) no in-flight requests +if (hasActiveRuntimeSessions(...)) return; // (3) no active runtime sessions +``` + +`hasActiveRuntimeSessions` is `activeOperationCount > 0` (`src/daemon/idle-shutdown.ts:24-26`). The doc's "no stateful sessions are active" only covers condition (3); it omits the in-flight-requests check. + +**Correction:** Expand the daemon facts row to include in-flight requests. **Status (2026-04-25): applied.** + +#### Finding 6: `liveProgressEnabled` vs `streamingFragmentsEnabled` are not explained + +**Claim:** The doc lists both `liveProgressEnabled: boolean` and `streamingFragmentsEnabled: boolean` on `ToolHandlerContext` without explaining the distinction. The verbatim interface shape is technically correct (both fields exist in `src/rendering/types.ts:40-41`), but a tool author reading the doc reasonably asks why both are there. + +**Reality:** They are not redundant. Verified in `src/utils/tool-execution-compat.ts:7-22`: + +- **`liveProgressEnabled`** controls whether the tool's logic *produces* live progress (extra work to surface stages, periodic updates). +- **`streamingFragmentsEnabled`** controls whether emitted fragments are *forwarded* through the render pipeline or silently dropped at the wire boundary. + +In most boundaries they track each other (both true for CLI text/jsonl, both false for MCP and CLI json/raw). They diverge in the daemon case (`src/daemon/daemon-server.ts:181-182`): `liveProgressEnabled: false` (the daemon does not render its own progress) and `streamingFragmentsEnabled: true` (it forwards fragments back to the CLI client over the daemon protocol, which then renders them). + +**Correction:** Drop both fields from the documented `ToolHandlerContext` shape rather than explaining them. They are slated for removal from the API itself in [getsentry/XcodeBuildMCP#360](https://github.com/getsentry/XcodeBuildMCP/issues/360); documenting dead/about-to-be-removed surface area is worse than omitting it. **Status (2026-04-25): applied** — the interface block in `architecture.mdx` no longer references these fields. + +### Additional gap (worth mentioning, not blocking) + +The architecture doc does not mention the `XCODEBUILDMCP_DAEMON_IDLE_TIMEOUT_MS` env var, which overrides the 10-minute default (`src/daemon/idle-shutdown.ts:3-22`). This is a nicety; including it would make the daemon facts row complete. + +## Investigation Log + +### Phase 1 – Initial assessment +**Hypothesis:** The architecture doc has drifted in places. +**Findings:** Identified ~50 verifiable claims across 9 subsystems (runtimes, manifests, workflow selection, tool contract, streaming, domain types, rendering, next-steps, daemon, build pipeline). +**Conclusion:** Proceed via context_builder + oracle synthesis. + +### Phase 2 – Context builder + oracle audit +**Hypothesis:** Claims may have drifted as code evolved. +**Findings:** context_builder seeded 71 files (58 full, 13 codemap) covering every claim area. Oracle's response_type=question pass produced a claim-by-claim verification with file:line evidence. Five inaccuracies identified, all the rest verified accurate. +**Evidence:** Oracle export at `prompt-exports/oracle-question-2026-04-25-094309-architecture-audit-c-65ef.md`. +**Conclusion:** Five corrections needed; remaining claims are accurate. + +### Phase 3 – Spot verification +**Hypothesis:** Oracle's load-bearing line references should be verified against actual files. +**Findings:** Direct reads confirmed: +- `src/core/manifest/schema.ts:11-15` only declares `mcp` and `cli` in availability. +- `src/utils/typed-tool-factory.ts:186,202` declares both `createSessionAwareTool` and `createSessionAwareToolWithContext`. +- `src/cli/yargs-app.ts:75-95` registers six top-level commands plus the workflow tool tree. +- `src/daemon.ts:337-358` confirms three idle-check conditions: time, in-flight requests, active runtime sessions. +- `src/rendering/types.ts:37-45` confirms `ToolHandlerContext.nextSteps?` exists, supporting handler-set follow-ups. +- `src/daemon/socket-path.ts:53-58` confirms `XCODEBUILDMCP_SOCKET` override. +**Conclusion:** All five oracle-flagged inaccuracies confirmed against source. + +## Root Cause + +Doc drift, not implementation bugs. Five sentences in `architecture.mdx` describe earlier states of the codebase or oversimplify. The remaining content has stayed in sync. + +## Recommendations + +Apply these six textual corrections to `xcodebuildmcp.com/app/docs/_content/architecture.mdx`. Suggested replacement text per finding: + +### 1. CLI runtime row in "The two runtimes" table + +**Current** (entry point cell): +> `xcodebuildmcp ` + +**Replace with:** +> `xcodebuildmcp ` for tool invocations. Top-level commands such as `mcp`, `init`, `setup`, `upgrade`, `tools`, and `daemon` are also registered. + +### 2. Runtime availability row in "Workflow selection" table + +**Current:** +> Whether a manifest entry is exposed to MCP, CLI, or daemon mode. + +**Replace with:** +> Whether a manifest entry is exposed to MCP or CLI. Daemon exposure is derived: the daemon serves CLI-routed stateful tools rather than appearing as a manifest flag. + +### 3. Tool contract `handler` export description + +**Current:** +> A handler created with `createTypedTool(...)` or `createTypedToolWithContext(...)`. + +**Replace with:** +> A handler created with `createTypedTool(...)`, `createTypedToolWithContext(...)`, `createSessionAwareTool(...)`, or `createSessionAwareToolWithContext(...)`. + +### 4. Next-step resolution lede + +**Current:** +> Tools do not hand-write follow-up instructions. Next steps come from two places: 1. Static templates in the tool manifest. 2. Runtime params from `ctx.nextStepParams` or explicit `ctx.nextSteps`. + +**Replace with:** +> Follow-up instructions normally come from static templates in the tool manifest. Handlers should prefer setting `ctx.nextStepParams` to provide runtime values for those templates, but may set explicit `ctx.nextSteps` when a dynamic follow-up cannot be represented by a template. + +### 5. Daemon idle-shutdown row in "Daemon facts" table + +**Current:** +> The daemon shuts down after 10 minutes idle by default, when no stateful sessions are active. + +**Replace with:** +> The daemon shuts down after 10 minutes idle by default (overridable via `XCODEBUILDMCP_DAEMON_IDLE_TIMEOUT_MS`), once no in-flight requests are pending and no active runtime sessions remain. + +### 6. ToolHandlerContext interface block + +**Current** (just the interface, no field-level explanation): +```ts +interface ToolHandlerContext { + emit: (fragment: AnyFragment) => void + attach: (image: ImageAttachment) => void + liveProgressEnabled: boolean + streamingFragmentsEnabled: boolean + nextStepParams?: NextStepParamsMap + nextSteps?: NextStep[] + structuredOutput?: StructuredToolOutput +} +``` + +**Replace with the same interface plus a follow-up explainer:** + +> `liveProgressEnabled` and `streamingFragmentsEnabled` look redundant but they govern different stages. `liveProgressEnabled` tells the tool's logic whether to *produce* progress events at all. `streamingFragmentsEnabled` tells the wire boundary whether emitted fragments should be *forwarded* through the render pipeline or silently dropped. They track each other in most cases (both true for CLI text/jsonl, both false for MCP and CLI json/raw). They diverge for daemon-routed calls: the daemon does not render its own progress (`liveProgressEnabled: false`) but does forward fragments back to the CLI client over the daemon protocol (`streamingFragmentsEnabled: true`). + +## Preventive Measures + +- **Tie key claims to code as the codebase evolves.** Periodic targeted audits like this one catch drift cheaply because each architecture-doc paragraph maps to a small set of source files. +- **Prefer claim shapes that age well.** "Manifest availability declares MCP/CLI exposure; daemon exposure is derived" survives refactors better than "MCP, CLI, or daemon mode" because it states intent rather than enumerating an implementation detail. +- **Note escape hatches even when the happy path dominates.** "Manifests are the source of next steps" is briefer but misleads contributors who hit cases where they need `ctx.nextSteps`. Stating the escape hatch explicitly removes a future bug-report-or-PR cycle. diff --git a/docs/reviews/docs-audit-end-user-vs-contributing.md b/docs/reviews/docs-audit-end-user-vs-contributing.md new file mode 100644 index 0000000..69758a6 --- /dev/null +++ b/docs/reviews/docs-audit-end-user-vs-contributing.md @@ -0,0 +1,293 @@ +# Docs audit: end-user vs Contributing scope + +Audit of the public documentation site at xcodebuildmcp.com, scoped to every non-Contributing page. Goal: flag content that speaks to contributors/tool-authors (manifest schemas, MCP protocol-spec concepts, internal rendering pipeline, internal type exports, predicates, etc.) but currently lives in Overview / Getting Started / Usage / Reference / Guides. + +Source: `/Volumes/Developer/xcodebuildmcp.com/app/docs/_content/`. Sidebar grouping: `/Volumes/Developer/xcodebuildmcp.com/app/docs/_data/routes.ts`. + +## Executive summary + +The non-Contributing surface is overwhelmingly end-user oriented and in good shape. Three pages leak developer-facing content into the user surface and deserve the most attention: + +1. `output-formats.mdx` has an "Environment signal for tool authors" section (`XCODEBUILDMCP_CLI_OUTPUT_FORMAT`) that explicitly addresses tool authors, and a "Response schema reference" block that exposes an internal TypeScript type. +2. `mcp-mode.mdx` ends with a "Tool annotations" section that teaches users the MCP protocol-spec annotation keys (`readOnlyHint`, `destructiveHint`, `openWorldHint`) instead of the user-visible outcome (fewer confirmation prompts). +3. `xcode-ide.mdx` has a one-liner about internal `xcode_tools_*` CLI proxy naming that is confusing as written and should be rewritten. + +Smaller rewrite candidates exist in `privacy.mdx` (one internal code sigil) and `cli.mdx` (the daemon section is a near-miss, currently user-voiced but drifts into implementation-centric phrasing). Nothing warrants a full page move into Contributing. + +No new Contributing pages are needed. Every flagged passage has a natural home in an existing Contributing page (`architecture.mdx` for rendering signals, `tool-authoring.mdx` for authoring concerns) or should simply be removed/rewritten in place. + +## Page-by-page findings + +### Overview group + +#### `introduction.mdx` — GREEN + +Marketing landing page. Feature grid, two-modes block, Why XcodeBuildMCP list, Sentry callout. All outcome-oriented. No action. + +### Getting Started group + +#### `installation.mdx` — GREEN + +Requirements, Homebrew and npm paths, doctor, uninstall. All end-user content. No action. + +#### `setup.mdx` — GREEN + +Wire into editor, run wizard, install skill, first build, next steps, troubleshooting pointer. Agent dialogue example is user-facing. No action. + +#### `clients.mdx` — GREEN + +Per-client config snippets. All drop-in config for end users. No action. + +### Usage group + +#### `cli.mdx` — GREEN (minor rewrite candidate) + +Synopsis, top-level commands, argument forms, session-defaults auto-fill, recipes, per-workspace daemon, daemon commands, troubleshooting, CLI-vs-MCP comparison. All user-facing. + +Minor rewrite candidate, not a move: + +- Lines 122 to 136 "Per-workspace daemon" describes user-visible daemon behavior but the phrasing leans implementation-oriented ("Workspace identity: derived from the location of `.xcodebuildmcp/config.yaml`, or falls back to the current directory. Socket: each daemon runs on a Unix socket at ..."). This is legitimately user-visible (socket path matters when chmod fixes appear in troubleshooting), so **keep** but consider outcome-first framing: lead with "the first stateful tool call auto-starts a per-workspace daemon that shuts down after 10 minutes idle", then put socket path and workspace key as reference bullets below. + +No hard findings. Proposal: **keep as-is**; gentle rewrite is optional. + +#### `mcp-mode.mdx` — YELLOW + +Starting the server, feature-support matrix, session defaults, workflow selection, Xcode IDE bridge pointer, tool annotations. First 4/5ths of the page are well-targeted at users. The final section is the problem. + +Finding 1 (hard): Lines 128 to 136, section "## Tool annotations": + +> Every tool declares read-only, destructive, and open-world hints. MCP clients that respect annotations (Codex, recent Claude Code) use them to reduce unnecessary confirmation prompts. +> +> | Annotation | Meaning | +> |------------|---------| +> | `readOnlyHint: true` | Tool does not modify state. | +> | `destructiveHint: true` | Tool may delete or overwrite. | +> | `openWorldHint: true` | Tool makes network/filesystem requests beyond the project. | + +This is pure MCP-protocol-spec vocabulary. End users don't set these keys; they observe their effect. The raw key names only matter to someone inspecting tool metadata or writing a new tool (which belongs in `tool-authoring.mdx` — note that page already references `annotations` at lines 124 to 141). + +Proposal: **rewrite in user voice**. Replace the table with one sentence of user outcome, e.g. "Every XcodeBuildMCP tool flags itself as read-only, destructive, or network-touching. MCP clients that respect those hints (Codex, recent Claude Code) skip confirmation prompts for read-only tools and prompt on destructive ones." Drop the `readOnlyHint`/`destructiveHint`/`openWorldHint` table. The keys are already documented for tool authors inside `tool-authoring.mdx` at lines 124 to 141. + +#### `workflows.mdx` — GREEN + +Enabling workflows, auto-generated workflow list, custom workflows, experimental discovery, context-savings callout. All user-facing. No action. + +### Reference group + +#### `tools.mdx` — GREEN + +Live-generated tool catalog plus a `build_run_sim` worked example and the MCP-vs-CLI name explainer. All user-facing. No action. + +#### `output-formats.mdx` — RED (two clear developer-facing passages) + +This is the worst offender on the site: it explains CLI output formats for users (good), then slips into an internal TypeScript-type reference block and ends with a section explicitly titled "Environment signal for tool authors". + +Finding 1 (hard): Lines 187 to 199, section "## Response schema reference": + +> The response fields, as exported from the source TypeScript types: +> +> ```ts +> interface StructuredOutputEnvelope { +> schema: string +> schemaVersion: string +> didError: boolean +> error: string | null +> data: TData | null +> } +> ``` + +The table at lines 59 to 65 already describes these five fields in user-friendly prose. Repeating them as an internal TypeScript interface, framed with "as exported from the source TypeScript types", pulls the reader into XcodeBuildMCP's source instead of their own client/CLI consumption model. It duplicates the fields table and then editorializes about internal exports. + +Proposal: **rewrite in user voice**. Drop the TypeScript interface. Keep the two schema-file links (lines 201 to 204). Suggested replacement: + +> The same envelope fields are published as canonical JSON schemas under [`schemas/structured-output/`](https://github.com/getsentry/XcodeBuildMCP/tree/main/schemas/structured-output). Concrete examples: + +(i.e. just remove lines 189 to 199 and keep the rest.) + +Finding 2 (hard): Lines 329 to 332, section "## Environment signal for tool authors": + +> The CLI stores the selected mode in `XCODEBUILDMCP_CLI_OUTPUT_FORMAT` while a tool invocation runs. Treat `--output` as the user-facing interface. The env var is useful when internal code needs to know whether the current CLI invocation selected `text`, `json`, `jsonl`, or `raw`. + +This is explicitly titled for tool authors and says "internal code needs to know". It has no business on the public user-facing output-formats page. + +Proposal: **move to `tool-authoring.mdx`**, under a new "Runtime signals" subsection inside an existing area (e.g. near "Streaming example" at lines 198 to 220 or as a closing bullet in "Common mistakes" at lines 271 to 282). Alternative home: `architecture.mdx` under "Rendering pipeline" (lines 112 to 138), since the env var is effectively a runtime-only boundary signal. Either way, delete from `output-formats.mdx`. + +Finding 3 (soft): Lines 335 to 340, the "## Related" list includes links to `architecture` and `tool-authoring`: + +> - [Architecture](/docs/architecture), contributor-level rendering model +> - [Tool Authoring](/docs/tool-authoring), adding schemas and structured results + +These are fine as cross-links but the descriptor "contributor-level rendering model" explicitly surfaces the contributor split — which is appropriate if the audit logic holds. **Keep**, this is the boundary working correctly. + +#### `configuration.mdx` — GREEN + +Config file location, layering, full schema, quick-reference table. All user-visible options, each tied to a user-visible behavior. No action. + +#### `session-defaults.mdx` — GREEN + +How it works, runtime/config/env paths for setting, reference table, named profiles, opt-out, CLI behavior. All end-user. The page is agent-addressed as well as user-addressed (JSON snippets for `session_set_defaults` calls are literally what agents emit), but that is user-facing output in a client transcript, not an internal-protocol leak. No action. + +Note to reviewer: audit prompt asks whether this page "explains the internal profile store". It does not. The "Named profiles" block is pure user-facing schema. **Open question below** is the opposite: whether the page should expand, not contract. + +#### `env-vars.mdx` — GREEN + +Two tables (general settings, session-default bootstrap) plus an example and the `setup --format mcp-json` pointer. All end-user. No action. + +#### `xcode-ide.mdx` — YELLOW + +Overview, requirements, enable, tools exposed, trust prompts, debug tools, Xcode-scoping env vars. Mostly user-facing. + +Finding 1 (hard): Line 46: + +> The CLI continues to use dynamic `xcode_tools_*` proxy naming. + +Placed as a dangling trailing sentence after the "Tools exposed" table (lines 38 to 44), this is a confusing internal-detail throwaway. Users who skim will read "The two gateway tools `xcode_ide_list_tools` and `xcode_ide_call_tool` are stable" (good) and then bump into a reference to `xcode_tools_*` (what is that, did the previous sentence lie?). + +Proposal: **rewrite in user voice**. Either drop the sentence, or expand it into a short explicit paragraph: "In CLI mode, the proxied Xcode tools are still exposed under their dynamic `xcode_tools_*` names rather than the two MCP gateway tools above." This is user-relevant when a user is running the CLI against the bridge. + +Other sections: + +- Lines 48 to 54 "Trust prompts" and lines 56 to 62 "Debug tools" mention `xcode_tools_bridge_status` / `xcode_tools_bridge_sync` / `xcode_tools_bridge_disconnect`. These are user-visible tools gated by `debug: true` and the troubleshooting flow is user-facing. **Keep**. + +### Guides group + +#### `device-signing.mdx` — GREEN + +One-time Xcode setup, capability table, verify command, Wi-Fi note. All user-facing. No action. + +#### `skills.mdx` — GREEN + +Install, flags, unsupported-client fallback, why-skills bullets. All user-facing. No action. + +#### `demos.mdx` — GREEN + +Three media embeds with user-benefit captions. No action. + +#### `migration-v2.mdx` — GREEN + +Two breaking changes, detailed reference, CLI + skills announcement, project config announcement. All user-facing. The "Why default workflows changed" section (lines 96 to 100) briefly mentions LLM context-window mechanics; that is user-education, not internals. No action. + +#### `privacy.mdx` — GREEN (one micro-rewrite) + +Finding 1 (soft): Line 15: + +> - **Internal operational logs** only when explicitly marked for Sentry (`{ sentry: true }` in server code). Standard console logs are not auto-forwarded. + +The `{ sentry: true }` literal and "in server code" phrasing leaks an internal convention into an otherwise tight user-trust document. End users can't set that flag and don't need to know it is an object-literal key. + +Proposal: **rewrite in user voice**. Example: + +> - **Internal operational logs** only when the server explicitly tags an event for Sentry. Standard console logs are not auto-forwarded. + +Small change, preserves the honesty of the boundary without exposing an implementation detail. **Keep the rest of the page as-is.** + +#### `troubleshooting.mdx` — GREEN + +Triage checklist, doctor, UI-automation, tool timeouts, missing tools, Xcode-agent PATH, device signing, stale simulators, daemon, socket perms, where to file. All end-user. No action. + +#### `changelog.mdx` — GREEN + +Pure `` placeholder. No action. + +## Consolidated proposal + +Ordered by priority. "Find" column is line ranges to aid a follow-up agent. + +| Priority | Page | Find | Action | Destination / replacement | +|----------|------|------|--------|---------------------------| +| P0 | `output-formats.mdx` | 329 to 332 | Move | `tool-authoring.mdx` (new "Runtime signals" subsection near lines 198 to 220) OR `architecture.mdx` under "Rendering pipeline" (lines 112 to 138). Remove from `output-formats.mdx`. | +| P0 | `mcp-mode.mdx` | 128 to 136 | Rewrite in user voice | Replace table with one sentence of user outcome. Drop the `readOnlyHint`/`destructiveHint`/`openWorldHint` keys. They are already documented for authors in `tool-authoring.mdx` lines 124 to 141. | +| P1 | `output-formats.mdx` | 187 to 199 | Remove (or trim) | The five envelope fields are already documented in the table at lines 59 to 65. Drop the TypeScript interface block and the "as exported from the source TypeScript types" sentence. Keep the two schema links at lines 201 to 204. | +| P2 | `xcode-ide.mdx` | 46 | Rewrite in user voice | Either drop the `xcode_tools_*` sentence or expand into a clear paragraph: "In CLI mode, proxied Xcode tools are exposed under dynamic `xcode_tools_*` names rather than the two gateway tools above." | +| P3 | `privacy.mdx` | 15 | Rewrite in user voice | Replace `` `{ sentry: true }` in server code `` with "when the server explicitly tags an event for Sentry." | +| P4 | `cli.mdx` | 122 to 136 | Optional rewrite | Lead with outcome ("first stateful call auto-starts a per-workspace daemon; it shuts down after 10 minutes idle"), demote socket path / workspace identity to reference bullets below. No move. | + +No page-level moves into Contributing are warranted. Every finding can be resolved by trimming a paragraph, rewriting a sentence, or moving a single four-line passage (the `XCODEBUILDMCP_CLI_OUTPUT_FORMAT` one). + +## Open questions for reviewer + +1. **Tool annotations visibility.** `mcp-mode.mdx` currently teaches the raw annotation keys. End users can observe the effect (no confirmation prompt), but power users occasionally want to audit which tools claim `destructiveHint` before handing the keys to their agent. Options: + - (A) Drop the keys entirely (current proposal). + - (B) Keep the keys but reframe as "what XcodeBuildMCP advertises to your client" rather than "annotations declared per tool". + - (C) Move the table to `tools.mdx` as a filter in the live `` (this is a real user workflow but would be a feature, not a doc edit). + Recommend (A) for now; revisit if (C) is ever shipped. + +2. **`XCODEBUILDMCP_CLI_OUTPUT_FORMAT` destination.** The env-var note is legitimately useful for tool authors but it's also a runtime-layer concern. Move to `tool-authoring.mdx` (closer to the audience) or `architecture.mdx` (closer to the mechanism)? My default is `tool-authoring.mdx`, appended near the bottom of "Streaming example" or in a new one-line "Runtime env signals" bullet, because that is where someone first encounters CLI output format in their own code. Confirm before moving. + +3. **Session defaults internal state.** Audit prompt specifically asks whether `session-defaults.mdx` "explains the internal profile store". It does not; the whole page is user-observable behavior and YAML schema. No change. Flagging in case the prompt intended a different target. + +4. **Daemon phrasing in `cli.mdx`.** The "Per-workspace daemon" section (lines 122 to 136) is not quite implementation-voiced but is close. Is the current outcome-plus-reference mix the right level for users, or would a lede-first rewrite be clearer? Low-impact, low-risk — deferrable. + +5. **Contributor cross-links on user pages.** `output-formats.mdx` Related section labels the Architecture link "contributor-level rendering model" (line 339). Keep as-is (it accurately tells the user they are crossing a boundary), or simplify to just the title? I recommend **keep**, because the label is the only signal to a skim-reader that the linked page is not for them. + +## Execution decisions (locked in by reviewer) + +The audit's findings are being actioned. Decisions recorded here so sub-agents working on specific items can see the full picture. + +### Reframing: tool annotations are public API, not internal + +`readOnlyHint`, `destructiveHint`, `openWorldHint` are part of the public MCP response XcodeBuildMCP advertises. They **stay** in end-user-visible docs. The original P0 recommendation to drop them is reversed. Full treatment moves to a new **`mcp-protocol-support.mdx`** page under the Reference group; `mcp-mode.mdx` keeps a short outcome-focused section that links to the new page. + +Per-tool annotation **pills** in `` (badge beside each tool in the catalog) are a good future feature but **out of scope** for this pass — requires a component change in `_components/tool-explorer.tsx` and a data change in the generated manifest JSON. + +### Open questions — resolved + +- **Q1 (tool annotation visibility)** — keep as public API. New page. +- **Q2 (`XCODEBUILDMCP_CLI_OUTPUT_FORMAT` destination)** — **Option C: delete entirely**. It is an internal mechanism; no reason for end users or tool authors to know about it moving forward. Not moved to `tool-authoring.mdx` or `architecture.mdx` — removed. +- **Q3 (session-defaults internal state)** — confirmed no leak. No action. +- **Q4 (`cli.mdx` daemon lede)** — **rewrite**. Do not assume users know what a daemon is. Open with the user-facing concept: "some tools rely on long-running background processes". Then introduce that XcodeBuildMCP calls this a daemon, cover lifecycle, workspace scoping (tied to `.xcodebuildmcp/config.yaml`), and available management commands. `.xcodebuildmcp/config.yaml` is part of the public feature — treat it as such. +- **Q5 (cross-link label on `output-formats.mdx`)** — **keep as-is**. The qualifier "contributor-level rendering model" is a useful boundary signal. + +### Sidebar placement + +New page slug: `mcp-protocol-support`. Sidebar group: **Reference**. Suggested position: after `tools` and before `output-formats` (so the user flow is "what tools exist → which MCP features do they flow through → what does the output look like"). Update `/Volumes/Developer/xcodebuildmcp.com/app/docs/_data/routes.ts`: +- Add `"mcp-protocol-support"` to `DocSlug` union +- Add `"mcp-protocol-support"` to `PAGES_ORDER` in the chosen position +- Add a `PAGE_META` entry (title "MCP Protocol Support", group "Reference", description calling out that the page declares which MCP spec features XcodeBuildMCP implements) +- Add `{ slug: "mcp-protocol-support" }` to the Reference `SidebarGroup.items` + +### Execution plan (three parallel work items) + +- [x] **Item 1 — prose trims in existing pages** (done) + - `output-formats.mdx`: remove lines 329–332 ("Environment signal for tool authors" section) + - `output-formats.mdx`: remove lines 187–199 (TypeScript `StructuredOutputEnvelope` interface block and the "as exported from the source TypeScript types" sentence). Keep the two schema links immediately below. + - `xcode-ide.mdx`: rewrite line 46 (`xcode_tools_*` dangling sentence) into a clear user-facing paragraph — recommended: "In CLI mode, proxied Xcode tools are exposed under dynamic `xcode_tools_*` names rather than the two gateway tools above." + - `privacy.mdx`: rewrite line 15 — replace `` the `{ sentry: true }` in server code `` sigil with "when the server explicitly tags an event for Sentry." + - No other changes to these files. + +- [x] **Item 2 — `cli.mdx` daemon section rewrite (lines 122–136)** (done) + - Open with the user-facing concept before naming the daemon. Suggested lede: "Some XcodeBuildMCP tools (log capture, debugging, long-running builds, test runs) need a background process to keep state across commands. The first time you use one of these, XcodeBuildMCP auto-starts a small scoped background process — a daemon — that survives between CLI invocations." + - Then explain lifecycle (shuts down after 10 min idle), workspace scoping (keyed off `.xcodebuildmcp/config.yaml`, or the current directory when absent), and the user-visible management commands (`daemon start`, `daemon status`, `daemon stop`, plus whatever else exists — the agent should verify by reading the current CLI surface). + - Socket path stays but becomes reference detail under a "Reference" heading, not the opening sentence. + - Result: a user who has never heard the word "daemon" can understand why this exists and what to do about it, without reading implementation-first phrasing. + +- [x] **Item 3 — new `mcp-protocol-support.mdx` page + `mcp-mode.mdx` trim + `routes.ts` registration** (done) + - Create `/Volumes/Developer/xcodebuildmcp.com/app/docs/_content/mcp-protocol-support.mdx`. + - Investigate the actual XcodeBuildMCP MCP server surface before writing. Do **not** fabricate feature claims. Starting points: + - `/Volumes/Developer/XcodeBuildMCP/src/server/` — server entry + capability declarations + - `/Volumes/Developer/XcodeBuildMCP/src/mcp/` — MCP-facing adapters, tools, resources + - `/Volumes/Developer/XcodeBuildMCP/src/core/manifest/` — manifest layer that annotations flow through + - `/Volumes/Developer/XcodeBuildMCP/schemas/structured-output/` — structured content envelope schemas + - Page content, minimum coverage (expand if more is actually implemented): + - Short intro: the MCP protocol has many optional features; this page declares which ones XcodeBuildMCP implements (so MCP-literate readers can evaluate coverage). + - Feature table or sections for: tools (list + call), tool annotations (full `readOnlyHint`/`destructiveHint`/`openWorldHint`/`idempotentHint`/`openWorldHint` as actually declared, with user-outcome framing), structured content (the envelope + schemas we publish), resources (if any), notifications (tool-list changes, progress if emitted, logs if forwarded), prompts (honest "not implemented" if that's the state), server capabilities advertised on initialize. + - Cross-links: to `tools` (catalog), `output-formats` (envelope details), `mcp-mode` (how to run the server). + - Keep tone direct, no emoji, technical prose. + - Trim `mcp-mode.mdx` tool annotations section (lines 128–136) to a short outcome-focused paragraph plus a link to the new page. Suggested content: one sentence covering "every tool declares read-only / destructive / open-world hints so compliant clients can reduce confirmation prompts", then "See [MCP Protocol Support](/docs/mcp-protocol-support) for the full list of MCP features XcodeBuildMCP implements." Drop the raw annotation-keys table — the full table lives on the new page. + - Update `routes.ts` as described under "Sidebar placement" above. + - Check the file `/Volumes/Developer/xcodebuildmcp.com/app/docs/_content/index.ts` for any registration the new slug needs. + +### Cross-cutting notes for all three items + +- Do not touch legacy `/Volumes/Developer/XcodeBuildMCP/docs/*.md` files. They are being replaced by the docs site. +- Audience framing is captured in `/Volumes/Developer/XcodeBuildMCP/CLAUDE.md` and `AGENTS.md` under `## Docs > ### Audience`. Read it before writing new prose. +- All three items run in parallel in separate agents. File ownership does not overlap. + +## Scope checks honored + +- Only pages under the non-Contributing groups were audited (`introduction`, `installation`, `setup`, `clients`, `cli`, `mcp-mode`, `workflows`, `tools`, `output-formats`, `configuration`, `session-defaults`, `env-vars`, `xcode-ide`, `device-signing`, `skills`, `demos`, `migration-v2`, `privacy`, `troubleshooting`, `changelog`). Each page was read in full. +- Contributing pages (`contributing.mdx`, `architecture.mdx`, `tool-authoring.mdx`, `testing.mdx`) were read only to confirm they are the right landing zones for flagged content. Their own content is out of scope. +- No sidebar restructuring is proposed beyond relocations into existing Contributing pages. +- No new pages are proposed; if one is needed in future, see open question 2. +- Legacy `/Volumes/Developer/XcodeBuildMCP/docs/` markdown files were not examined. +- No `.mdx` files were modified. diff --git a/mdx-components.tsx b/mdx-components.tsx index 183e382..725ab0d 100644 --- a/mdx-components.tsx +++ b/mdx-components.tsx @@ -3,6 +3,7 @@ import type { ReactElement } from "react" import { Callout } from "@/app/docs/_components/callout" import { CodeBlock } from "@/app/docs/_components/code-block" import { Tabs } from "@/app/docs/_components/tabs" +import { MermaidDiagram } from "@/app/docs/_components/mermaid-diagram" import { ToolExplorer } from "@/app/docs/_components/tool-explorer" import { LiveToolCount, @@ -34,9 +35,15 @@ export function useMDXComponents(components: MDXComponents): MDXComponents { const lang = langMatch ? langMatch[1] : undefined const filename = child.props["data-filename"] const raw = typeof child.props.children === "string" ? child.props.children : "" + const content = raw.replace(/\n$/, "") + + if (lang?.toLowerCase() === "mermaid") { + return + } + return ( - - {raw.replace(/\n$/, "")} + + {content} ) }, diff --git a/package.json b/package.json index d90bfcb..0ec4143 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "input-otp": "1.4.1", "js-yaml": "^4.1.1", "lucide-react": "^0.454.0", + "mermaid": "^11.14.0", "next": "15.5.10", "next-themes": "^0.4.4", "react": "^19", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9480d6a..ae31ea9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -137,6 +137,9 @@ importers: lucide-react: specifier: ^0.454.0 version: 0.454.0(react@19.0.0) + mermaid: + specifier: ^11.14.0 + version: 11.14.0 next: specifier: 15.5.10 version: 15.5.10(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -220,10 +223,31 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + '@antfu/install-pkg@1.1.0': + resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} + '@babel/runtime@7.27.6': resolution: {integrity: sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==} engines: {node: '>=6.9.0'} + '@braintree/sanitize-url@7.1.2': + resolution: {integrity: sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==} + + '@chevrotain/cst-dts-gen@12.0.0': + resolution: {integrity: sha512-fSL4KXjTl7cDgf0B5Rip9Q05BOrYvkJV/RrBTE/bKDN096E4hN/ySpcBK5B24T76dlQ2i32Zc3PAE27jFnFrKg==} + + '@chevrotain/gast@12.0.0': + resolution: {integrity: sha512-1ne/m3XsIT8aEdrvT33so0GUC+wkctpUPK6zU9IlOyJLUbR0rg4G7ZiApiJbggpgPir9ERy3FRjT6T7lpgetnQ==} + + '@chevrotain/regexp-to-ast@12.0.0': + resolution: {integrity: sha512-p+EW9MaJwgaHguhoqwOtx/FwuGr+DnNn857sXWOi/mClXIkPGl3rn7hGNWvo31HA3vyeQxjqe+H36yZJwYU8cA==} + + '@chevrotain/types@12.0.0': + resolution: {integrity: sha512-S+04vjFQKeuYw0/eW3U52LkAHQsB1ASxsPGsLPUyQgrZ2iNNibQrsidruDzjEX2JYfespXMG0eZmXlhA6z7nWA==} + + '@chevrotain/utils@12.0.0': + resolution: {integrity: sha512-lB59uJoaGIfOOL9knQqQRfhl9g7x8/wqFkp13zTdkRu1huG9kg6IJs1O8hqj9rs6h7orGxHJUKb+mX3rPbWGhA==} + '@emnapi/runtime@1.8.1': resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} @@ -247,6 +271,12 @@ packages: peerDependencies: react-hook-form: ^7.0.0 + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@iconify/utils@3.1.0': + resolution: {integrity: sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==} + '@img/colour@1.0.0': resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} engines: {node: '>=18'} @@ -418,6 +448,9 @@ packages: '@types/react': '>=16' react: '>=16' + '@mermaid-js/parser@1.1.0': + resolution: {integrity: sha512-gxK9ZX2+Fex5zu8LhRQoMeMPEHbc73UKZ0FQ54YrQtUxE1VVhMwzeNtKRPAu5aXks4FasbMe4xB4bWrmq6Jlxw==} + '@mixmark-io/domino@2.2.0': resolution: {integrity: sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==} @@ -1161,30 +1194,96 @@ packages: '@types/d3-array@3.2.1': resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} + '@types/d3-axis@3.0.6': + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + + '@types/d3-brush@3.0.6': + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + + '@types/d3-chord@3.0.6': + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + '@types/d3-color@3.1.3': resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + '@types/d3-contour@3.0.6': + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + + '@types/d3-delaunay@6.0.4': + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + + '@types/d3-dispatch@3.0.7': + resolution: {integrity: sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + '@types/d3-ease@3.0.2': resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + '@types/d3-interpolate@3.0.4': resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} '@types/d3-path@3.1.1': resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + '@types/d3-polygon@3.0.2': + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.3': + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + + '@types/d3-scale-chromatic@3.1.0': + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + '@types/d3-scale@4.0.9': resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + '@types/d3-shape@3.1.7': resolution: {integrity: sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==} + '@types/d3-time-format@4.0.3': + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + '@types/d3-time@3.0.4': resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} '@types/d3-timer@3.0.2': resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + '@types/debug@4.1.13': resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} @@ -1194,6 +1293,9 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/geojson@7946.0.16': + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -1218,6 +1320,9 @@ packages: '@types/react@19.0.0': resolution: {integrity: sha512-MY3oPudxvMYyesqs/kW1Bh8y9VqSmf+tzqw3ae8a9DZW68pUe3zAdHeI1jc6iAysuRdACnVknHP8AhwD4/dxtg==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/turndown@5.0.6': resolution: {integrity: sha512-ru00MoyeeouE5BX4gRL+6m/BsDfbRayOskWqUvh7CLGW+UXxHQItqALa38kKnOiZPqJrtzJUgAC2+F0rL1S4Pg==} @@ -1230,6 +1335,9 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + '@upsetjs/venn.js@2.0.0': + resolution: {integrity: sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1331,6 +1439,15 @@ packages: character-reference-invalid@2.0.1: resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + chevrotain-allstar@0.4.1: + resolution: {integrity: sha512-PvVJm3oGqrveUVW2Vt/eZGeiAIsJszYweUcYwcskg9e+IubNYKKD+rHHem7A6XVO22eDAL+inxNIGAzZ/VIWlA==} + peerDependencies: + chevrotain: ^12.0.0 + + chevrotain@12.0.0: + resolution: {integrity: sha512-csJvb+6kEiQaqo1woTdSAuOWdN0WTLIydkKrBnS+V5gZz0oqBrp4kQ35519QgK6TpBThiG3V1vNSHlIkv4AglQ==} + engines: {node: '>=22.0.0'} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -1368,6 +1485,23 @@ packages: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + cose-base@1.0.3: + resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} + + cose-base@2.2.0: + resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -1380,34 +1514,129 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + cytoscape-cose-bilkent@4.1.0: + resolution: {integrity: sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape-fcose@2.2.0: + resolution: {integrity: sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape@3.33.2: + resolution: {integrity: sha512-sj4HXd3DokGhzZAdjDejGvTPLqlt84vNFN8m7bGsOzDY5DyVcxIb2ejIXat2Iy7HxWhdT/N1oKyheJ5YdpsGuw==} + engines: {node: '>=0.10'} + + d3-array@2.12.1: + resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} + d3-array@3.2.4: resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} engines: {node: '>=12'} + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + d3-color@3.1.0: resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} engines: {node: '>=12'} + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + d3-ease@3.0.1: resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} engines: {node: '>=12'} + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + d3-format@3.1.0: resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} engines: {node: '>=12'} + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + d3-interpolate@3.0.1: resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} engines: {node: '>=12'} + d3-path@1.0.9: + resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} + d3-path@3.1.0: resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} engines: {node: '>=12'} + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-sankey@0.12.3: + resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + d3-scale@4.0.2: resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} engines: {node: '>=12'} + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-shape@1.3.7: + resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} + d3-shape@3.2.0: resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} engines: {node: '>=12'} @@ -1424,9 +1653,29 @@ packages: resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} engines: {node: '>=12'} + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + + dagre-d3-es@7.0.14: + resolution: {integrity: sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==} + date-fns@4.1.0: resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + dayjs@1.11.20: + resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -1442,6 +1691,9 @@ packages: decode-named-character-reference@1.3.0: resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + delaunator@5.1.0: + resolution: {integrity: sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -1465,6 +1717,9 @@ packages: dom-helpers@5.2.1: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + dompurify@3.4.1: + resolution: {integrity: sha512-JahakDAIg1gyOm7dlgWSDjV4n7Ip2PKR55NIT6jrMfIgLFgWo81vdr1/QGqWtFNRqXP9UV71oVePtjqS2ebnPw==} + eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -1581,6 +1836,9 @@ packages: deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true + hachure-fill@0.5.2: + resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -1606,6 +1864,10 @@ packages: html-url-attributes@3.0.1: resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + inline-style-parser@0.2.7: resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} @@ -1615,6 +1877,9 @@ packages: react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + internmap@1.0.1: + resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} + internmap@2.0.3: resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} engines: {node: '>=12'} @@ -1676,6 +1941,23 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true + katex@0.16.45: + resolution: {integrity: sha512-pQpZbdBu7wCTmQUh7ufPmLr0pFoObnGUoL/yhtwJDgmmQpbkg/0HSVti25Fu4rmd1oCR6NGWe9vqTWuWv3GcNA==} + hasBin: true + + khroma@2.1.0: + resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} + + langium@4.2.2: + resolution: {integrity: sha512-JUshTRAfHI4/MF9dH2WupvjSXyn8JBuUEWazB8ZVJUtXutT0doDlAv1XKbZ1Pb5sMexa8FF4CFBc0iiul7gbUQ==} + engines: {node: '>=20.10.0', npm: '>=10.2.3'} + + layout-base@1.0.2: + resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} + + layout-base@2.0.1: + resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==} + lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -1683,6 +1965,9 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + lodash-es@4.18.1: + resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} + lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -1708,6 +1993,11 @@ packages: markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + marked@16.4.2: + resolution: {integrity: sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==} + engines: {node: '>= 20'} + hasBin: true + mdast-util-find-and-replace@3.0.2: resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} @@ -1760,6 +2050,9 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + mermaid@11.14.0: + resolution: {integrity: sha512-GSGloRsBs+JINmmhl0JDwjpuezCsHB4WGI4NASHxL3fHo3o/BRXTxhDLKnln8/Q0lRFRyDdEjmk1/d5Sn1Xz8g==} + micromark-core-commonmark@2.0.3: resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} @@ -1877,6 +2170,9 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -1937,9 +2233,15 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + package-manager-detector@1.6.0: + resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} + parse-entities@4.0.2: resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + path-data-parser@0.1.0: + resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -1951,6 +2253,9 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1966,6 +2271,15 @@ packages: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + points-on-curve@0.2.0: + resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} + + points-on-path@0.2.1: + resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} + postcss-import@15.1.0: resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} engines: {node: '>=14.0.0'} @@ -2165,9 +2479,21 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + robust-predicates@3.0.3: + resolution: {integrity: sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==} + + roughjs@4.6.6: + resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + scheduler@0.25.0: resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} @@ -2247,6 +2573,9 @@ packages: babel-plugin-macros: optional: true + stylis@4.4.0: + resolution: {integrity: sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==} + sucrase@3.35.0: resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} engines: {node: '>=16 || 14 >=14.17'} @@ -2279,6 +2608,10 @@ packages: tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + tinyexec@1.1.1: + resolution: {integrity: sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==} + engines: {node: '>=18'} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -2289,6 +2622,10 @@ packages: trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + ts-dedent@2.2.0: + resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} + engines: {node: '>=6.10'} + ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} @@ -2307,6 +2644,9 @@ packages: engines: {node: '>=12.20'} hasBin: true + ufo@1.6.3: + resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} + undici-types@6.11.1: resolution: {integrity: sha512-mIDEX2ek50x0OlRgxryxsenE5XaQD4on5U2inY7RApK3SOJpofyw7uW2AyfMKkhAxXIceo2DeWGVGwyvng1GNQ==} @@ -2365,6 +2705,10 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + uuid@11.1.0: + resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} + hasBin: true + vaul@0.9.6: resolution: {integrity: sha512-Ykk5FSu4ibeD6qfKQH/CkBRdSGWkxi35KMNei0z59kTPAlgzpE/Qf1gTx2sxih8Q05KBO/aFhcF/UkBW5iI1Ww==} peerDependencies: @@ -2380,6 +2724,26 @@ packages: victory-vendor@36.9.2: resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==} + vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} + + vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + + vscode-languageserver-textdocument@1.0.12: + resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} + + vscode-languageserver-types@3.17.5: + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + + vscode-languageserver@9.0.1: + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} + hasBin: true + + vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -2408,8 +2772,30 @@ snapshots: '@alloc/quick-lru@5.2.0': {} + '@antfu/install-pkg@1.1.0': + dependencies: + package-manager-detector: 1.6.0 + tinyexec: 1.1.1 + '@babel/runtime@7.27.6': {} + '@braintree/sanitize-url@7.1.2': {} + + '@chevrotain/cst-dts-gen@12.0.0': + dependencies: + '@chevrotain/gast': 12.0.0 + '@chevrotain/types': 12.0.0 + + '@chevrotain/gast@12.0.0': + dependencies: + '@chevrotain/types': 12.0.0 + + '@chevrotain/regexp-to-ast@12.0.0': {} + + '@chevrotain/types@12.0.0': {} + + '@chevrotain/utils@12.0.0': {} + '@emnapi/runtime@1.8.1': dependencies: tslib: 2.8.1 @@ -2436,6 +2822,14 @@ snapshots: dependencies: react-hook-form: 7.54.1(react@19.0.0) + '@iconify/types@2.0.0': {} + + '@iconify/utils@3.1.0': + dependencies: + '@antfu/install-pkg': 1.1.0 + '@iconify/types': 2.0.0 + mlly: 1.8.2 + '@img/colour@1.0.0': optional: true @@ -2599,6 +2993,10 @@ snapshots: '@types/react': 19.0.0 react: 19.0.0 + '@mermaid-js/parser@1.1.0': + dependencies: + langium: 4.2.2 + '@mixmark-io/domino@2.2.0': {} '@next/env@15.5.10': {} @@ -3347,28 +3745,121 @@ snapshots: '@types/d3-array@3.2.1': {} + '@types/d3-axis@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-brush@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-chord@3.0.6': {} + '@types/d3-color@3.1.3': {} + '@types/d3-contour@3.0.6': + dependencies: + '@types/d3-array': 3.2.1 + '@types/geojson': 7946.0.16 + + '@types/d3-delaunay@6.0.4': {} + + '@types/d3-dispatch@3.0.7': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-dsv@3.0.7': {} + '@types/d3-ease@3.0.2': {} + '@types/d3-fetch@3.0.7': + dependencies: + '@types/d3-dsv': 3.0.7 + + '@types/d3-force@3.0.10': {} + + '@types/d3-format@3.0.4': {} + + '@types/d3-geo@3.1.0': + dependencies: + '@types/geojson': 7946.0.16 + + '@types/d3-hierarchy@3.1.7': {} + '@types/d3-interpolate@3.0.4': dependencies: '@types/d3-color': 3.1.3 '@types/d3-path@3.1.1': {} + '@types/d3-polygon@3.0.2': {} + + '@types/d3-quadtree@3.0.6': {} + + '@types/d3-random@3.0.3': {} + + '@types/d3-scale-chromatic@3.1.0': {} + '@types/d3-scale@4.0.9': dependencies: '@types/d3-time': 3.0.4 + '@types/d3-selection@3.0.11': {} + '@types/d3-shape@3.1.7': dependencies: '@types/d3-path': 3.1.1 + '@types/d3-time-format@4.0.3': {} + '@types/d3-time@3.0.4': {} '@types/d3-timer@3.0.2': {} + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/d3@7.4.3': + dependencies: + '@types/d3-array': 3.2.1 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.7 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.1 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.9 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.7 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + '@types/debug@4.1.13': dependencies: '@types/ms': 2.1.0 @@ -3379,6 +3870,8 @@ snapshots: '@types/estree@1.0.8': {} + '@types/geojson@7946.0.16': {} + '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 @@ -3405,6 +3898,9 @@ snapshots: dependencies: csstype: 3.1.3 + '@types/trusted-types@2.0.7': + optional: true + '@types/turndown@5.0.6': {} '@types/unist@2.0.11': {} @@ -3413,6 +3909,11 @@ snapshots: '@ungap/structured-clone@1.3.0': {} + '@upsetjs/venn.js@2.0.0': + optionalDependencies: + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + acorn-jsx@5.3.2(acorn@8.16.0): dependencies: acorn: 8.16.0 @@ -3493,6 +3994,19 @@ snapshots: character-reference-invalid@2.0.1: {} + chevrotain-allstar@0.4.1(chevrotain@12.0.0): + dependencies: + chevrotain: 12.0.0 + lodash-es: 4.18.1 + + chevrotain@12.0.0: + dependencies: + '@chevrotain/cst-dts-gen': 12.0.0 + '@chevrotain/gast': 12.0.0 + '@chevrotain/regexp-to-ast': 12.0.0 + '@chevrotain/types': 12.0.0 + '@chevrotain/utils': 12.0.0 + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -3537,6 +4051,20 @@ snapshots: commander@4.1.1: {} + commander@7.2.0: {} + + commander@8.3.0: {} + + confbox@0.1.8: {} + + cose-base@1.0.3: + dependencies: + layout-base: 1.0.2 + + cose-base@2.2.0: + dependencies: + layout-base: 2.0.1 + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -3547,22 +4075,107 @@ snapshots: csstype@3.1.3: {} + cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.2): + dependencies: + cose-base: 1.0.3 + cytoscape: 3.33.2 + + cytoscape-fcose@2.2.0(cytoscape@3.33.2): + dependencies: + cose-base: 2.2.0 + cytoscape: 3.33.2 + + cytoscape@3.33.2: {} + + d3-array@2.12.1: + dependencies: + internmap: 1.0.1 + d3-array@3.2.4: dependencies: internmap: 2.0.3 + d3-axis@3.0.0: {} + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + d3-color@3.1.0: {} + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.1.0 + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + d3-ease@3.0.1: {} + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + d3-format@3.1.0: {} + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + + d3-hierarchy@3.1.2: {} + d3-interpolate@3.0.1: dependencies: d3-color: 3.1.0 + d3-path@1.0.9: {} + d3-path@3.1.0: {} + d3-polygon@3.0.1: {} + + d3-quadtree@3.0.1: {} + + d3-random@3.0.1: {} + + d3-sankey@0.12.3: + dependencies: + d3-array: 2.12.1 + d3-shape: 1.3.7 + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + d3-scale@4.0.2: dependencies: d3-array: 3.2.4 @@ -3571,6 +4184,12 @@ snapshots: d3-time: 3.1.0 d3-time-format: 4.1.0 + d3-selection@3.0.0: {} + + d3-shape@1.3.7: + dependencies: + d3-path: 1.0.9 + d3-shape@3.2.0: dependencies: d3-path: 3.1.0 @@ -3585,8 +4204,65 @@ snapshots: d3-timer@3.0.1: {} + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.0 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + + dagre-d3-es@7.0.14: + dependencies: + d3: 7.9.0 + lodash-es: 4.18.1 + date-fns@4.1.0: {} + dayjs@1.11.20: {} + debug@4.4.3: dependencies: ms: 2.1.3 @@ -3597,6 +4273,10 @@ snapshots: dependencies: character-entities: 2.0.2 + delaunator@5.1.0: + dependencies: + robust-predicates: 3.0.3 + dequal@2.0.3: {} detect-libc@2.1.2: @@ -3617,6 +4297,10 @@ snapshots: '@babel/runtime': 7.27.6 csstype: 3.1.3 + dompurify@3.4.1: + optionalDependencies: + '@types/trusted-types': 2.0.7 + eastasianwidth@0.2.0: {} electron-to-chromium@1.5.178: {} @@ -3743,6 +4427,8 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 1.11.1 + hachure-fill@0.5.2: {} + hasown@2.0.2: dependencies: function-bind: 1.1.2 @@ -3806,6 +4492,10 @@ snapshots: html-url-attributes@3.0.1: {} + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + inline-style-parser@0.2.7: {} input-otp@1.4.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0): @@ -3813,6 +4503,8 @@ snapshots: react: 19.0.0 react-dom: 19.0.0(react@19.0.0) + internmap@1.0.1: {} + internmap@2.0.3: {} is-alphabetical@2.0.1: {} @@ -3862,10 +4554,31 @@ snapshots: dependencies: argparse: 2.0.1 + katex@0.16.45: + dependencies: + commander: 8.3.0 + + khroma@2.1.0: {} + + langium@4.2.2: + dependencies: + '@chevrotain/regexp-to-ast': 12.0.0 + chevrotain: 12.0.0 + chevrotain-allstar: 0.4.1(chevrotain@12.0.0) + vscode-languageserver: 9.0.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + + layout-base@1.0.2: {} + + layout-base@2.0.1: {} + lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} + lodash-es@4.18.1: {} + lodash@4.17.21: {} longest-streak@3.1.0: {} @@ -3884,6 +4597,8 @@ snapshots: markdown-table@3.0.4: {} + marked@16.4.2: {} + mdast-util-find-and-replace@3.0.2: dependencies: '@types/mdast': 4.0.4 @@ -4049,6 +4764,30 @@ snapshots: merge2@1.4.1: {} + mermaid@11.14.0: + dependencies: + '@braintree/sanitize-url': 7.1.2 + '@iconify/utils': 3.1.0 + '@mermaid-js/parser': 1.1.0 + '@types/d3': 7.4.3 + '@upsetjs/venn.js': 2.0.0 + cytoscape: 3.33.2 + cytoscape-cose-bilkent: 4.1.0(cytoscape@3.33.2) + cytoscape-fcose: 2.2.0(cytoscape@3.33.2) + d3: 7.9.0 + d3-sankey: 0.12.3 + dagre-d3-es: 7.0.14 + dayjs: 1.11.20 + dompurify: 3.4.1 + katex: 0.16.45 + khroma: 2.1.0 + lodash-es: 4.18.1 + marked: 16.4.2 + roughjs: 4.6.6 + stylis: 4.4.0 + ts-dedent: 2.2.0 + uuid: 11.1.0 + micromark-core-commonmark@2.0.3: dependencies: decode-named-character-reference: 1.3.0 @@ -4324,6 +5063,13 @@ snapshots: minipass@7.1.2: {} + mlly@1.8.2: + dependencies: + acorn: 8.16.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.3 + ms@2.1.3: {} mz@2.7.0: @@ -4374,6 +5120,8 @@ snapshots: package-json-from-dist@1.0.1: {} + package-manager-detector@1.6.0: {} + parse-entities@4.0.2: dependencies: '@types/unist': 2.0.11 @@ -4384,6 +5132,8 @@ snapshots: is-decimal: 2.0.1 is-hexadecimal: 2.0.1 + path-data-parser@0.1.0: {} + path-key@3.1.1: {} path-parse@1.0.7: {} @@ -4393,6 +5143,8 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 + pathe@2.0.3: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -4401,6 +5153,19 @@ snapshots: pirates@4.0.7: {} + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.2 + pathe: 2.0.3 + + points-on-curve@0.2.0: {} + + points-on-path@0.2.1: + dependencies: + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + postcss-import@15.1.0(postcss@8.5.0): dependencies: postcss: 8.5.0 @@ -4669,10 +5434,23 @@ snapshots: reusify@1.1.0: {} + robust-predicates@3.0.3: {} + + roughjs@4.6.6: + dependencies: + hachure-fill: 0.5.2 + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + points-on-path: 0.2.1 + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 + rw@1.3.3: {} + + safer-buffer@2.1.2: {} + scheduler@0.25.0: {} semver@7.7.4: @@ -4767,6 +5545,8 @@ snapshots: client-only: 0.0.1 react: 19.0.0 + stylis@4.4.0: {} + sucrase@3.35.0: dependencies: '@jridgewell/gen-mapping': 0.3.12 @@ -4822,6 +5602,8 @@ snapshots: tiny-invariant@1.3.3: {} + tinyexec@1.1.1: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -4830,6 +5612,8 @@ snapshots: trough@2.2.0: {} + ts-dedent@2.2.0: {} + ts-interface-checker@0.1.13: {} tslib@2.8.1: {} @@ -4842,6 +5626,8 @@ snapshots: typescript@5.0.2: {} + ufo@1.6.3: {} + undici-types@6.11.1: {} unified@11.0.5: @@ -4908,6 +5694,8 @@ snapshots: util-deprecate@1.0.2: {} + uuid@11.1.0: {} + vaul@0.9.6(@types/react-dom@19.0.0)(@types/react@19.0.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: '@radix-ui/react-dialog': 1.1.4(@types/react-dom@19.0.0)(@types/react@19.0.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -4944,6 +5732,23 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 + vscode-jsonrpc@8.2.0: {} + + vscode-languageserver-protocol@3.17.5: + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + + vscode-languageserver-textdocument@1.0.12: {} + + vscode-languageserver-types@3.17.5: {} + + vscode-languageserver@9.0.1: + dependencies: + vscode-languageserver-protocol: 3.17.5 + + vscode-uri@3.1.0: {} + which@2.0.2: dependencies: isexe: 2.0.0