diff --git a/.changeset/curated-public-api.md b/.changeset/curated-public-api.md new file mode 100644 index 0000000..d1b13c9 --- /dev/null +++ b/.changeset/curated-public-api.md @@ -0,0 +1,10 @@ +--- +"@anarchitecture/summon": minor +"@anarchitecture/summon-server": patch +"@anarchitecture/summon-react": patch +--- + +Curate the root Summon export to the beta host-authoring API and move advanced +browser, engine, and host runtime APIs behind explicit public subpaths. Packed +server and React packages now import those public subpaths instead of relying on +root export leakage. diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 25f0bc5..f57e8ee 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -1,31 +1,43 @@ --- -name: 🐛 Bug Report -about: Thank you for taking the time, please report a reproducible bug -title: "[Bug] " +name: Bug report +about: Report a reproducible Summon bug +title: "[Bug] " labels: bug -assignees: add codeowner's @name here - --- -**Describe the bug** -*A clear and concise description of what the bug is.* +## Summary + +What broke? + +## Reproduction + +1. +2. +3. + +## Expected Behavior + +What should have happened? + +## Actual Behavior + +What happened instead? + +## Environment -**To Reproduce:** -*Steps to reproduce the behavior:* -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error +- Package and version: +- Browser/runtime: +- Operating system: +- Node/pnpm versions: -**Expected behavior:** -*A clear and concise description of what you expected to happen.* +## Generated Surface Context -**Supporting Material** -*If applicable, add screenshots, output log and/or other documentation to help explain your problem.* +If this involves generated output, include the smallest useful protocol snippet, +surface plan, validation issue, or Devtools event. Do not include credentials, +private user data, or secrets. -**Environment (please complete the following information):** - - OS: [ex: iOS] - - Version +## Sandbox Or Security Impact -**Additional context** -Add any other context that you feel is relevant about the problem here. +Does this involve sandbox containment, grant bypass, CSP behavior, iframe +configuration, or host-owned data exposure? If yes, do not file a public issue +for exploitable behavior; use GitHub private vulnerability reporting instead. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 0ba9db2..64eb98d 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,4 +1,2 @@ -contact_links: - - name: ❓ Questions and Help 🤔 - url: https://discord.gg/block-opensource (/add your discord channel if applicable) - about: This issue tracker is not for support questions. Please refer to the community for more help. +blank_issues_enabled: true +contact_links: [] diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 85a7af5..3fa37ce 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: release: name: Version or publish runs-on: ubuntu-latest - timeout-minutes: 15 + timeout-minutes: 35 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: @@ -34,9 +34,7 @@ jobs: - run: pnpm install --frozen-lockfile - - run: pnpm build - - - run: pnpm check:public-packages + - run: pnpm exec playwright install --with-deps chromium webkit - name: Create Release PR or publish uses: changesets/action@6a0a831ff30acef54f2c6aa1cbbc1096b066edaf # v1.7.0 diff --git a/CODEOWNERS b/CODEOWNERS index 05435e9..7e4ffa0 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,24 +1 @@ -# This CODEOWNERS file denotes the project leads -# and encodes their responsibilities for code review. - -# Instructions: At a minimum, replace the '@GITHUB_USER_NAME_GOES_HERE' -# here with at least one project lead. - -# Lines starting with '#' are comments. -# Each line is a file pattern followed by one or more owners. -# The format is described: https://github.blog/2017-07-06-introducing-code-owners/ - -# These owners will be the default owners for everything in the repo. -* @nahiyankhan - - -# ----------------------------------------------- -# BELOW THIS LINE ARE TEMPLATES, UNUSED -# ----------------------------------------------- -# Order is important. The last matching pattern has the most precedence. -# So if a pull request only touches javascript files, only these owners -# will be requested to review. -# *.js @octocat @github/js - -# You can also use email addresses if you prefer. -# docs/* docs@example.com \ No newline at end of file +* @nahiyankhan diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..21be7b6 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,6 @@ +# Code Of Conduct + +Summon follows Block's open-source community standards. + +See the Block organization code of conduct: +https://github.com/block/.github/blob/main/CODE_OF_CONDUCT.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..2a42f29 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,67 @@ +# Contributing To Summon + +Thanks for helping make Summon sturdier. Summon is pre-1.0, so public APIs can +still move, but changes should preserve the core boundary: generated artifacts +describe UI; the host owns grants, handlers, state, network, credentials, and +persistence. + +## Local Setup + +```sh +pnpm install --frozen-lockfile +cp apps/server/.env.example apps/server/.env +# optional for generation demos: set ANTHROPIC_API_KEY in apps/server/.env +pnpm dev:all +``` + +The browser demo runs at `http://localhost:5173/generate.html`. + +## Required Checks + +Run the focused checks for your change, then run the full release gate before a +public package or sandbox-boundary change: + +```sh +pnpm typecheck +pnpm test +pnpm build +pnpm check:public-packages +pnpm check:public-api +pnpm pack:dry-run +pnpm smoke:public-packages +pnpm test:safety +``` + +`pnpm test:safety` runs Chromium and WebKit smoke tests for sandbox containment, +strict input, component islands, startup fatal checks, and generate-page boot. +Run it before changing iframe attributes, CSP, postMessage routing, bootstrap +startup checks, script policy, grants, or component overlay behavior. + +## Package Boundary + +Applications should import public packages only: + +- `@anarchitecture/summon` for host-authoring helpers and surface-plan types. +- `@anarchitecture/summon/browser` for iframe/runtime browser helpers. +- `@anarchitecture/summon/engine` for protocol, validation, prompt contracts, + stream graph, and other advanced engine APIs. +- `@anarchitecture/summon/host` for adapter authors needing the full host + runtime surface. +- `@anarchitecture/summon-server` for provider-neutral generation lifecycle. +- `@anarchitecture/summon-react` for React rendering and component islands. + +Do not import `src/*.ts` paths or `@summon-internal/*` packages from apps, +examples, docs, or public package builds. If a public export changes, update +`scripts/check-public-api.mjs`, package-consumption docs, and the packed-package +smoke test in the same change. + +## Changesets + +Public package changes need a changeset: + +```sh +pnpm changeset +``` + +Private `@summon-internal/*` implementation packages and demo apps are ignored +by Changesets; describe public impact on `@anarchitecture/*` packages. diff --git a/README.md b/README.md index 871fc9b..022a405 100644 --- a/README.md +++ b/README.md @@ -82,9 +82,9 @@ generation starts. The model sees that plan as a contract but cannot widen it. ## Public Packages -- `@anarchitecture/summon` - core protocol, surface plans, host contract - helpers, diagnostics primitives, and explicit browser/policy/envelope/assets/ - Devtools subpaths. +- `@anarchitecture/summon` - curated host-authoring helpers, policy helpers, + and surface-plan APIs. Advanced browser, engine, host, policy, envelope, + assets, and Devtools APIs live on explicit subpaths. - `@anarchitecture/summon-server` - provider-neutral generation lifecycle, repair, summaries, and model-provider interfaces. - `@anarchitecture/summon-react` - `SummonSurface` and React component island @@ -137,6 +137,8 @@ pnpm typecheck pnpm test pnpm test:safety pnpm build +pnpm check:public-api +pnpm smoke:public-packages pnpm pack:dry-run pnpm dev:all pnpm port-direction [id] diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..5c8ef73 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,18 @@ +# Security Policy + +Summon's security model depends on a null-origin iframe, restrictive CSP, +host-owned grants, schema-validated policy dispatch, and explicit capability +contracts. Reports involving sandbox escape, grant bypass, CSP weakening, +forged `postMessage` routing, host data exposure, or credential access should +not be filed as public issues. + +Use GitHub private vulnerability reporting for this repository. Include: + +- A minimal reproduction. +- Browser/runtime and operating system. +- Generated protocol lines or HTML involved, if applicable. +- The selected `SurfacePlan`, granted intents, and granted capabilities. +- Whether the issue affects static, declarative, scripted, worker, or component + island surfaces. + +For non-exploitable bugs, use the public bug report template. diff --git a/apps/demo/src/batch-main.ts b/apps/demo/src/batch-main.ts index 99060c7..1c2e16e 100644 --- a/apps/demo/src/batch-main.ts +++ b/apps/demo/src/batch-main.ts @@ -1,11 +1,10 @@ +import { PolicyEngine, type CapabilityPack } from '@anarchitecture/summon'; import { spawnSandbox, type SandboxHandle } from '@anarchitecture/summon/browser'; -import { PolicyEngine } from '@anarchitecture/summon/policy'; import { parseProtocolLine, SectionAccumulator, - type CapabilityPack, type ValidationCapability, -} from '@anarchitecture/summon'; +} from '@anarchitecture/summon/engine'; import bootstrapSource from '@anarchitecture/summon/bootstrap.js?raw'; import defaultTokensSource from '@anarchitecture/summon/tokens.css?raw'; import { ALL_PROMPTS, sample } from './prompts.js'; diff --git a/apps/demo/src/generate-main.ts b/apps/demo/src/generate-main.ts index afe4f5c..1228ef4 100644 --- a/apps/demo/src/generate-main.ts +++ b/apps/demo/src/generate-main.ts @@ -1,38 +1,40 @@ import { - type ComponentIslandRegistry, - type SurfaceStreamContext, - type SurfaceStreamResult, consumeSurfaceStream, createComponentIslandRegistry, spawnSandbox, + type ComponentIslandRegistry, type SandboxHandle, + type SurfaceStreamContext, + type SurfaceStreamResult, } from '@anarchitecture/summon/browser'; import { createSurfaceEnvelope, parseSurfaceEnvelope, type SurfaceEnvelope, } from '@anarchitecture/summon/envelope'; -import { PolicyEngine } from '@anarchitecture/summon/policy'; +import { + parseTokenValues, + SectionAccumulator, + type ProtocolLine, + type SummonLayout, + type ValidationCapability, + type ValidationComponent, +} from '@anarchitecture/summon/engine'; import { deriveSurfacePlanControls, normalizeSurfacePlan, - SectionAccumulator, + PolicyEngine, SURFACE_AUTHORITY_VALUES, SURFACE_DATA_VALUES, SURFACE_PERSISTENCE_VALUES, SURFACE_PURPOSE_VALUES, SURFACE_RUNTIME_VALUES, - type ProtocolLine, type CapabilityPack, type ComponentPack, type ScriptPolicy, type SurfaceCeiling, type SurfacePlan, - type SummonLayout, - type ValidationCapability, - type ValidationComponent, } from '@anarchitecture/summon'; -import { parseTokenValues } from '@summon-internal/engine'; import { createEventStore, type DevtoolsEvent } from '@anarchitecture/summon/devtools'; import bootstrapSource from '@anarchitecture/summon/bootstrap.js?raw'; import defaultTokensSource from '@anarchitecture/summon/tokens.css?raw'; diff --git a/apps/demo/src/strict-main.ts b/apps/demo/src/strict-main.ts index d23c0e3..f14bf91 100644 --- a/apps/demo/src/strict-main.ts +++ b/apps/demo/src/strict-main.ts @@ -8,13 +8,15 @@ * in. The architectural property — outer describes, host renders — is the * same regardless of the tokenizer. */ +import { + PolicyEngine, +} from '@anarchitecture/summon'; import { spawnSandbox, createStrictInputRegistry, type SandboxHandle, type StrictInputController, } from '@anarchitecture/summon/browser'; -import { PolicyEngine } from '@anarchitecture/summon/policy'; import bootstrapSource from '@anarchitecture/summon/bootstrap.js?raw'; import tokensSource from '@anarchitecture/summon/tokens.css?raw'; import { STRICT_DEMO_BODY_HTML } from './strict-demo-artifact.js'; diff --git a/apps/server/src/component-pack.ts b/apps/server/src/component-pack.ts index 308bb86..bedd8f8 100644 --- a/apps/server/src/component-pack.ts +++ b/apps/server/src/component-pack.ts @@ -1,9 +1,11 @@ import type { - ComponentExample, ComponentPack, - ComponentSizing, ComponentSurface, } from '@anarchitecture/summon'; +import type { + ComponentExample, + ComponentSizing, +} from '@anarchitecture/summon/engine'; /** * Validate a component pack sent by the client. The server remains renderer diff --git a/apps/server/src/directions-loader.ts b/apps/server/src/directions-loader.ts index 7541682..9c1e2ce 100644 --- a/apps/server/src/directions-loader.ts +++ b/apps/server/src/directions-loader.ts @@ -5,7 +5,7 @@ import { compileDirectionContract, coerceOpts, type DirectionOpts, -} from '@summon-internal/engine'; +} from '@anarchitecture/summon/engine'; export const PREFERRED_DEFAULT_DIRECTION_ID = 'ghost'; diff --git a/apps/server/src/generate-route.test.ts b/apps/server/src/generate-route.test.ts index 8864b26..a0149a2 100644 --- a/apps/server/src/generate-route.test.ts +++ b/apps/server/src/generate-route.test.ts @@ -6,7 +6,8 @@ import { createServer, type IncomingMessage } from 'node:http'; import { dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import test from 'node:test'; -import type { CapabilityPack, ProtocolLine, SurfaceCeiling, SurfacePlan } from '@anarchitecture/summon'; +import type { CapabilityPack, SurfaceCeiling, SurfacePlan } from '@anarchitecture/summon'; +import type { ProtocolLine } from '@anarchitecture/summon/engine'; const here = dirname(fileURLToPath(import.meta.url)); const packageRoot = resolve(here, '..'); diff --git a/apps/server/src/ghost-adapter.ts b/apps/server/src/ghost-adapter.ts index 55cdc32..d4eefc9 100644 --- a/apps/server/src/ghost-adapter.ts +++ b/apps/server/src/ghost-adapter.ts @@ -8,8 +8,7 @@ import { type GhostMemoryStackLayer, type PackageMemory, } from '@anarchitecture/ghost/scan'; -import type { ProtocolLine } from '@anarchitecture/summon'; -import { compileTokenContract } from '@summon-internal/engine'; +import { compileTokenContract, type ProtocolLine } from '@anarchitecture/summon/engine'; import { existsSync, readFileSync, statSync } from 'node:fs'; import { mkdtemp, readFile, rm } from 'node:fs/promises'; import { tmpdir } from 'node:os'; diff --git a/apps/server/src/main.ts b/apps/server/src/main.ts index fb96671..c81117f 100644 --- a/apps/server/src/main.ts +++ b/apps/server/src/main.ts @@ -3,13 +3,15 @@ import cors from 'cors'; import Anthropic from '@anthropic-ai/sdk'; import { type CapabilityPack, + type ScriptPolicy, +} from '@anarchitecture/summon'; +import { + parseTokenValues, type ContractPromptBlock, type ProtocolLine, - type ScriptPolicy, type SummonLayout, type TokenOverride, -} from '@anarchitecture/summon'; -import { parseTokenValues } from '@summon-internal/engine'; +} from '@anarchitecture/summon/engine'; import { resolveSurfaceGenerationPlan, runSurfaceGeneration, diff --git a/docs/adoption/package-consumption.md b/docs/adoption/package-consumption.md index d09af1b..e56c6c8 100644 --- a/docs/adoption/package-consumption.md +++ b/docs/adoption/package-consumption.md @@ -6,6 +6,17 @@ or `@summon-internal/*` packages from applications. For package boundary rationale, see [Public Packaging Plan](public-packaging.md). +The root `@anarchitecture/summon` entrypoint is intentionally curated for +host-authoring helpers, component/capability registries, policy helpers, and +surface-plan types. Use explicit subpaths for runtime and advanced APIs: + +- `@anarchitecture/summon/browser` for iframe spawning, stream consumption, + component islands, and strict input. +- `@anarchitecture/summon/engine` for protocol parsing, validators, prompt + contracts, `SectionAccumulator`, `StreamGraph`, and hardening. +- `@anarchitecture/summon/host` for adapter authors who need the full host + runtime surface. + ## React Hosts ```ts @@ -185,5 +196,7 @@ Run this before publishing: ```sh pnpm build pnpm check:public-packages +pnpm check:public-api pnpm pack:dry-run +pnpm smoke:public-packages ``` diff --git a/docs/adoption/public-packaging.md b/docs/adoption/public-packaging.md index 06e1d85..e910e59 100644 --- a/docs/adoption/public-packaging.md +++ b/docs/adoption/public-packaging.md @@ -14,11 +14,25 @@ Publish by install environment, not by internal implementation layer. @anarchitecture/summon-react ``` -`@anarchitecture/summon` is the shared host/contract package. Its root export is -kept narrow: protocol parsing, surface-plan helpers, host capability/component -contract helpers, and public diagnostics types. Browser runtime, policy, -envelope, assets, and Devtools APIs live on explicit subpaths such as -`@anarchitecture/summon/browser` and `@anarchitecture/summon/policy`. +`@anarchitecture/summon` is the frameworkless client/core package. Its root +entrypoint is curated for host-authoring helpers: capability and component +registries, `PolicyEngine`, and `SurfacePlan` helpers/types. Advanced runtime +surfaces live behind explicit subpaths: + +```txt +@anarchitecture/summon/browser +@anarchitecture/summon/engine +@anarchitecture/summon/host +@anarchitecture/summon/policy +@anarchitecture/summon/envelope +@anarchitecture/summon/assets +@anarchitecture/summon/devtools +``` + +Use `/browser` for iframe spawning, stream consumption, component islands, and +strict input. Use `/engine` for protocol, validation, prompt contracts, stream +graph, and hardening. Use `/host` only when writing adapters that need the full +host runtime surface. `@anarchitecture/summon-server` is the provider-neutral generation package. It owns `runSurfaceGeneration`, prompt/contract assembly, repair feedback, summary @@ -78,6 +92,8 @@ Keep the private implementation graph boring: - Fail CI if public JS or `.d.ts` imports `@summon-internal/*`, public wrappers use `export *`, public-looking implementation dirs appear at `dist/*`, or wrapper exports drift from `scripts/public-api-manifest.json`. +- Fail CI if the runtime public API snapshot drifts without an intentional + update to `scripts/check-public-api.mjs`. - Do source-health work here when it is destination-agnostic: tests, security fixes, API cleanup, build reliability, and package metadata correctness. @@ -88,6 +104,8 @@ Run this before publishing: ```sh pnpm build pnpm check:public-packages +pnpm check:public-api pnpm pack:dry-run +pnpm smoke:public-packages pnpm test:safety ``` diff --git a/package.json b/package.json index 1b1aecb..aa432ea 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,9 @@ "build:apps": "pnpm --filter @summon-internal/demo build", "build": "pnpm build:impl && pnpm build:public-core && pnpm build:react-impl && pnpm build:public && pnpm build:apps", "check:public-packages": "node scripts/check-public-packages.mjs", - "pack:dry-run": "pnpm -r --filter \"@anarchitecture/*\" exec npm --cache /tmp/summon-npm-cache pack --dry-run --json", + "check:public-api": "node scripts/check-public-api.mjs", + "check:release": "pnpm typecheck && pnpm test && pnpm build && pnpm check:public-packages && pnpm check:public-api && pnpm pack:dry-run && pnpm smoke:public-packages && pnpm test:safety", + "pack:dry-run": "node scripts/pack-public-packages.mjs --dry-run", "smoke:public-packages": "node scripts/smoke-public-packages.mjs", "test": "pnpm -r --filter @summon-internal/engine --filter @summon-internal/host --filter @summon-internal/server --filter @summon-internal/demo-server --filter @summon-internal/demo test", "test:safety": "playwright test", @@ -22,7 +24,7 @@ "typecheck": "pnpm -r typecheck", "changeset": "changeset", "version-packages": "changeset version", - "release": "pnpm build && pnpm check:public-packages && changeset publish", + "release": "pnpm check:release && changeset publish", "port-direction": "tsx scripts/port-direction.ts", "eval-directions": "tsx scripts/eval-directions.ts" }, @@ -36,5 +38,10 @@ "tsx": "^4.7.0", "@changesets/changelog-github": "^0.6.0", "@changesets/cli": "^2.31.0" + }, + "pnpm": { + "onlyBuiltDependencies": [ + "esbuild" + ] } } diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index 7da4f29..0a6fcd6 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -2,9 +2,8 @@ import { type CapabilityRegistry, type ComponentDefinition, type ComponentRegistry, - SectionAccumulator, - type ProtocolLine, } from '@anarchitecture/summon'; +import { SectionAccumulator, type ProtocolLine } from '@anarchitecture/summon/engine'; import { createComponentIslandRegistry, spawnSandbox, diff --git a/packages/react/tsconfig.build.json b/packages/react/tsconfig.build.json index f3d2382..214080b 100644 --- a/packages/react/tsconfig.build.json +++ b/packages/react/tsconfig.build.json @@ -10,7 +10,9 @@ "@anarchitecture/summon/assets": ["packages/summon/dist/assets.d.ts"], "@anarchitecture/summon/browser": ["packages/summon/dist/browser.d.ts"], "@anarchitecture/summon/devtools": ["packages/summon/dist/devtools.d.ts"], + "@anarchitecture/summon/engine": ["packages/summon/dist/engine.d.ts"], "@anarchitecture/summon/envelope": ["packages/summon/dist/envelope.d.ts"], + "@anarchitecture/summon/host": ["packages/summon/dist/host.d.ts"], "@anarchitecture/summon/policy": ["packages/summon/dist/policy.d.ts"], "@summon-internal/devtools": ["packages/devtools/dist/index.d.ts"], "@summon-internal/engine": ["packages/engine/dist/index.d.ts"], diff --git a/packages/summon/package.json b/packages/summon/package.json index 161c25b..8ec63ee 100644 --- a/packages/summon/package.json +++ b/packages/summon/package.json @@ -31,6 +31,14 @@ "types": "./dist/browser.d.ts", "import": "./dist/browser.js" }, + "./engine": { + "types": "./dist/engine.d.ts", + "import": "./dist/engine.js" + }, + "./host": { + "types": "./dist/host.d.ts", + "import": "./dist/host.js" + }, "./policy": { "types": "./dist/policy.d.ts", "import": "./dist/policy.js" diff --git a/packages/summon/src/engine.ts b/packages/summon/src/engine.ts new file mode 100644 index 0000000..43ca608 --- /dev/null +++ b/packages/summon/src/engine.ts @@ -0,0 +1 @@ +export * from '@summon-internal/engine'; diff --git a/packages/summon/src/host.ts b/packages/summon/src/host.ts new file mode 100644 index 0000000..daf67cd --- /dev/null +++ b/packages/summon/src/host.ts @@ -0,0 +1 @@ +export * from '@summon-internal/host'; diff --git a/packages/summon/src/index.ts b/packages/summon/src/index.ts index f66d458..5dc2157 100644 --- a/packages/summon/src/index.ts +++ b/packages/summon/src/index.ts @@ -1,66 +1,71 @@ +export { + createCapabilityRegistry, + createComponentRegistry, + defineAction, + defineApprovalAction, + defineCapability, + defineComponent, + defineDataResource, + defineIntent, + defineWorkerAction, + defineWorkerResource, + IntentArgsError, + PolicyEngine, +} from '@summon-internal/host'; + export { DEFAULT_SURFACE_CEILING, DEFAULT_SURFACE_PLAN, - ProtocolParseError, - SectionAccumulator, - StreamGraph, + deriveSurfacePlanControls, + inferSurfacePlan, + normalizeSurfaceCeiling, + normalizeSurfacePlan, SURFACE_AUTHORITY_VALUES, SURFACE_DATA_VALUES, SURFACE_PERSISTENCE_VALUES, SURFACE_PURPOSE_VALUES, SURFACE_RUNTIME_VALUES, - constrainSurfacePlan, - deriveSurfacePlanControls, - hintsForContractIssue, - inferSurfacePlan, - isProtocolLine, - normalizeSurfaceCeiling, - normalizeSurfacePlan, - parseProtocolLine, - parseProtocolLineStrict, + surfacePlanScriptPolicy, surfacePlanWithinCeiling, + constrainSurfacePlan, } from '@summon-internal/engine'; + +export type { + ActionDefinition, + ApprovalActionDefinition, + ApprovalDecision, + ApprovalStateKeys, + CapabilityDefinition, + CapabilityRegistry, + ComponentDefinition, + ComponentDestroyer, + ComponentPropsParseResult, + ComponentRegistry, + ComponentRenderContext, + ComponentRenderer, + DataResourceDefinition, + IntentContext, + IntentEntry, + IntentHandler, + PolicyEngineOptions, + StateShapeDescriptor, + TypedIntentEntry, +} from '@summon-internal/host'; + export type { - AddLine, + CapabilityBindingSpec, CapabilityKind, CapabilityPack, CapabilityPattern, CapabilityStateKeys, CapabilitySurface, CapabilityTrigger, - ComponentExample, + CapabilityTriggerSpec, ComponentPack, - ComponentSizing, ComponentSpec, ComponentSurface, - ContractIssue, - ContractIssueSeverity, - ContractIssueSource, - ContractPromptBlock, - DataResourceSpec, - DirectionContractInput, - DirectionInput, - Exemplar, IntentSpec, - MetaLine, - ProtocolLine, - ProtocolParseErrorCode, - ProtocolParseOptions, - ProtocolSkipMetaValue, - RepairFeedbackMetaValue, - ScreenSynthesizedMetaValue, ScriptPolicy, - SectionAccumulatorSnapshot, - SectionApplyKind, - SectionApplyResult, - SectionSnapshotEntry, - SetLine, - StreamGraphEdge, - StreamGraphHealth, - StreamGraphSection, - StreamGraphSnapshot, - SummonLayout, - SummonLayoutSlot, SurfaceAuthority, SurfaceCeiling, SurfaceData, @@ -71,33 +76,4 @@ export type { SurfacePlanMode, SurfacePurpose, SurfaceRuntime, - TokenOverride, - ValidationCapability, - ValidationComponent, } from '@summon-internal/engine'; -export { - createCapabilityRegistry, - createComponentRegistry, - defineAction, - defineApprovalAction, - defineComponent, - defineDataResource, - defineWorkerAction, - defineWorkerResource, -} from '@summon-internal/host'; -export type { - ActionDefinition, - ApprovalActionDefinition, - ApprovalDecision, - ApprovalStateKeys, - CapabilityDefinition, - CapabilityRegistry, - ComponentDefinition, - ComponentDestroyer, - ComponentPropsParseResult, - ComponentRegistry, - ComponentRenderContext, - ComponentRenderer, - DataResourceDefinition, - StateShapeDescriptor, -} from '@summon-internal/host'; diff --git a/scripts/build-public-packages.mjs b/scripts/build-public-packages.mjs index c89db57..2312197 100644 --- a/scripts/build-public-packages.mjs +++ b/scripts/build-public-packages.mjs @@ -25,9 +25,6 @@ const coreExports = { './_internal/engine/index.js': [ 'DEFAULT_SURFACE_CEILING', 'DEFAULT_SURFACE_PLAN', - 'ProtocolParseError', - 'SectionAccumulator', - 'StreamGraph', 'SURFACE_AUTHORITY_VALUES', 'SURFACE_DATA_VALUES', 'SURFACE_PERSISTENCE_VALUES', @@ -35,13 +32,10 @@ const coreExports = { 'SURFACE_RUNTIME_VALUES', 'constrainSurfacePlan', 'deriveSurfacePlanControls', - 'hintsForContractIssue', 'inferSurfacePlan', - 'isProtocolLine', 'normalizeSurfaceCeiling', 'normalizeSurfacePlan', - 'parseProtocolLine', - 'parseProtocolLineStrict', + 'surfacePlanScriptPolicy', 'surfacePlanWithinCeiling', ], './_internal/host/index.js': [ @@ -49,21 +43,147 @@ const coreExports = { 'createComponentRegistry', 'defineAction', 'defineApprovalAction', + 'defineCapability', 'defineComponent', 'defineDataResource', + 'defineIntent', 'defineWorkerAction', 'defineWorkerResource', + 'IntentArgsError', + 'PolicyEngine', + ], + }, + types: { + './_internal/engine/index.js': [ + 'CapabilityBindingSpec', + 'CapabilityKind', + 'CapabilityPack', + 'CapabilityPattern', + 'CapabilityStateKeys', + 'CapabilitySurface', + 'CapabilityTrigger', + 'CapabilityTriggerSpec', + 'ComponentPack', + 'ComponentSpec', + 'ComponentSurface', + 'IntentSpec', + 'ScriptPolicy', + 'SurfaceAuthority', + 'SurfaceCeiling', + 'SurfaceData', + 'SurfacePersistence', + 'SurfacePlan', + 'SurfacePlanControls', + 'SurfacePlanInferenceInput', + 'SurfacePlanMode', + 'SurfacePurpose', + 'SurfaceRuntime', + ], + './_internal/host/index.js': [ + 'ActionDefinition', + 'ApprovalActionDefinition', + 'ApprovalDecision', + 'ApprovalStateKeys', + 'CapabilityDefinition', + 'CapabilityRegistry', + 'ComponentDefinition', + 'ComponentDestroyer', + 'ComponentPropsParseResult', + 'ComponentRegistry', + 'ComponentRenderContext', + 'ComponentRenderer', + 'DataResourceDefinition', + 'IntentContext', + 'IntentEntry', + 'IntentHandler', + 'PolicyEngineOptions', + 'StateShapeDescriptor', + 'TypedIntentEntry', + ], + }, + }, + './engine': { + values: { + './_internal/engine/index.js': [ + 'CAPABILITY_BINDING_SPECS', + 'CAPABILITY_TRIGGER_SPECS', + 'DEFAULT_SURFACE_CEILING', + 'DEFAULT_SURFACE_PLAN', + 'DEFAULT_VALIDATION_LIMITS', + 'OPPORTUNISTIC_TOKENS', + 'OPT_OUT_GROUPS', + 'OPT_OUT_TOKENS', + 'ProtocolParseError', + 'REQUIRED_TOKENS', + 'SHADOW_TOKENS', + 'SUMMON_FIXED_INSTRUCTIONS', + 'SUMMON_PROTOCOL_VERSION', + 'SUMMON_SYSTEM_PROMPT', + 'SURFACE_AUTHORITY_VALUES', + 'SURFACE_DATA_VALUES', + 'SURFACE_PERSISTENCE_VALUES', + 'SURFACE_PURPOSE_VALUES', + 'SURFACE_RUNTIME_VALUES', + 'SectionAccumulator', + 'StreamGraph', + 'TOKEN_CONTRACT', + 'buildCapabilitiesBlock', + 'buildComponentsBlock', + 'buildDirectionBlock', + 'buildLayoutBlock', + 'buildOverrideBlock', + 'buildPosturesBlock', + 'buildSurfacePlanBlock', + 'coerceOpts', + 'compileCapabilityContract', + 'compileComponentContract', + 'compileDirectionContract', + 'compileSystemContracts', + 'compileTokenContract', + 'constrainSurfacePlan', + 'contractIssue', + 'createProtocolHardener', + 'defaultTriggersForKind', + 'deriveSurfacePlanControls', + 'formatCapabilityProtocolContract', + 'formatTokenContract', + 'hasCompleteResourceStateKeys', + 'hintsForContractIssue', + 'inferSurfacePlan', + 'isProtocolLine', + 'normalizeSurfaceCeiling', + 'normalizeSurfacePlan', + 'normalizeValidationLimits', + 'parseDefinedTokens', + 'parseProtocolLine', + 'parseProtocolLineStrict', + 'parseTokenValues', + 'surfacePlanScriptPolicy', + 'surfacePlanWithinCeiling', + 'validateDirection', + 'validateHtmlFragment', + 'validateProtocolLine', + 'withIssueSeverity', ], }, types: { './_internal/engine/index.js': [ 'AddLine', + 'CapabilitiesBlockOptions', + 'CapabilityBindingSpec', + 'CapabilityContractOptions', 'CapabilityKind', 'CapabilityPack', 'CapabilityPattern', 'CapabilityStateKeys', 'CapabilitySurface', 'CapabilityTrigger', + 'CapabilityTriggerSpec', + 'CompiledCapabilityContract', + 'CompiledComponentContract', + 'CompiledDirectionContract', + 'CompiledSystemContracts', + 'CompiledTokenContract', 'ComponentExample', 'ComponentPack', 'ComponentSizing', @@ -76,9 +196,17 @@ const coreExports = { 'DataResourceSpec', 'DirectionContractInput', 'DirectionInput', + 'DirectionOpts', 'Exemplar', 'IntentSpec', 'MetaLine', + 'OptOutGroup', + 'OptOutValue', + 'PostureContract', + 'PostureRegistry', + 'ProtocolHardener', + 'ProtocolHardenerOptions', + 'ProtocolHardenerResult', 'ProtocolLine', 'ProtocolParseErrorCode', 'ProtocolParseOptions', @@ -107,25 +235,100 @@ const coreExports = { 'SurfacePlanMode', 'SurfacePurpose', 'SurfaceRuntime', + 'SystemContractInput', + 'TokenContract', + 'TokenContractInput', + 'TokenKind', 'TokenOverride', + 'TokenSpec', 'ValidationCapability', 'ValidationComponent', + 'ValidationContext', + 'ValidationLimits', + 'ValidationResult', ], + }, + }, + './host': { + values: { + './_internal/host/index.js': [ + 'IntentArgsError', + 'PolicyEngine', + 'SUMMON_SURFACE_ENVELOPE_VERSION', + 'bindEndpoint', + 'consumeSurfaceStream', + 'createCapabilityRegistry', + 'createComponentIslandRegistry', + 'createComponentRegistry', + 'createStrictInputRegistry', + 'createSurfaceEnvelope', + 'defineAction', + 'defineApprovalAction', + 'defineCapability', + 'defineComponent', + 'defineDataResource', + 'defineIntent', + 'defineWorkerAction', + 'defineWorkerResource', + 'isSurfaceEnvelope', + 'parseSurfaceEnvelope', + 'spawnSandbox', + ], + }, + types: { './_internal/host/index.js': [ 'ActionDefinition', 'ApprovalActionDefinition', 'ApprovalDecision', 'ApprovalStateKeys', + 'Artifact', 'CapabilityDefinition', 'CapabilityRegistry', 'ComponentDefinition', 'ComponentDestroyer', + 'ComponentIslandBounds', + 'ComponentIslandDescriptor', + 'ComponentIslandError', + 'ComponentIslandErrorCode', + 'ComponentIslandRegistry', + 'ComponentIslandRegistryOptions', + 'ComponentIslandSyncContext', 'ComponentPropsParseResult', 'ComponentRegistry', 'ComponentRenderContext', 'ComponentRenderer', + 'ComponentsMessage', + 'CreateSurfaceEnvelopeInput', 'DataResourceDefinition', + 'EndpointBinding', + 'EndpointStateKeys', + 'FatalMessage', + 'IntentContext', + 'IntentEntry', + 'IntentHandler', + 'IntentMessage', + 'PolicyEngineOptions', + 'ReadyMessage', + 'SandboxHandle', + 'SandboxInboundMessage', + 'SpawnOptions', + 'StateMessage', 'StateShapeDescriptor', + 'StrictInputBounds', + 'StrictInputController', + 'StrictInputFactory', + 'StrictInputFactoryArgs', + 'StrictInputRegistry', + 'StrictInputRegistryOptions', + 'SurfaceEnvelope', + 'SurfaceStreamContext', + 'SurfaceStreamLineDecision', + 'SurfaceStreamOptions', + 'SurfaceStreamParseError', + 'SurfaceStreamRenderMode', + 'SurfaceStreamResult', + 'SurfaceStreamSource', + 'TypedIntentEntry', ], }, }, @@ -381,6 +584,8 @@ async function writeWrappers(distDir, definitions) { const files = { '.': 'index', './browser': 'browser', + './engine': 'engine', + './host': 'host', './policy': 'policy', './envelope': 'envelope', './assets': 'assets', @@ -426,9 +631,8 @@ async function buildServer() { const distDir = resolveRoot('packages/summon-server/dist'); await rm(distDir, { recursive: true, force: true }); - await copyDistTree(resolveRoot('packages/engine/dist'), join(distDir, '_internal', 'engine')); await copyDistTree(resolveRoot('packages/server/dist'), join(distDir, '_internal', 'server'), [ - ['@summon-internal/engine', '../engine/index.js'], + ['@summon-internal/engine', '@anarchitecture/summon/engine'], ]); await writeWrappers(distDir, serverExports); } @@ -437,7 +641,13 @@ async function buildReact() { await assertBuilt('packages/react'); const distDir = resolveRoot('packages/summon-react/dist'); await rm(distDir, { recursive: true, force: true }); - await copyDistTree(resolveRoot('packages/react/dist'), join(distDir, '_internal', 'react')); + await copyDistTree(resolveRoot('packages/react/dist'), join(distDir, '_internal', 'react'), [ + ['@summon-internal/sandbox-runtime/assets', '@anarchitecture/summon/assets'], + ['@summon-internal/host/envelope', '@anarchitecture/summon/envelope'], + ['@summon-internal/devtools', '@anarchitecture/summon/devtools'], + ['@summon-internal/engine', '@anarchitecture/summon/engine'], + ['@summon-internal/host', '@anarchitecture/summon/host'], + ]); await writeWrappers(distDir, reactExports); } diff --git a/scripts/check-public-api.mjs b/scripts/check-public-api.mjs new file mode 100644 index 0000000..106cf9c --- /dev/null +++ b/scripts/check-public-api.mjs @@ -0,0 +1,145 @@ +import { readFile } from 'node:fs/promises'; +import { dirname, join } from 'node:path'; +import { pathToFileURL, fileURLToPath } from 'node:url'; + +const rootDir = dirname(fileURLToPath(new URL('../package.json', import.meta.url))); + +const expectedRootExports = [ + 'DEFAULT_SURFACE_CEILING', + 'DEFAULT_SURFACE_PLAN', + 'IntentArgsError', + 'PolicyEngine', + 'SURFACE_AUTHORITY_VALUES', + 'SURFACE_DATA_VALUES', + 'SURFACE_PERSISTENCE_VALUES', + 'SURFACE_PURPOSE_VALUES', + 'SURFACE_RUNTIME_VALUES', + 'constrainSurfacePlan', + 'createCapabilityRegistry', + 'createComponentRegistry', + 'defineAction', + 'defineApprovalAction', + 'defineCapability', + 'defineComponent', + 'defineDataResource', + 'defineIntent', + 'defineWorkerAction', + 'defineWorkerResource', + 'deriveSurfacePlanControls', + 'inferSurfacePlan', + 'normalizeSurfaceCeiling', + 'normalizeSurfacePlan', + 'surfacePlanScriptPolicy', + 'surfacePlanWithinCeiling', +].sort(); + +const expectedServerExports = [ + 'generateSurfaceStream', + 'resolveSurfaceGenerationPlan', + 'runSurfaceGeneration', + 'summarizeContractIssues', +].sort(); + +const expectedReactExports = [ + 'SummonSurface', + 'defineReactComponent', +].sort(); + +const forbiddenRootExports = [ + 'bootstrapSource', + 'buildCapabilitiesBlock', + 'compileSystemContracts', + 'consumeSurfaceStream', + 'createEventStore', + 'createSurfaceEnvelope', + 'parseProtocolLine', + 'SectionAccumulator', + 'spawnSandbox', + 'StreamGraph', +]; + +async function importDist(packageName, entry = 'index.js') { + const path = join(rootDir, 'packages', packageName, 'dist', entry); + return import(pathToFileURL(path).href); +} + +function assertExactExports(name, mod, expected) { + const actual = Object.keys(mod).sort(); + const missing = expected.filter((item) => !actual.includes(item)); + const extra = actual.filter((item) => !expected.includes(item)); + if (missing.length || extra.length) { + throw new Error([ + `${name} exports drifted`, + missing.length ? `missing: ${missing.join(', ')}` : null, + extra.length ? `extra: ${extra.join(', ')}` : null, + ].filter(Boolean).join('\n')); + } +} + +function assertHas(name, mod, exports) { + const missing = exports.filter((item) => !(item in mod)); + if (missing.length) { + throw new Error(`${name} is missing expected exports: ${missing.join(', ')}`); + } +} + +const core = await importDist('summon'); +assertExactExports('@anarchitecture/summon', core, expectedRootExports); +for (const forbidden of forbiddenRootExports) { + if (forbidden in core) { + throw new Error(`@anarchitecture/summon root must not export ${forbidden}`); + } +} + +assertHas('@anarchitecture/summon/browser', await importDist('summon', 'browser.js'), [ + 'consumeSurfaceStream', + 'createComponentIslandRegistry', + 'createStrictInputRegistry', + 'spawnSandbox', +]); +assertHas('@anarchitecture/summon/engine', await importDist('summon', 'engine.js'), [ + 'buildCapabilitiesBlock', + 'compileSystemContracts', + 'createProtocolHardener', + 'parseProtocolLine', + 'SectionAccumulator', + 'StreamGraph', +]); +assertHas('@anarchitecture/summon/host', await importDist('summon', 'host.js'), [ + 'createCapabilityRegistry', + 'PolicyEngine', + 'spawnSandbox', +]); +assertHas('@anarchitecture/summon/policy', await importDist('summon', 'policy.js'), [ + 'PolicyEngine', +]); +assertHas('@anarchitecture/summon/envelope', await importDist('summon', 'envelope.js'), [ + 'createSurfaceEnvelope', +]); +const assets = await importDist('summon', 'assets.js'); +if (typeof assets.bootstrapSource !== 'string' || typeof assets.tokensSource !== 'string') { + throw new Error('@anarchitecture/summon/assets must export bootstrapSource and tokensSource strings'); +} +assertHas('@anarchitecture/summon/devtools', await importDist('summon', 'devtools.js'), [ + 'createEventStore', +]); + +assertExactExports( + '@anarchitecture/summon-server', + await importDist('summon-server'), + expectedServerExports, +); +assertExactExports( + '@anarchitecture/summon-react', + await importDist('summon-react'), + expectedReactExports, +); + +const manifest = JSON.parse(await readFile(join(rootDir, 'packages/summon/package.json'), 'utf8')); +for (const subpath of ['./engine', './host']) { + if (!manifest.exports?.[subpath]) { + throw new Error(`@anarchitecture/summon package.json must export ${subpath}`); + } +} + +console.log('public API snapshot is stable'); diff --git a/scripts/pack-public-packages.mjs b/scripts/pack-public-packages.mjs new file mode 100644 index 0000000..8b39c79 --- /dev/null +++ b/scripts/pack-public-packages.mjs @@ -0,0 +1,101 @@ +import { execFileSync } from 'node:child_process'; +import { mkdir, mkdtemp, readFile, writeFile } from 'node:fs/promises'; +import { dirname, join } from 'node:path'; +import { tmpdir } from 'node:os'; +import { fileURLToPath } from 'node:url'; + +export const rootDir = dirname(fileURLToPath(new URL('../package.json', import.meta.url))); + +export const publicPackageDirs = [ + 'packages/summon', + 'packages/summon-server', + 'packages/summon-react', +]; + +function cleanEnv() { + const env = { ...process.env }; + for (const key of Object.keys(env)) { + if (key.toLowerCase().startsWith('npm_config_')) { + delete env[key]; + } + } + return env; +} + +async function createNpmScratch() { + const dir = await mkdtemp(join(tmpdir(), 'summon-npm-')); + const cacheDir = join(dir, 'cache'); + const userConfig = join(dir, '.npmrc'); + const globalConfig = join(dir, '.npm-globalrc'); + await mkdir(cacheDir, { recursive: true }); + await writeFile(userConfig, 'registry=https://registry.npmjs.org/\n'); + await writeFile(globalConfig, ''); + return { cacheDir, globalConfig, userConfig }; +} + +export async function readPackageManifest(packageDir) { + const manifestPath = join(rootDir, packageDir, 'package.json'); + return JSON.parse(await readFile(manifestPath, 'utf8')); +} + +export function tarballFileName(manifest) { + const scopedName = manifest.name.startsWith('@') + ? manifest.name.slice(1).replace('/', '-') + : manifest.name; + return `${scopedName}-${manifest.version}.tgz`; +} + +export async function packPublicPackages(options = {}) { + const { + dryRun = false, + destinationDir, + json = true, + } = options; + const scratch = await createNpmScratch(); + if (destinationDir) await mkdir(destinationDir, { recursive: true }); + + const out = []; + for (const packageDir of publicPackageDirs) { + const packagePath = join(rootDir, packageDir); + const args = [ + 'pack', + packagePath, + '--cache', + scratch.cacheDir, + '--globalconfig', + scratch.globalConfig, + '--userconfig', + scratch.userConfig, + ]; + if (json) args.push('--json'); + if (dryRun) args.push('--dry-run'); + if (destinationDir) args.push('--pack-destination', destinationDir); + + const stdout = execFileSync('npm', args, { + cwd: dirname(scratch.userConfig), + env: cleanEnv(), + encoding: 'utf8', + stdio: ['ignore', 'pipe', 'inherit'], + }); + const parsed = json ? JSON.parse(stdout) : []; + const entries = Array.isArray(parsed) ? parsed : [parsed]; + for (const entry of entries) { + out.push({ + packageDir, + ...entry, + ...(destinationDir && entry.filename + ? { tarballPath: join(destinationDir, entry.filename) } + : {}), + }); + } + } + return out; +} + +if (import.meta.url === `file://${process.argv[1]}`) { + const dryRun = process.argv.includes('--dry-run'); + const destinationIndex = process.argv.indexOf('--pack-destination'); + const destinationDir = destinationIndex >= 0 ? process.argv[destinationIndex + 1] : undefined; + const result = await packPublicPackages({ dryRun, destinationDir }); + console.log(JSON.stringify(result, null, 2)); +} diff --git a/scripts/public-api-manifest.json b/scripts/public-api-manifest.json index 67e614b..3fe5184 100644 --- a/scripts/public-api-manifest.json +++ b/scripts/public-api-manifest.json @@ -5,9 +5,8 @@ "values": [ "DEFAULT_SURFACE_CEILING", "DEFAULT_SURFACE_PLAN", - "ProtocolParseError", - "SectionAccumulator", - "StreamGraph", + "IntentArgsError", + "PolicyEngine", "SURFACE_AUTHORITY_VALUES", "SURFACE_DATA_VALUES", "SURFACE_PERSISTENCE_VALUES", @@ -18,26 +17,25 @@ "createComponentRegistry", "defineAction", "defineApprovalAction", + "defineCapability", "defineComponent", "defineDataResource", + "defineIntent", "defineWorkerAction", "defineWorkerResource", "deriveSurfacePlanControls", - "hintsForContractIssue", "inferSurfacePlan", - "isProtocolLine", "normalizeSurfaceCeiling", "normalizeSurfacePlan", - "parseProtocolLine", - "parseProtocolLineStrict", + "surfacePlanScriptPolicy", "surfacePlanWithinCeiling" ], "types": [ "ActionDefinition", - "AddLine", "ApprovalActionDefinition", "ApprovalDecision", "ApprovalStateKeys", + "CapabilityBindingSpec", "CapabilityDefinition", "CapabilityKind", "CapabilityPack", @@ -46,47 +44,24 @@ "CapabilityStateKeys", "CapabilitySurface", "CapabilityTrigger", + "CapabilityTriggerSpec", "ComponentDefinition", "ComponentDestroyer", - "ComponentExample", "ComponentPack", "ComponentPropsParseResult", "ComponentRegistry", "ComponentRenderContext", "ComponentRenderer", - "ComponentSizing", "ComponentSpec", "ComponentSurface", - "ContractIssue", - "ContractIssueSeverity", - "ContractIssueSource", - "ContractPromptBlock", "DataResourceDefinition", - "DataResourceSpec", - "DirectionContractInput", - "DirectionInput", - "Exemplar", + "IntentContext", + "IntentEntry", + "IntentHandler", "IntentSpec", - "MetaLine", - "ProtocolLine", - "ProtocolParseErrorCode", - "ProtocolParseOptions", - "ProtocolSkipMetaValue", - "RepairFeedbackMetaValue", - "ScreenSynthesizedMetaValue", + "PolicyEngineOptions", "ScriptPolicy", - "SectionAccumulatorSnapshot", - "SectionApplyKind", - "SectionApplyResult", - "SectionSnapshotEntry", - "SetLine", "StateShapeDescriptor", - "StreamGraphEdge", - "StreamGraphHealth", - "StreamGraphSection", - "StreamGraphSnapshot", - "SummonLayout", - "SummonLayoutSlot", "SurfaceAuthority", "SurfaceCeiling", "SurfaceData", @@ -97,9 +72,7 @@ "SurfacePlanMode", "SurfacePurpose", "SurfaceRuntime", - "TokenOverride", - "ValidationCapability", - "ValidationComponent" + "TypedIntentEntry" ] }, "./assets": { @@ -175,6 +148,150 @@ "SurfacePlanEvent" ] }, + "./engine": { + "file": "engine", + "values": [ + "CAPABILITY_BINDING_SPECS", + "CAPABILITY_TRIGGER_SPECS", + "DEFAULT_SURFACE_CEILING", + "DEFAULT_SURFACE_PLAN", + "DEFAULT_VALIDATION_LIMITS", + "OPPORTUNISTIC_TOKENS", + "OPT_OUT_GROUPS", + "OPT_OUT_TOKENS", + "ProtocolParseError", + "REQUIRED_TOKENS", + "SHADOW_TOKENS", + "SUMMON_FIXED_INSTRUCTIONS", + "SUMMON_PROTOCOL_VERSION", + "SUMMON_SYSTEM_PROMPT", + "SURFACE_AUTHORITY_VALUES", + "SURFACE_DATA_VALUES", + "SURFACE_PERSISTENCE_VALUES", + "SURFACE_PURPOSE_VALUES", + "SURFACE_RUNTIME_VALUES", + "SectionAccumulator", + "StreamGraph", + "TOKEN_CONTRACT", + "buildCapabilitiesBlock", + "buildComponentsBlock", + "buildDirectionBlock", + "buildLayoutBlock", + "buildOverrideBlock", + "buildPosturesBlock", + "buildSurfacePlanBlock", + "coerceOpts", + "compileCapabilityContract", + "compileComponentContract", + "compileDirectionContract", + "compileSystemContracts", + "compileTokenContract", + "constrainSurfacePlan", + "contractIssue", + "createProtocolHardener", + "defaultTriggersForKind", + "deriveSurfacePlanControls", + "formatCapabilityProtocolContract", + "formatTokenContract", + "hasCompleteResourceStateKeys", + "hintsForContractIssue", + "inferSurfacePlan", + "isProtocolLine", + "normalizeSurfaceCeiling", + "normalizeSurfacePlan", + "normalizeValidationLimits", + "parseDefinedTokens", + "parseProtocolLine", + "parseProtocolLineStrict", + "parseTokenValues", + "surfacePlanScriptPolicy", + "surfacePlanWithinCeiling", + "validateDirection", + "validateHtmlFragment", + "validateProtocolLine", + "withIssueSeverity" + ], + "types": [ + "AddLine", + "CapabilitiesBlockOptions", + "CapabilityBindingSpec", + "CapabilityContractOptions", + "CapabilityKind", + "CapabilityPack", + "CapabilityPattern", + "CapabilityStateKeys", + "CapabilitySurface", + "CapabilityTrigger", + "CapabilityTriggerSpec", + "CompiledCapabilityContract", + "CompiledComponentContract", + "CompiledDirectionContract", + "CompiledSystemContracts", + "CompiledTokenContract", + "ComponentExample", + "ComponentPack", + "ComponentSizing", + "ComponentSpec", + "ComponentSurface", + "ContractIssue", + "ContractIssueSeverity", + "ContractIssueSource", + "ContractPromptBlock", + "DataResourceSpec", + "DirectionContractInput", + "DirectionInput", + "DirectionOpts", + "Exemplar", + "IntentSpec", + "MetaLine", + "OptOutGroup", + "OptOutValue", + "PostureContract", + "PostureRegistry", + "ProtocolHardener", + "ProtocolHardenerOptions", + "ProtocolHardenerResult", + "ProtocolLine", + "ProtocolParseErrorCode", + "ProtocolParseOptions", + "ProtocolSkipMetaValue", + "RepairFeedbackMetaValue", + "ScreenSynthesizedMetaValue", + "ScriptPolicy", + "SectionAccumulatorSnapshot", + "SectionApplyKind", + "SectionApplyResult", + "SectionSnapshotEntry", + "SetLine", + "StreamGraphEdge", + "StreamGraphHealth", + "StreamGraphSection", + "StreamGraphSnapshot", + "SummonLayout", + "SummonLayoutSlot", + "SurfaceAuthority", + "SurfaceCeiling", + "SurfaceData", + "SurfacePersistence", + "SurfacePlan", + "SurfacePlanControls", + "SurfacePlanInferenceInput", + "SurfacePlanMode", + "SurfacePurpose", + "SurfaceRuntime", + "SystemContractInput", + "TokenContract", + "TokenContractInput", + "TokenKind", + "TokenOverride", + "TokenSpec", + "ValidationCapability", + "ValidationComponent", + "ValidationContext", + "ValidationLimits", + "ValidationResult" + ] + }, "./envelope": { "file": "envelope", "values": [ @@ -185,9 +302,93 @@ ], "types": ["CreateSurfaceEnvelopeInput", "SurfaceEnvelope"] }, + "./host": { + "file": "host", + "values": [ + "IntentArgsError", + "PolicyEngine", + "SUMMON_SURFACE_ENVELOPE_VERSION", + "bindEndpoint", + "consumeSurfaceStream", + "createCapabilityRegistry", + "createComponentIslandRegistry", + "createComponentRegistry", + "createStrictInputRegistry", + "createSurfaceEnvelope", + "defineAction", + "defineApprovalAction", + "defineCapability", + "defineComponent", + "defineDataResource", + "defineIntent", + "defineWorkerAction", + "defineWorkerResource", + "isSurfaceEnvelope", + "parseSurfaceEnvelope", + "spawnSandbox" + ], + "types": [ + "ActionDefinition", + "ApprovalActionDefinition", + "ApprovalDecision", + "ApprovalStateKeys", + "Artifact", + "CapabilityDefinition", + "CapabilityRegistry", + "ComponentDefinition", + "ComponentDestroyer", + "ComponentIslandBounds", + "ComponentIslandDescriptor", + "ComponentIslandError", + "ComponentIslandErrorCode", + "ComponentIslandRegistry", + "ComponentIslandRegistryOptions", + "ComponentIslandSyncContext", + "ComponentPropsParseResult", + "ComponentRegistry", + "ComponentRenderContext", + "ComponentRenderer", + "ComponentsMessage", + "CreateSurfaceEnvelopeInput", + "DataResourceDefinition", + "EndpointBinding", + "EndpointStateKeys", + "FatalMessage", + "IntentContext", + "IntentEntry", + "IntentHandler", + "IntentMessage", + "PolicyEngineOptions", + "ReadyMessage", + "SandboxHandle", + "SandboxInboundMessage", + "SpawnOptions", + "StateMessage", + "StateShapeDescriptor", + "StrictInputBounds", + "StrictInputController", + "StrictInputFactory", + "StrictInputFactoryArgs", + "StrictInputRegistry", + "StrictInputRegistryOptions", + "SurfaceEnvelope", + "SurfaceStreamContext", + "SurfaceStreamLineDecision", + "SurfaceStreamOptions", + "SurfaceStreamParseError", + "SurfaceStreamRenderMode", + "SurfaceStreamResult", + "SurfaceStreamSource", + "TypedIntentEntry" + ] + }, "./policy": { "file": "policy", - "values": ["IntentArgsError", "PolicyEngine", "defineIntent"], + "values": [ + "IntentArgsError", + "PolicyEngine", + "defineIntent" + ], "types": [ "IntentContext", "IntentEntry", diff --git a/scripts/smoke-public-packages.mjs b/scripts/smoke-public-packages.mjs index 45af7d0..ed334f2 100644 --- a/scripts/smoke-public-packages.mjs +++ b/scripts/smoke-public-packages.mjs @@ -1,14 +1,15 @@ import { execFileSync } from 'node:child_process'; -import { mkdir, mkdtemp, writeFile } from 'node:fs/promises'; -import { dirname, join } from 'node:path'; +import { mkdir, mkdtemp, readFile, writeFile } from 'node:fs/promises'; +import { join } from 'node:path'; import { tmpdir } from 'node:os'; -import { fileURLToPath } from 'node:url'; +import { + packPublicPackages, + rootDir, +} from './pack-public-packages.mjs'; -const rootDir = dirname(fileURLToPath(new URL('../package.json', import.meta.url))); const workDir = await mkdtemp(join(tmpdir(), 'summon-public-smoke-')); const tarballDir = join(workDir, 'tarballs'); const projectDir = join(workDir, 'project'); -const npmCacheDir = join(workDir, 'npm-cache'); function run(command, args, cwd = rootDir) { execFileSync(command, args, { cwd, stdio: 'inherit' }); @@ -18,23 +19,30 @@ await writeFile(join(workDir, 'README'), 'Summon public package smoke test scrat await mkdir(tarballDir, { recursive: true }); await mkdir(projectDir, { recursive: true }); -for (const packageDir of ['packages/summon', 'packages/summon-server', 'packages/summon-react']) { - run('npm', ['--cache', npmCacheDir, 'pack', '--pack-destination', tarballDir], join(rootDir, packageDir)); +const packed = await packPublicPackages({ destinationDir: tarballDir }); +const byName = new Map(packed.map((entry) => [entry.name, entry])); +const rootManifest = JSON.parse(await readFile(join(rootDir, 'package.json'), 'utf8')); +const core = byName.get('@anarchitecture/summon'); +const serverPackage = byName.get('@anarchitecture/summon-server'); +const react = byName.get('@anarchitecture/summon-react'); +if (!core?.tarballPath || !serverPackage?.tarballPath || !react?.tarballPath) { + throw new Error('public package smoke could not find all packed tarballs'); } await writeFile(join(projectDir, 'package.json'), JSON.stringify({ private: true, type: 'module', + packageManager: rootManifest.packageManager, dependencies: { - '@anarchitecture/summon': `file:${join(tarballDir, 'anarchitecture-summon-0.1.0.tgz')}`, - '@anarchitecture/summon-server': `file:${join(tarballDir, 'anarchitecture-summon-server-0.1.0.tgz')}`, - '@anarchitecture/summon-react': `file:${join(tarballDir, 'anarchitecture-summon-react-0.1.0.tgz')}`, + '@anarchitecture/summon': `file:${core.tarballPath}`, + '@anarchitecture/summon-server': `file:${serverPackage.tarballPath}`, + '@anarchitecture/summon-react': `file:${react.tarballPath}`, react: '19.2.5', 'react-dom': '19.2.5', }, pnpm: { overrides: { - '@anarchitecture/summon': `file:${join(tarballDir, 'anarchitecture-summon-0.1.0.tgz')}`, + '@anarchitecture/summon': `file:${core.tarballPath}`, }, }, }, null, 2) + '\n'); @@ -49,15 +57,16 @@ run('pnpm', ['install', '--ignore-scripts'], projectDir); await writeFile(join(projectDir, 'smoke.mjs'), [ "import {", - " parseProtocolLine,", " createCapabilityRegistry,", " createComponentRegistry,", + " defineIntent,", " deriveSurfacePlanControls,", - " SectionAccumulator,", - " StreamGraph,", + " PolicyEngine,", "} from '@anarchitecture/summon';", "import { spawnSandbox, consumeSurfaceStream, createComponentIslandRegistry, createStrictInputRegistry } from '@anarchitecture/summon/browser';", - "import { PolicyEngine, defineIntent } from '@anarchitecture/summon/policy';", + "import { compileSystemContracts, parseProtocolLine, SectionAccumulator, StreamGraph } from '@anarchitecture/summon/engine';", + "import { spawnSandbox as hostSpawnSandbox, PolicyEngine as HostPolicyEngine } from '@anarchitecture/summon/host';", + "import { PolicyEngine as PolicyEngineFromPolicy } from '@anarchitecture/summon/policy';", "import { createSurfaceEnvelope, parseSurfaceEnvelope } from '@anarchitecture/summon/envelope';", "import { bootstrapSource, tokensSource } from '@anarchitecture/summon/assets';", "import { createEventStore } from '@anarchitecture/summon/devtools';", @@ -66,20 +75,24 @@ await writeFile(join(projectDir, 'smoke.mjs'), [ "", "const root = await import('@anarchitecture/summon');", "const server = await import('@anarchitecture/summon-server');", - "if (typeof parseProtocolLine !== 'function') throw new Error('core import failed');", "if (typeof createCapabilityRegistry !== 'function') throw new Error('capability import failed');", "if (typeof createComponentRegistry !== 'function') throw new Error('component import failed');", + "if (typeof defineIntent !== 'function' || typeof PolicyEngine !== 'function') throw new Error('policy helper import failed');", "if (typeof deriveSurfacePlanControls !== 'function') throw new Error('surface plan import failed');", - "if (typeof SectionAccumulator !== 'function' || typeof StreamGraph !== 'function') throw new Error('diagnostic primitive import failed');", + "if (typeof parseProtocolLine !== 'function' || typeof compileSystemContracts !== 'function') throw new Error('engine compiler import failed');", + "if (typeof SectionAccumulator !== 'function' || typeof StreamGraph !== 'function') throw new Error('engine diagnostic import failed');", "if (typeof spawnSandbox !== 'function' || typeof consumeSurfaceStream !== 'function') throw new Error('browser import failed');", "if (typeof createComponentIslandRegistry !== 'function' || typeof createStrictInputRegistry !== 'function') throw new Error('browser helper import failed');", - "if (typeof PolicyEngine !== 'function' || typeof defineIntent !== 'function') throw new Error('policy import failed');", + "if (typeof hostSpawnSandbox !== 'function' || typeof HostPolicyEngine !== 'function') throw new Error('host import failed');", + "if (typeof PolicyEngineFromPolicy !== 'function') throw new Error('policy subpath import failed');", "if (typeof createSurfaceEnvelope !== 'function' || typeof parseSurfaceEnvelope !== 'function') throw new Error('envelope import failed');", "if (typeof bootstrapSource !== 'string' || typeof tokensSource !== 'string') throw new Error('assets import failed');", "if (typeof createEventStore !== 'function') throw new Error('devtools import failed');", "if (typeof runSurfaceGeneration !== 'function' || typeof generateSurfaceStream !== 'function' || typeof resolveSurfaceGenerationPlan !== 'function' || typeof summarizeContractIssues !== 'function') throw new Error('server import failed');", "if (typeof SummonSurface !== 'function' || typeof defineReactComponent !== 'function') throw new Error('react import failed');", - "if ('spawnSandbox' in root || 'PolicyEngine' in root || 'compileSystemContracts' in root || 'createProtocolHardener' in root || 'buildDirectionBlock' in root || 'compileTokenContract' in root) throw new Error('core exposes implementation/runtime internals');", + "for (const forbidden of ['spawnSandbox', 'compileSystemContracts', 'buildCapabilitiesBlock', 'parseProtocolLine', 'StreamGraph']) {", + " if (forbidden in root) throw new Error(`root leaked ${forbidden}`);", + "}", "if ('buildEditBlock' in server) throw new Error('server exposes buildEditBlock');", "", "async function expectRejected(specifier) {", @@ -91,8 +104,6 @@ await writeFile(join(projectDir, 'smoke.mjs'), [ " throw new Error(`${specifier} should not be importable`);", "}", "", - "await expectRejected('@anarchitecture/summon/engine');", - "await expectRejected('@anarchitecture/summon/host');", "await expectRejected('@anarchitecture/summon/server');", "await expectRejected('@anarchitecture/summon/_internal/engine/index.js');", "await expectRejected('@anarchitecture/summon-server/_internal/server/index.js');", diff --git a/tsconfig.json b/tsconfig.json index a24a734..f55f9a2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -28,6 +28,8 @@ "@summon-internal/server": ["packages/server/src/index.ts"], "@anarchitecture/summon": ["packages/summon/src/index.ts"], "@anarchitecture/summon/browser": ["packages/summon/src/browser.ts"], + "@anarchitecture/summon/engine": ["packages/summon/src/engine.ts"], + "@anarchitecture/summon/host": ["packages/summon/src/host.ts"], "@anarchitecture/summon/policy": ["packages/summon/src/policy.ts"], "@anarchitecture/summon/envelope": ["packages/summon/src/envelope.ts"], "@anarchitecture/summon/assets": ["packages/summon/src/assets.ts"],