From f09ff61af360cadebc5a832815580d9b30b87356 Mon Sep 17 00:00:00 2001 From: Nahiyan Khan Date: Sat, 18 Jul 2026 02:11:26 -0400 Subject: [PATCH] chore: improve repository hygiene --- .github/workflows/release.yml | 6 +- .gitignore | 3 + CODEOWNERS | 26 +----- apps/docs/src/components/docs/icons.tsx | 25 ------ packages/context-control/README.md | 16 ++-- packages/context-control/cli.mjs | 4 +- packages/context-control/lib/model.mjs | 77 ++++++++---------- .../test/context-control.test.ts | 17 +++- packages/ghost/test/cli.test.ts | 80 ++++++++++--------- packages/vessel-react/fingerprint/.events | 2 - .../scripts/resolve-dts-paths.mjs | 4 +- 11 files changed, 109 insertions(+), 151 deletions(-) delete mode 100644 packages/vessel-react/fingerprint/.events diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b65ec986..73064207 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -89,9 +89,9 @@ jobs: echo "artifact_url=$artifact_url" } >> "$GITHUB_OUTPUT" - # Mirror block/sessh: mint a scoped token for the OSS Homebrew tap and - # trigger its bump-formula workflow so `brew install block/tap/ghost` - # tracks releases automatically. block -> block, no Square refs. Gated on + # Mint a scoped token for the OSS Homebrew tap and trigger its + # bump-formula workflow so `brew install block/tap/ghost` tracks releases + # automatically. Gated on # an actual publish and on the BLOCK_HOMEBREW_TAP_* secrets (GitHub App # installed on this repo), so forks and unconfigured environments skip it # cleanly instead of failing the release. diff --git a/.gitignore b/.gitignore index dbacff6b..73787dbc 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,6 @@ docs/superpowers/plans/ docs/superpowers/specs/ notes/ /demo/ +# Local Ghost selection event tapes +**/.ghost/.events +**/fingerprint/.events diff --git a/CODEOWNERS b/CODEOWNERS index 05435e95..b7aadb8c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,24 +1,2 @@ -# 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 +# Default owner for all files. +* @nahiyankhan \ No newline at end of file diff --git a/apps/docs/src/components/docs/icons.tsx b/apps/docs/src/components/docs/icons.tsx index 6517c562..be85559c 100644 --- a/apps/docs/src/components/docs/icons.tsx +++ b/apps/docs/src/components/docs/icons.tsx @@ -113,31 +113,6 @@ export const Icons = { /> ), - cashapp: (props: IconProps) => ( - - Cash App Logo - - - - ), paypal: (props: IconProps) => ( `. Trials run concurrently and sample at the - endpoint's default temperature — trial-to-trial variance is the signal - being measured, so it is not pinned to 0. +- `openai-compatible` — a real LLM behind any OpenAI-compatible chat API. + Configure `CONTEXT_CONTROL_BASE_URL`, `CONTEXT_CONTROL_API_KEY`, and + `CONTEXT_CONTROL_MODEL` in an untracked `.env` or `.env.local` at the + working directory. The CLI loads it on startup and makes this adapter the + default when all three values are present. Trials run concurrently and + sample at the endpoint's default temperature because trial-to-trial variance + is the signal being measured. Add providers to `MODEL_ADAPTERS` in `lib/model.mjs`. diff --git a/packages/context-control/cli.mjs b/packages/context-control/cli.mjs index 1af5b26f..39c0f1fd 100644 --- a/packages/context-control/cli.mjs +++ b/packages/context-control/cli.mjs @@ -6,8 +6,8 @@ import { resolve } from "node:path"; import { defaultGhostBin } from "./lib/ghost.mjs"; import { startServer } from "./lib/server.mjs"; -// Load .env from the working directory if present (DATABRICKS_HOST lives -// in an untracked .env / .env.local, same convention as the ghost CLI). +// Load optional model-adapter configuration from untracked env files, using +// the same convention as the ghost CLI. for (const envFile of [".env", ".env.local"]) { const envPath = resolve(process.cwd(), envFile); if (existsSync(envPath)) { diff --git a/packages/context-control/lib/model.mjs b/packages/context-control/lib/model.mjs index 2b03f47d..1c498313 100644 --- a/packages/context-control/lib/model.mjs +++ b/packages/context-control/lib/model.mjs @@ -8,14 +8,9 @@ // deliberately imperfect — it produces the speckle pattern the heatmap // exists to expose. Use it to exercise the UI loop. // -// - databricks: a real LLM behind a Databricks serving endpoint with an -// OpenAI-compatible chat API. This is the model actually under test: -// it sees the ask plus the menu (id, kind, description — exactly the +// - openai-compatible: a real LLM behind an OpenAI-compatible chat API. +// It sees the ask plus the menu (id, kind, description — exactly the // selection surface `ghost gather` emits) and returns node ids. -import { execFile } from "node:child_process"; -import { promisify } from "node:util"; - -const execFileAsync = promisify(execFile); const STOPWORDS = new Set([ "a", @@ -127,52 +122,47 @@ export function parseIdReply(text) { } } -/** - * Databricks serving-endpoint adapter (OpenAI-compatible chat API). - * Auth comes from the `databricks` CLI's cached OAuth token; the host - * comes from DATABRICKS_HOST. Nothing is stored. - */ -export function databricksModel({ - host = process.env.DATABRICKS_HOST, - endpoint = process.env.CONTEXT_CONTROL_ENDPOINT ?? "goose", +/** OpenAI-compatible chat adapter configured entirely through public env vars. */ +export function openAICompatibleModel({ + baseUrl = process.env.CONTEXT_CONTROL_BASE_URL, + apiKey = process.env.CONTEXT_CONTROL_API_KEY, + model = process.env.CONTEXT_CONTROL_MODEL, } = {}) { - if (!host) throw new Error("databricks model needs DATABRICKS_HOST"); - let tokenPromise = null; - const getToken = () => { - tokenPromise ??= execFileAsync("databricks", [ - "auth", - "token", - "--host", - host, - ]).then(({ stdout }) => JSON.parse(stdout).access_token); - return tokenPromise; - }; + if (!baseUrl) { + throw new Error("openai-compatible model needs CONTEXT_CONTROL_BASE_URL"); + } + if (!apiKey) { + throw new Error("openai-compatible model needs CONTEXT_CONTROL_API_KEY"); + } + if (!model) { + throw new Error("openai-compatible model needs CONTEXT_CONTROL_MODEL"); + } return { - name: `databricks:${endpoint}`, + name: "openai-compatible", async select({ ask, menu, cover }) { - const token = await getToken(); const res = await fetch( - `${host}/serving-endpoints/${endpoint}/invocations`, + `${baseUrl.replace(/\/$/, "")}/chat/completions`, { method: "POST", headers: { - authorization: `Bearer ${token}`, + authorization: `Bearer ${apiKey}`, "content-type": "application/json", }, body: JSON.stringify({ + model, messages: [ { role: "system", content: SELECT_SYSTEM }, { role: "user", content: selectUser(ask, menu, cover) }, ], - // Trial-to-trial variance is the signal being measured, so - // sample at the endpoint's default temperature; do not pin 0. + // Trial-to-trial variance is the signal being measured, so sample at + // the endpoint's default temperature rather than pinning it to zero. max_tokens: 1024, }), }, ); if (!res.ok) { throw new Error( - `databricks ${endpoint}: ${res.status} ${await res.text()}`, + `openai-compatible model: ${res.status} ${await res.text()}`, ); } const data = await res.json(); @@ -182,14 +172,14 @@ export function databricksModel({ } const MODEL_ADAPTERS = { - databricks: { - available: () => Boolean(process.env.DATABRICKS_HOST), - create: (name) => { - const endpoint = name.includes(":") - ? name.slice(name.indexOf(":") + 1) - : null; - return databricksModel(endpoint ? { endpoint } : {}); - }, + "openai-compatible": { + available: () => + Boolean( + process.env.CONTEXT_CONTROL_BASE_URL && + process.env.CONTEXT_CONTROL_API_KEY && + process.env.CONTEXT_CONTROL_MODEL, + ), + create: () => openAICompatibleModel(), }, "fake-lexical": { available: () => true, @@ -199,10 +189,9 @@ const MODEL_ADAPTERS = { /** Resolve a model name exposed by availableModels. */ export function resolveModel(name = availableModels()[0]) { - const key = name?.startsWith("databricks:") ? "databricks" : name; - const adapter = MODEL_ADAPTERS[key]; + const adapter = MODEL_ADAPTERS[name]; if (!adapter) throw new Error(`unknown model: ${name}`); - return adapter.create(name); + return adapter.create(); } /** Available adapter names in default order. */ diff --git a/packages/context-control/test/context-control.test.ts b/packages/context-control/test/context-control.test.ts index 7a13bbcd..81e3710e 100644 --- a/packages/context-control/test/context-control.test.ts +++ b/packages/context-control/test/context-control.test.ts @@ -4,7 +4,7 @@ import { join, resolve } from "node:path"; import { describe, expect, it } from "vitest"; import { initFingerprintPackage } from "../../ghost/src/scan/fingerprint-package.js"; import { parseAsks } from "../lib/bench.mjs"; -import { parseIdReply } from "../lib/model.mjs"; +import { openAICompatibleModel, parseIdReply } from "../lib/model.mjs"; import { consistency, jaccard, @@ -145,6 +145,21 @@ describe("demo asks", () => { }); }); +describe("openAICompatibleModel", () => { + it("requires portable endpoint configuration", () => { + expect(() => openAICompatibleModel({})).toThrow("CONTEXT_CONTROL_BASE_URL"); + expect(() => + openAICompatibleModel({ baseUrl: "https://models.example.com/v1" }), + ).toThrow("CONTEXT_CONTROL_API_KEY"); + expect(() => + openAICompatibleModel({ + baseUrl: "https://models.example.com/v1", + apiKey: "test-key", + }), + ).toThrow("CONTEXT_CONTROL_MODEL"); + }); +}); + describe("parseIdReply", () => { it("parses a bare JSON array", () => { expect(parseIdReply('["a", "b.c"]')).toEqual(["a", "b.c"]); diff --git a/packages/ghost/test/cli.test.ts b/packages/ghost/test/cli.test.ts index 064d1e52..4d090be5 100644 --- a/packages/ghost/test/cli.test.ts +++ b/packages/ghost/test/cli.test.ts @@ -1519,7 +1519,7 @@ describe("ghost CLI", () => { [ "relay", "gather", - "Code/Features/Lending/LendingUI", + "Sources/Features/Transfers/TransfersUI", "--package", ".ghost", "--format", @@ -1538,14 +1538,16 @@ describe("ghost CLI", () => { expect(json).toHaveProperty("stackDirs"); expect(json).toHaveProperty("brief"); expect(json.source.kind).toBe("package"); - expect(json.targetPaths).toEqual(["Code/Features/Lending/LendingUI"]); + expect(json.targetPaths).toEqual([ + "Sources/Features/Transfers/TransfersUI", + ]); expect(json.stackDirs).toHaveLength(1); expect(typeof json.brief).toBe("string"); expect(json.context.schema).toBe("ghost.relay-context/v1"); expect(json).not.toHaveProperty("context_packet"); expect(json.context.target).toMatchObject({ mode: "generation", - paths: ["Code/Features/Lending/LendingUI"], + paths: ["Sources/Features/Transfers/TransfersUI"], }); expect(json.context.sections.intent).toEqual( expect.arrayContaining([ @@ -1572,7 +1574,7 @@ describe("ghost CLI", () => { why_selected: expect.arrayContaining([ { kind: "linked_ref", - value: "inventory.exemplar:lending-tokenized-screen", + value: "inventory.exemplar:transfers-tokenized-screen", }, ]), }), @@ -1581,12 +1583,12 @@ describe("ghost CLI", () => { kind: "composition", }), expect.objectContaining({ - ref: "inventory.exemplar:lending-tokenized-screen", + ref: "inventory.exemplar:transfers-tokenized-screen", kind: "inventory", - path: "Code/Features/Lending/LendingUI", + path: "Sources/Features/Transfers/TransfersUI", why_selected: expect.arrayContaining([ - { kind: "path", value: "Code/Features/Lending/LendingUI" }, - { kind: "scope", value: "lending" }, + { kind: "path", value: "Sources/Features/Transfers/TransfersUI" }, + { kind: "scope", value: "transfers" }, { kind: "surface_type", value: "native-feature" }, ]), }), @@ -1602,9 +1604,9 @@ describe("ghost CLI", () => { expect(json.selected_context.suggested_reads).toEqual( expect.arrayContaining([ expect.objectContaining({ - path: "Code/Features/Lending/LendingUI", + path: "Sources/Features/Transfers/TransfersUI", reason: - "source surface for inventory.exemplar:lending-tokenized-screen", + "source surface for inventory.exemplar:transfers-tokenized-screen", }), ]), ); @@ -2227,7 +2229,7 @@ async function writeCheckPackage( `schema: ghost.fingerprint/v1 intent: summary: - product: Cash iOS + product: Harbor iOS situations: [] principles: - id: tokenized-ui-color @@ -2236,16 +2238,16 @@ intent: experience_contracts: [] inventory: exemplars: - - id: lending-tokenized-screen - path: Code/Features/Lending/LendingUI - title: Lending tokenized UI - surface: lending - why: Shows semantic CashTheme color usage for native lending UI. + - id: transfers-tokenized-screen + path: Sources/Features/Transfers/TransfersUI + title: Transfers tokenized UI + surface: transfers + why: Shows semantic HarborTheme color usage for native transfers UI. refs: - intent.principle:tokenized-ui-color - composition.pattern:tokenized-ui-color building_blocks: - tokens: [CashTheme.primary] + tokens: [HarborTheme.primary] components: [] composition: patterns: @@ -2257,7 +2259,7 @@ composition: options.checks === false ? undefined : `schema: ghost.validate/v1 -id: cash-ios +id: harbor-ios checks: - id: no-hardcoded-ui-color title: Use design tokens for UI color @@ -2266,9 +2268,9 @@ checks: derivation: intent: [intent.principle:tokenized-ui-color] composition: [composition.pattern:tokenized-ui-color] - inventory: [inventory.exemplar:lending-tokenized-screen] + inventory: [inventory.exemplar:transfers-tokenized-screen] applies_to: - paths: [Code/Features/Lending] + paths: [Sources/Features/Transfers] detector: type: forbidden-regex pattern: '${detectorPattern}' @@ -2277,8 +2279,8 @@ checks: support: 0.94 observed_count: 47 examples: - - Code/Features/Lending/LendingUI - repair: Replace literals with Arcade/Cash semantic tokens. + - Sources/Features/Transfers/TransfersUI + repair: Replace literals with Harbor semantic tokens. - id: candidate-density-check title: Candidate density check status: proposed @@ -2286,21 +2288,21 @@ checks: derivation: intent: [intent.principle:tokenized-ui-color] applies_to: - paths: [Code/Features/Lending] + paths: [Sources/Features/Transfers] detector: type: required-regex - pattern: 'CashTheme' + pattern: 'HarborTheme' evidence: support: 0.5 observed_count: 1 examples: - - Code/Features/Lending/LendingUI + - Sources/Features/Transfers/TransfersUI `, ); await writeFile( join(pkg, "resources.yml"), `schema: ghost.resources/v1 -id: cash-ios +id: harbor-ios primary: target: . `, @@ -2320,7 +2322,7 @@ primary: await writeFile( join(pkg, "patterns.yml"), `schema: ghost.patterns/v1 -id: cash-ios +id: harbor-ios surface_types: [] composition_patterns: [] `, @@ -2473,7 +2475,7 @@ checks: derivation: intent: [${intentRef}] applies_to: - paths: [Code/Features/Lending] + paths: [Sources/Features/Transfers] detector: type: forbidden-regex pattern: '#[0-9a-fA-F]{3,8}' @@ -2482,15 +2484,15 @@ checks: support: 0.94 observed_count: 47 examples: - - Code/Features/Lending/LendingUI + - Sources/Features/Transfers/TransfersUI `; } function mapWithScopes(): string { return `--- schema: ghost.map/v1 -id: cash-ios -repo: squareup/cash-ios +id: harbor-ios +repo: example/harbor-ios mapped_at: 2026-05-06T00:00:00.000Z platform: ios languages: @@ -2506,31 +2508,31 @@ composition: - design-tokens design_system: paths: - - Code/DesignSystem + - Sources/DesignSystem status: active surface_sources: render_strategy: static-source include: - - Code/Features/** + - Sources/Features/** exclude: - "**/Tests/**" feature_areas: - - name: lending + - name: transfers paths: - - Code/Features/Lending + - Sources/Features/Transfers scopes: - - id: lending - name: Lending + - id: transfers + name: Transfers kind: product-surface paths: - - Code/Features/Lending + - Sources/Features/Transfers orientation_files: - README.md --- ## Identity -Cash iOS. +Harbor iOS. ## Topology diff --git a/packages/vessel-react/fingerprint/.events b/packages/vessel-react/fingerprint/.events deleted file mode 100644 index 14a7fa82..00000000 --- a/packages/vessel-react/fingerprint/.events +++ /dev/null @@ -1,2 +0,0 @@ -{"ts":"2026-07-08T11:24:21.294Z","event":"gather","menu":["anti-goal.median","contract.theming","contract.tokens","index","pattern.conversation","primitive.composition","primitive.controls"],"wild":false,"wildIds":[]} -{"ts":"2026-07-08T11:24:37.764Z","event":"pull","ids":["primitive.controls"],"inlinedMaterials":11,"omittedMaterials":0} diff --git a/packages/vessel-react/scripts/resolve-dts-paths.mjs b/packages/vessel-react/scripts/resolve-dts-paths.mjs index f1945b37..d2b0255e 100644 --- a/packages/vessel-react/scripts/resolve-dts-paths.mjs +++ b/packages/vessel-react/scripts/resolve-dts-paths.mjs @@ -4,8 +4,8 @@ * real relative paths. tsc leaves the aliases verbatim; consumers can't * resolve them because they don't have the same tsconfig `paths`. * - * Tiny in-tree alternative to the `tsc-alias` npm package (which we can't - * reliably install through the Block artifactory right now). + * Tiny in-tree alternative to the `tsc-alias` npm package, avoiding an + * extra runtime dependency. */ import { readdir, readFile, writeFile } from "node:fs/promises";