Scrap and build v0.1.0 - #3
Merged
Merged
Conversation
…lth check endpoints - Add Drizzle ORM configuration for PostgreSQL database. - Create user role enum and users table schema. - Implement application structure with Hono framework for routing. - Add middleware for error handling, request context, and not found responses. - Develop user repository, service, and routes for CRUD operations. - Implement health check route to monitor server status. - Set up environment variable validation and configuration loading. - Create logging utility for structured logging. - Add TypeScript configuration and build setup with tsdown. - Include integration tests for user API endpoints.
…urce span tracking - Introduced `LocalVarId` and `VariableResolution` types in `Katari.Data.Id` for local variable identification and resolution. - Added `TypeResolution` data type to represent various type resolutions including data, requests, and generics. - Refactored `NormalizedType` to use `NormalizedBaseType` instead of `NormalizedTypeBase`, enhancing clarity in type representation. - Implemented `intersectType` and `intersectBaseType` functions for type intersection logic in `Katari.Data.NormalizedType`. - Created `SourceSpan` and `Position` types in a new `Katari.Data.SourceSpan` module to track source code positions and spans. - Added JSON serialization for `Position` and `SourceSpan` types. - Implemented utility functions for checking if a position is contained within a source span.
Phase-indexed AST (Katari.Data.AST) を仕様変更込みで完成させ、normalizer を含む型システム層を多角レビューに基づき修正。 AST: - agent 引数 `label => pattern` / request・external・primitive・data 引数 `label : type ?= default` / variable pattern のデフォルト引数 - spread 全廃、`agent type -> type`、matcher / request handler の generics - 単一 Located/Reference 系、retag ヘルパ一式、deriving stock 統一 型システム (Normalizer / Environment / Error): - generic 上限の既定を kind の top に(未登録 generic の空虚な subtype を防止) - effect override / bound 吸収の shadow セマンティクスを修正(guarantee 保持) - generic 引数の arity 検査 K3008 を normalize 境界に追加 - layer slot を Maybe + combineSlot/subtypeSlot に統一、object/sequence の 整列を combine/subtype で共有 - Environment を GenericParameterInfo(kind 込み)に集約、並列 map を解消 - Error にソース span を導入(Located + checker 境界付与方針)、派生可能な message を構造から描画 基盤: lazy RWS→CPS、Common を Data.Map.Merge へ、命名 typo/略称の一掃、 CI lint job に Haskell ツールチェーン追加、stub 削除。 compiler 52/0・hlint clean・ビルド警告ゼロ。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Severity / severityOf(typeErrorCode と並ぶ per-error 総関数、catch-all なしで列挙し将来のエラー追加に severity 決定を強制) - Diagnostics = Seq LocatedCompilerError(フェーズの writer monoid 想定) - finalizeDiagnostics(dedup + source 位置順)/ renderDiagnostics - emission ヘルパと module 分割は mtl が入る Identifier 着工時に行う方針 (それまで Error は純カタログのまま) compiler 54/0・hlint clean・ビルド警告ゼロ。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Katari.Diagnostics 新設: Error から Diagnostics 機構を移設し emission ヘルパ reportAt / capture / finalizeDiagnostics / renderDiagnostics を追加(mtl が 入るのでここで分離、Error は純カタログに復帰)。LocatedCompilerError synonym 削除 - Katari.Identifier: モナド骨格のみ(env/state / RWS 別名 / runIdentifier / fresh-id 供給 / scope lookup・with)。解決ウォークは未実装 - Katari.Panic: 内部エラー(不変条件違反)用の abort チャネル panic。Error と別系統 - emission は reportAt 一本(投機的 report は削除、bridge 着工時に転送形を追加) - tests: DiagnosticsSpec / IdentifierSpec / PanicSpec compiler 59/0・hlint clean・ビルド警告ゼロ。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- freshGenericId / freshLocalVariableId を get-then-put から MonadState の state コンビネータ一発に(src 唯一の非イディオム箇所、解決ウォークの雛形) - finalizeDiagnostics: ソートキーが Located 上で injective である不変条件を明記 - Error モジュールヘッダで Diagnostics(蓄積)/ Panic(内部中断)へ相互参照 レビュー結果: 正しさの欠陥ゼロ(capture / finalize / panic / fresh-id / scope 復元を実証検証)。compiler 59/0・hlint clean・警告ゼロ。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Katari.Data.Variant → Katari.Data.Variance に改名 (未使用 Polarity 削除)
- Phase コンストラクタ Zonked → Typed (型族4本 + コメント)
- 単一コンストラクタ record を data T = T {...} 通常構文へ統一
(SemanticType/NormalizedType/Error の計17型; sum 型は GADT 維持)
- kind の stringly-typed 表現を既存 GenericKind enum に統一
(kindOf/tellKindMismatch/substituteGenerics, renderGenericKind 追加)
- lint-fix scripts 追加 (hlint --refactor / biome --fix);
一部 error-info を newtype 化
警告ゼロ (-Wall -Wcompat 他) ・compiler-test 59/59 green
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ricArgumentsを追加し、UseStatementを新規作成。型注釈を強化し、コメントを更新。
…on and attribute handling - Enhanced the Identifier module to define the module interface and import context for name resolution. - Introduced new data types for exported symbols and module interfaces. - Updated the Normalizer module to refine attribute handling, ensuring attributes are not distributed into invariant data arguments. - Improved subtype comparisons by incorporating a contextual "world" for attribute visibility. - Adjusted tests to reflect changes in attribute handling and subtype relationships. - Updated package.json scripts for more granular type checking and added CLAUDE.md for documentation.
…EffectRowにtailsフィールドを追加し、効果の正規化およびサブスティテューションのロジックを改善。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CompilerError を Parse(K1)/Identifier(K2)/Type(K3)/Lowering(K4) の phase 圏に拡張。Identifier 後に解決済み名が環境/宣言に無いのは不変条件違反なので UnknownData/Request/Generic(K3002-3004) を削除し Katari.Panic へ。dataInfoFor/requestInfoFor を非 Maybe 化。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Parser / Identifier(scan+identify) / Environment(global buildEnvironment) / Check / Lowering / Schema の I/O を stub で固定し Katari.Compile で結線。IR は Data.IR の placeholder。runtime が module 毎にアップロードするため link は無し。中身は後続で実装。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lexer/Type/Pattern/Expression/Parser に分割した recursive-descent parser。 中身は全 stub だった Katari.Parser を本実装に置換。 - 文境界でだけ改行を有意化 (旧 compiler のバーチャルセミコロン相当)。 line/multiline の 2 space-consumer を Reader の spaceMode で切替、 演算子トークンは常に改行を食う (行末演算子で継続 = Go ルール)。 - 区切り記号: 分配束縛 =>、値割当 =、戻り ->。関数型は agent kw 必須。 generic upper-bound は [T extends Bound] (記号も予約語も増やさない)。 - use はブロック残りを継続 body として束縛 (collectBlockItems が再帰)。 - next/break は Reader の loopContext で for/handler 版に振り分け。 - 宣言レベル error recovery: 壊れた宣言を DeclarationError sentinel に 置換し列 1 の宣言キーワードへ同期、診断は State に蓄積して全件返す。 - megaparsec label で declaration/expression/type/pattern のエラー改善。 - ParserSpec で hello/算術/data+match/for/handler/use/import/narrowing/ generics/recovery 等を網羅 (91 examples green, ormolu/hlint クリーン)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Added `Katari.Identifier.Pattern` module for resolving patterns, including variable, wildcard, literal, tuple, type-filter, record, and constructor patterns. - Introduced functions to resolve field patterns and constructor references. - Created `Katari.Identifier.Type` module for resolving type-level syntax, including primitive types, agents, applications, tuples, unions, and objects. - Implemented generic parameter handling and resolution within the type system. - Updated the parser to correctly handle source spans for module names and type references. - Enhanced the identifier tests to cover new functionalities, including diagnostics for undefined names and duplicate declarations. - Improved symbol table visibility checks in the identifier tests.
- qualified-or-bare の名前解決を resolveQualifiedReference に共通化 (type-name / constructor / request-handler の3重複を解消) - 重複検出を declarationBindings から駆動し TopLevelName を削除 (名前空間分類の二重定義・resolveModule の二重走査を解消) - Identifier テストの診断 assertion を shouldBe に厳格化 - then 節の with-state / 値読みの正しい挙動を回帰テストで固定 挙動はリファクタ前と一致。compiler テスト 127/0 green。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…境を追加 Typechecker.Check を Katari.Typechecker に昇格し、Parser/Identifier と同じ 「トップ entry + 同名ディレクトリに helper」規約に揃える。 TypeEnvironment を 4 環境に拡張 (buildEnvironment 本体は引き続き stub): - valueEnvironment: agent/external/primitive を「top-level の agent 型を 持つ変数」として統一的に扱う (cross-module 参照を 1 lookup で型付け) - synonymEnvironment: 型シノニムを env-builder が収集・展開・循環検出。 kind-agnostic なので definition は NormalizedGenericArgument Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Introduced `ModuleName` utility functions for constructing module names from segments, extracting last segments, and checking module coverage. - Enhanced `IdentifierError` to include a new error for reserved module names, with appropriate diagnostics. - Updated the identifier resolution process to support desugaring of binary and unary operators into calls to the `primitive` module, ensuring operators are resolved without needing import context. - Added a new `JSONSchema` representation for runtime schema requirements, including serialization to JSON. - Created a `Primitive` module to define the mapping of operators to their corresponding primitive functions. - Embedded the `primitive` module source into the compiler, ensuring operators are correctly desugared during the identification phase. - Implemented tests for the standard library to verify the correct embedding and operator desugaring behavior.
- Introduced SQL schema for runtime components including tables for blobs, scopes, threads, delegations, escalations, external calls, instances, runs, and environment entries. - Implemented TypeScript definitions for database tables and runtime engine types, including instances, threads, scopes, and value models. - Established relationships between tables with foreign keys to maintain data integrity. - Added JSON type definition for arbitrary JSON values used in runtime schemas and values.
- Updated type names in NormalizerSpec for clarity and consistency. - Added tests for subtype relationships between tuples and arrays, ensuring correct handling of fixed-length and variable-length types. - Enhanced object subtype tests to verify behavior with additional fields. - Improved normalization and denormalization tests for semantic types, ensuring accurate round-tripping. - Refactored database schema to remove the scope_variables table, integrating its functionality into the scopes table with a new values column. - Updated foreign key constraints and added indexes for improved query performance. - Removed health check routes and adjusted API surface to reflect current module structure. - Enhanced TypeScript types for better clarity and added new default pattern matching functionality. - Enabled strict TypeScript checks with noUncheckedIndexedAccess for improved type safety.
…lity - Simplified the Normalizer module by removing the traverseArguments function and integrating its logic directly into the substituteType function. This change enhances readability and reduces complexity in handling argument traversal. - Updated the substituteAttribute function to streamline the absorption of replaced generics, improving the overall structure and maintainability of the code. - Fixed a bug in the referencesInExpression function within the ValueGraph module to ensure correct handling of record entries, enhancing the accuracy of expression reference analysis. - Clarified comments in EnvironmentSpec to better explain the distinction between generic ids in different modules, ensuring clearer understanding of the variance fixed point mechanism.
…escalation history typescript/admin-web (@katari-lang/admin-web, Vite + React 19 + Tailwind 4 + react-query): projects / dashboard / runs / run detail / agents / agent invoke / escalations / snapshots / files / env / settings, against the current runtime API. Semantic color tokens over CSS variables give one-class theming (light / dark / system, no dark: twins); components split atomic (ui/) vs domain (runs/, escalations/, agents/, values/, schema-form/), padding-first spacing throughout. Beyond main's console: an escalation inbox with a live sidebar badge and in-place answering (schema-driven form, never-typed throws flagged unanswerable), a run page that shows open questions inline plus the answered Q&A transcript, re-run with the same argument, a snapshots page with the head manifest, per-row reveal for non-secret env values, and a ValueViewer fluent in the wire's $constructor / $ref (downloadable) / $agent / $closure / $redacted shapes. Polling is condition-driven (2.5 s while anything is live, quiet otherwise); a route-keyed error boundary keeps the shell alive if a page throws. runtime: GET /projects/:id/runs/:id/escalations serves the run's answered-escalation transcript from run_escalations_audit (unseal + redact like the run's own argument / result) — the only read the console needed that the API did not yet expose. The delegation tree stays out, as agreed, until the runtime-side work lands. Verified live against the running runtime in headless Chrome: projects, dashboard, runs, an errored run's typed-throw payload, agent invoke form, snapshots, and env all render with real data; 199 runtime tests, tsc, and biome are green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Address the high-effort code review, plus a base-reactor refactor. Correctness: - Conform an external (FFI/http) call's RESULT against the callee's declared output schema, core-side in onDelegateAck (the one seam with the IR, the wrapper instance's schema, and its generics). A violation fails the run as a panic at the proxy, rather than a wrong-typed value corrupting a match later. - Guard the client-JSON acceptance surfaces (run start, escalation answer) with decodeClientJson: a malformed decode is now a 400, not a 500. - Bound prelude.array.range so an over-large (possibly AI-supplied) span can no longer stall or OOM the serial actor turn. - onEscalate drops during the completion drain window (pendingOutcome set), symmetric with openInnerDelegation, so no relay is orphaned. Cleanup / refactor: - send(event, issuer) takes the issuing instance explicitly; applySendEdge is folded into send and the currentTurnOwner / turnInstance / turnOwnerId ambient is removed. - Base reactor gains an issuedByCaller reverse index (the delegation-tree wiring): issuedDelegationsOf / hasIssuedDelegations / issuedRowOf are now O(children), not full-map scans; the ffi inner-call bridges get a parent index too. - Shared isFailureRequest predicate (escalation-filter); the wire-codec constants + $-key escaping move to @katari-lang/types/wire.ts, imported by both the runtime codec and the FFI port (no more hand-mirrored lockstep). - Port: narrow the aborted pre-check to the expected KatariCancelledError (a genuine cleanup failure now hits the diagnostic again); use node:crypto randomUUID. Tests: runtime 199 (+ output-conform, range bound, undecodable-answer 400). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Panic becomes catchable via a special ambient clause, while staying unraisable. The runtime needs no change (handleAsk already matches prelude.panic by string, and panic already bubbles as a prelude.panic ask); the whole feature is in the compiler front-end: - Katari.Primitive: the wired-in panicRequestName (prelude.panic). - Check.walkRequestHandler: recognize a bare `panic` clause structurally (it is undeclared, so it never resolves) and type it from a synthetic `panic(msg: string) -> never` signature. - Check.checkHandlerScheme: EXCLUDE the panic clause from the continuation's overwrite effect row — this is what makes it ambient (addable to any handler), and is required: an undeclared request in an effect-row type would break variance lookups. - Lowering.lowerRequestHandler: lower the panic clause to prelude.panic. - Identifier.resolveRequestHandler: leave the bare `panic` reference unresolved without reporting an undefined-name error (undeclared by design). Recovery is via `break` only (-> never, like throw). This also gives programs a way to catch an interrupted-FFI panic and retry. Tests: PanicSpec (5) + a LoweringSpec case (lowers to prelude.panic); compiler 533. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
One run's live delegation tree: who summoned whom, right now. The read side follows the escalation-list precedent — it reads the Layer 1 rows (delegations + instances + kind extensions + escalations) directly, the same durable mirror every reactor's warm issuedByCaller / handled indexes are rebuilt from on recovery, so the API and the engine always agree and no reactor is loaded just to look at a run. - Edges compose as the base reactor documents them: callee instance = instances.delegation_id, children = delegations.caller_instance_id. - Node labels from the kind extensions: core = target (agent name / closure), ffi = dispatch key; http keeps no request, so the node falls back to its reactor kind. ffi/http surface their own status (awaitingAnswer), which the envelope cannot express. - Open escalations attach to their raiser, one row per bubble hop; `answerable` marks the api-addressed leg (the one the answer surface accepts), so the badged path in a UI leads to the waiting origin. - Pure assembly (assembleDelegationTree) + project-scoped selects; a visited guard degrades corrupt rows to a truncated tree, never a hang. Terminal run => tree null (the rows are pure live routing). Live-verified: interactive escalation run shows main → panel → two parallel consult → ask chains with per-hop questions; answering both completes the run and the tree returns to null. Tests: delegation-tree (6) — runtime 211. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ri-lang/types Run page: a live "Delegation tree" card while the run is in flight — each node is one delegation edge with its instance's label (agent / closure / external key, falling back to the reactor kind), a status badge (running / cancelling / awaiting answer / pending while the delegate is still in flight), and the open questions it raised; the api-addressed leg is highlighted and relay hops are marked, so the badged path leads to where the run is actually waiting. Polls with the run and disappears on terminal (the rows are live routing). Wire-convention catch-up: the runtime moved the value-wire constants + $-key escaping into @katari-lang/types (wire.ts), shared with the codec and the FFI port. The console now imports the same definition — ValueViewer dispatches variants through wireKindOf and unescapes keys with unescapeRecordKey, SchemaForm builds file/agent references from FILE_KEY/AGENT_KEY/..., RunDetailPage checks REDACTED_KEY — so a fourth hand-mirrored copy of the convention is gone. Live-verified in headless Chrome against the running runtime: the interactive playground run renders main → panel → two parallel consult → ask chains, with inline answering completing the run. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…discord_bot
Five single-feature examples (agent-tools, ffi-hello, ffi-blob,
ffi-inner, ffi-throw) fold into examples/playground, one module per
concern, every entry live-verified against the running runtime:
- basics — data/match, for (map + accumulator), parallel for,
stateful inline handlers, prelude sampling
- tools — agents as AI tools (schema derivation, typed JSON
boundary, dynamic dispatch); the old agent-tools
- errors — throw[T] raised + caught, and the ambient panic clause
catching a live runtime failure (missing env entry)
- interactive — escalation: parallel consults each holding an open
ask; the delegation-tree showcase
- ffi + ffi.ts — all four boundary shapes in one sidecar (plain
values, file both directions, inner delegation, typed
throw)
examples/discord_bot is main's bot ported to the current language:
match arrows / `=>` field patterns, `external agent` (no from-string),
`secret` -> `string of private`, typed throws (prelude.throw[T]) with
a union catch clause, env_not_found handler -> the ambient panic
clause, `session_provider` returning a handler -> inline use handler,
and the custom http_post sidecar replaced by a thin post_json over the
built-in http.fetch (one fewer FFI surface). Tool dispatch drops
tool_index for a metadata-name scan (variable patterns do not narrow
`T | null`). Compiles clean (18 modules) and bundles + deploys.
Adaptation notes: `io` has no surface spelling, so agents that perform
io leave their effect row to inference (an explicitly annotated row
cannot call an external today); a pure recursive group is annotated
with `prelude.throw[never]` as the empty upper bound.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ix workflows Version model: haskell/cli/VERSION is a one-line file, the single user-visible version of the CLI — `cliVersion` embeds it at build time (file-embed, like the init templates) so `katari --version` and the registry compiler-pin warning speak it; the cabal `version:` fields stay X.Y.Z.0 placeholders (cabal cannot carry a pre-release suffix). The pin comparison strips a pre-release suffix before taking the release triple, so an rc CLI still matches a stable registry pin. Scripts (versions-common.mjs shares the format + package enumeration): - stamp-version — rewrite VERSION + every haskell package.yaml + every typescript package.json to one version, before tagging. - verify-versions — the release precheck: cross-check all of the above against the pushed tag; every workflow gates on it. - stage-binary-packages / bump-versions — publish-time only: wrap the released binaries as @katari-lang/cli-<platform> and inject them into the shim's optionalDependencies (the committed tree stays installable before the first publish). Workflows (tag-triggered, all gated on verify-versions): - release-katari — build the CLI per platform (linux-x64, darwin-arm64), attach tarballs + sha256 to the GitHub Release. - release-npm — on release-katari success: build the workspace, download the binaries, publish types/port/runtime/bundle, the platform packages, then the cli shim, under a dist-tag derived from the pre-release identifier. OIDC Trusted Publishing, no npm secret. - release-katari-runtime — the server image to ghcr.io/<owner>/katari (amd64+arm64); :latest only moves on stable. - release-vsix — package the editor extension and attach the .vsix. Verified: stamp/verify round-trip both directions with zero residual diff; stage+bump dry-run against local tarballs; katari --version reports 0.1.0-rc6 from the embedded file; cli tests + hlint + ormolu clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…node_modules/.bin Setup friction, removed at its three sources: - KATARI_BUNDLE_BIN: gone for dev. `katari apply` already resolved a project-local node_modules/.bin/katari-bundle by walking up from the project root, but ran whatever it found through `node` — correct for npm (a symlink to the JS entry) and a SyntaxError for pnpm (a POSIX launcher script). Canonicalize first: a JS target runs through node, anything else executes directly. The examples add @katari-lang/bundle as a devDependency — exactly what a user project would do — so the workspace install wires the bundler up by itself. - Runtime env: the dev script loads .env files with node's own --env-file-if-exists (the built-in that replaced dotenv) — the repo's top-level .env first (shared with docker compose's substitution), then a package-local one, real environment winning over both. The loading is visible in the script line and ships nowhere: `start` and the container image take real environment only, and no env-file code exists in the app. A top-level .env.example documents every knob and the one-time key generation line. - KATARI_API_URL: already unnecessary for the examples (katari.toml's [runtime].url) — the READMEs now say so instead of exporting it. Live-verified end to end with zero exported variables: fresh default database, `pnpm --filter @katari-lang/runtime dev` boots from the top-level .env, `katari apply` + `katari run basics.main` both succeed from a bare shell in examples/playground. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ro-setup dev
The runtime image now serves the admin console, local dev gets a real
S3 path, and the whole stack comes up with one command.
Console in the image:
- The runtime serves the built console at the root (/) alongside the
JSON API (/api/v1) — one origin, no proxy. A new admin-web middleware
serves the static dist with an /api guard and an index.html history
fallback; when KATARI_ADMIN_WEB_DIST is unset (a source checkout) the
root stays the JSON info and the console runs from its own vite dev
server. The Dockerfile builds admin-web in the build stage and bakes
its dist in, defaulting the env at it.
- The runtime is now a self-contained application bundle: tsdown inlines
its one workspace dep (@katari-lang/types — types + the wire
constants), so `pnpm deploy` never ships raw TypeScript the image
cannot execute. It emits JS only (nothing imports its types), and
@katari-lang/types drops to a devDependency.
S3 blob store for dev:
- compose.yaml gains an adobe/s3mock service (the maintained successor
to MinIO OSS for local testing); the dockerized runtime points its
blob store at it. S3BlobStore.ensureBucket creates the bucket on boot
(idempotent, gated by BLOB_S3_CREATE_BUCKET) with a bounded retry so a
just-started mock is tolerated — real AWS leaves it off.
Zero-setup dev:
- `pnpm run dev` brings up postgres + s3mock (compose) and runs the
runtime + console in parallel (pnpm --parallel). The runtime reads the
top-level .env via node's --env-file-if-exists. The dev .env.example
is trimmed to the one required key plus the S3 pointer.
Self-host template:
- `katari init` scaffolds a compose.yaml wired to the published GHCR
image (pinned to the CLI's version via a new {{version}} template
placeholder) with Postgres + durable SeaweedFS (OSS, not the
deprecated MinIO). Its env.example and README match.
Live-verified end to end: `docker compose up` → the console at
http://localhost:3000/ (assets + SPA deep-link fallback), /api/v1
health, and a file-blob round-trip (ffi.main → bytes=13) through
s3mock, all inside the built image; and the host `pnpm run dev` flow
with the same S3 path. runtime 205 tests + tsc + biome + ormolu clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…_API_KEY The API is authenticated in v0.1.0. A caller sends `Authorization: Bearer <KATARI_API_KEY>`; the runtime rejects anything else with 401. - The key is separate from KATARI_SECRET_KEY (which only encrypts secrets at rest): KATARI_API_KEY is the auth token, KATARI_SECRET_KEY the at-rest cipher key. Both are required at boot — the runtime refuses to start without either, so an API is never accidentally left open and secrets are never left unencrypted. - Auth is always on (no opt-out). The middleware exempts exactly two things, because neither can carry the header: /api/v1/health (the container healthcheck / uptime monitors) and every non-/api path (the console's own static assets — a browser can't attach Authorization to a <script>). The comparison is constant-time. - The CLI already reads KATARI_API_KEY and sends it as a Bearer token, so it needed no change; a missing/wrong key now surfaces as a clean 401. - The console gains a login gate: it renders normally and only interposes a login screen when a request comes back 401 (a query poll or a mutation), validates the entered key against a protected endpoint before letting the app back in, and stores it for the Bearer header. Settings gains sign-out (clear the key). - `katari init` scaffolds a compose.yaml + .env.example that require KATARI_API_KEY (alongside the existing KATARI_SECRET_KEY); the dev compose + .env.example require it too. The CLI reads it from the environment, so the example READMEs export it from the repo `.env`. Live-verified: runtime refuses to boot with no KATARI_API_KEY; with it set, no-key/wrong-key requests 401 while the right key and /health pass; the CLI works with the key and errors cleanly without; the built console served by an auth-on runtime loads publicly and shows the login screen on the first 401. runtime 212 tests (+auth, +api-key config) + tsc + biome + ormolu clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Retarget the semantic color tokens to main's palette (highlight / katari / paper + danger / success / warning), so the whole console recolors from one place: cyan `highlight` becomes the primary accent, neutrals become the warm paper / katari scales, and each `-soft` tint is a translucent wash of its base. Drop rounded corners and shadows everywhere (the Switch keeps its rounded-full track, as on main), square + uppercase the Badge, and remove the top-bar and sidebar separators to keep lines minimal. Restore the missing logo: add public/katari.svg + favicon.svg, a Logo component (masked glyph + wordmark + Console tag), and load fonts in index.html — the KATARI wordmark is Montserrat, body is DM Sans, mono is DM Mono. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rowing Add `io` (the external-call effect) and `pure` (the empty effect) as surface type keywords alongside `all` / `never`, threaded through the AST, parser, identifier resolution, query facts, and elaboration (SemanticEffectIo / SemanticEffectPure), plus editor highlighting. An agent can now spell `with io` or `with pure` directly instead of the `throw[never]` workaround. Narrow a later match arm's variable / wildcard binder to the residual scrutinee after earlier arms' covers are subtracted (`subtractCover`): `case null` then `case rest` binds `rest` at the non-null residual — the in-language way to fold a nullable. A refutable arm still sees the full scrutinee, so exhaustiveness and every cover are unchanged; the residual only over-approximates, keeping it sound. Adopt both in the discord_bot example (`with pure`, a null-narrowed `or_null`, and `json.decode[unknown]` replacing the removed `jsonx.to_value`). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the hardcoded dev-default secret key from compose.yaml so the value comes from the environment (a root `.env`), and gitignore `/.env` so that file never lands in the repo. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Remove the pnpm `minimumReleaseAgeExclude` entry for hono@4.12.24; the pin is no longer needed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…DMIN_WEB_DIST Whether the runtime serves the web console was a configured path (KATARI_ADMIN_WEB_DIST) that only ever held one value — the image's baked-in dist. Replace the knob with a fixed path next to the runtime (`admin-web/dist`, relative to the working directory) and a presence check: the image copies the console there, so it appears with no configuration; a source checkout has no such directory, so the runtime serves only the JSON API and the console runs from its vite dev server. `mountAdminWeb` now returns whether it mounted, and the Dockerfile drops the ENV. Live-verified: the built image serves the console at / with no KATARI_ADMIN_WEB_DIST in its environment (health public, the API still 401s without the key); a source-checkout runtime serves the JSON info root instead. runtime 212 tests + tsc + biome clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`collectEntries` now returns each callable's whole `AgentBlock` (not just its `SchemaInfo`), so the agent list / detail endpoints can carry the declaration's `@"..."` description alongside its schemas. The IR already stamps `AgentBlock.description`, so this is pure read-path plumbing; `deriveAnswerSchema` and the escalation answer-schema lookup are updated for the wider entry type. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The project `readme` column existed but nothing ever filled it, so the console's README card never showed. Wire the pipeline end to end: - runtime: add `PATCH /projects/:id` (`updateProjectSchema` / repository.update / service.update) that partially updates description + readme (null clears, omitted leaves untouched); - cli: `katari apply` reads the project's `README.md` and sends it — creating a project with it, and updating an existing project's description + README on every deploy so they track the source. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Design: adopt main's type / control language — Lexend (Tera) display face + DM Sans / DM Mono via the font tokens, a global pointer cursor on clickables, `color-scheme` pinned per theme so native controls (number stepper, <select> popup) render in the right palette, teal Lexend page titles, uppercase table heads, and a chevron affordance on the (previously arrow-less) Select. Restored / improved views: - Agents: a collapsible folder tree with two-line rows showing each agent's description. - Schema: a structured visualizer (type badges, left-border nesting, required / union / enum / array / reference / never) replacing the flat text dump. - Dashboard: render the project README as themed markdown (MarkdownContent — inline element styles, no `@tailwindcss/typography` dependency). - Snapshots: a per-row link into that snapshot's agent list. - ValueViewer: nest straight down with a fixed indent (constructor tag as a header, fields below-left) instead of stepping right by each label / tag width. - Escalations: optimistically drop an answered escalation from the inbox instead of waiting a poll. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…button The agent detail page renders the callable's `@"..."` description (as themed markdown, inline code and all) below the header, and the Invoke panel gets a Paste button that fills the argument form from a JSON value on the clipboard. Pasting revealed two stale-field bugs in the schema form, now fixed: the argument form remounts on paste so fields with their own state (the raw-JSON buffer) re-read the pasted value, and a union field derives its initial branch from the value (matching a constructor by its `$constructor` tag) instead of always opening the first branch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Appearance already lives in the top bar and the only other Settings function was changing the API key, which logging out + the login screen covers — so drop the Settings page and route, and add a top-bar user menu showing the runtime the console is signed in to plus a Log out action (clears the key and re-arms the auth gate). Give the top bar `relative z-40` so the menu isn't trapped under page content: its `backdrop-blur` makes it a stacking context, so the menu's own z-index only ordered within the bar and page `<select>`s painted over it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…f panicking A missing secret is an anticipated configuration failure (an optional integration, a default) that a program should be able to recover from, not a broken invariant. Move it onto the typed-error channel: `get_secret` now throws `env.missing_secret(key, message)` — the key rides along so a fallback handler can branch on which secret is absent. Uncaught, the throw still fails the run, so required-config behaviour is unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ommit) Files (api-root-owned blobs) had no reclamation path — the byte-reclaim machinery already existed (ResourcePool.reclaimedBytes → the substrate deletes the BlobStore bytes strictly after the commit), but nothing let a user free a file. Add DELETE /projects/:id/files/:fileId on top of that machinery: `pool.deleteBlobOwnedBy` frees only an api-root-owned blob (never an in-flight FFI call's mid-call upload), staging its row deletion this turn and its bytes for the post-commit reclaim. A run still holding the deleted file's ref reads it as gone — the explicit delete is the user's call. Wires the consumers to match: `katari file delete` (with id-prefix resolution) and the admin console's Files page delete button. Drops the now-unused NotImplementedError. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ete teardown Three rc6-hardening changes to the runtime lifecycle that share the facade / registry / actor seam: - FFI blob side-channel auth: the sidecar's blob upload / download runs against the runtime's authenticated `/api`, but it sent no bearer and was never handed the key — every blob op 401'd on an auth-enforced (i.e. every real) runtime. The runtime now passes the API key to the sidecar as env and the port's blob client sends `Authorization: Bearer`. - Boot-time run recovery: reactivation was lazy (a project reloaded only when next touched), so after a restart a long-running run stayed suspended until external traffic happened to arrive. `bin.ts` now calls `activateInFlightProjects` once the server is listening, resuming every project that holds a non-terminal run — fault-isolated per project. - Project-delete teardown: deleting a project now evicts its warm actor (killing its sidecars, aborting in-flight http, rejecting its run promises via the new transport `close()` methods), then frees the blob bytes its rows referenced from the store — the last orphan path the DB cascade left behind. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ction Snapshots are immutable and the head is just a pointer, so a rollback is a head move — the storage already allowed it, but no surface exposed it (the doc marked the endpoint as follow-up work). Add `PUT /projects/:id/snapshots/head` (validates the snapshot exists, then moves the head under the same project-row lock a deploy takes), the `katari project rollback SNAPSHOT` command (id-prefix resolution like the other id args), and a "Make head" action on the console's Snapshots page. A run pins the snapshot it started on, so only new runs follow the moved head; nothing in flight is touched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The unit suites mock each layer, so nothing exercised the wire between the Haskell compiler's IR/schema output and the TypeScript runtime — the gap that hid the FFI blob 401. This adds `e2e/`: it compiles examples/playground with the stack-built katari CLI (compile + sidecar bundle + deploy over HTTP) and drives a real runtime server (compose postgres + s3mock) through runs, files, escalations, a snapshot rollback, and a mid-run server restart (asserting the boot-time resume). It provisions and drops its own database and bucket, and is not part of `pnpm run test` (it needs docker + a Haskell toolchain); run it with `pnpm run test:e2e`. Also ignores nested workspace-package node_modules. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.