From 31b9fc163948897a079b052708ff8c858bb2db03 Mon Sep 17 00:00:00 2001 From: Mikkel Georgsen Date: Mon, 30 Mar 2026 22:32:47 +0200 Subject: [PATCH] feat(01-foundation-01): scaffold branding package with VOCAB constant and tests - Create packages/branding/ workspace package (@paperclipai/branding) - Add VOCAB constant with 8 Nexus display strings (company, companies, ceo, board, hire, fire, appName, tagline) - Export VocabKey type for type-safe string lookups - Add vitest config and 9 passing unit tests covering all VOCAB values - Update pnpm-lock.yaml to link new workspace package --- packages/branding/package.json | 34 ++++++++++++++++++++++++++++ packages/branding/src/index.ts | 1 + packages/branding/src/vocab.test.ts | 35 +++++++++++++++++++++++++++++ packages/branding/src/vocab.ts | 15 +++++++++++++ packages/branding/tsconfig.json | 8 +++++++ packages/branding/vitest.config.ts | 7 ++++++ pnpm-lock.yaml | 6 +++++ 7 files changed, 106 insertions(+) create mode 100644 packages/branding/package.json create mode 100644 packages/branding/src/index.ts create mode 100644 packages/branding/src/vocab.test.ts create mode 100644 packages/branding/src/vocab.ts create mode 100644 packages/branding/tsconfig.json create mode 100644 packages/branding/vitest.config.ts diff --git a/packages/branding/package.json b/packages/branding/package.json new file mode 100644 index 00000000..bb0a12b4 --- /dev/null +++ b/packages/branding/package.json @@ -0,0 +1,34 @@ +{ + "name": "@paperclipai/branding", + "version": "0.1.0", + "license": "MIT", + "type": "module", + "exports": { + ".": "./src/index.ts", + "./*": "./src/*.ts" + }, + "publishConfig": { + "access": "public", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + }, + "./*": { + "types": "./dist/*.d.ts", + "import": "./dist/*.js" + } + }, + "main": "./dist/index.js", + "types": "./dist/index.d.ts" + }, + "files": ["dist"], + "scripts": { + "build": "tsc", + "clean": "rm -rf dist", + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "typescript": "^5.7.3" + } +} diff --git a/packages/branding/src/index.ts b/packages/branding/src/index.ts new file mode 100644 index 00000000..9611f5da --- /dev/null +++ b/packages/branding/src/index.ts @@ -0,0 +1 @@ +export { VOCAB, type VocabKey } from "./vocab.js"; diff --git a/packages/branding/src/vocab.test.ts b/packages/branding/src/vocab.test.ts new file mode 100644 index 00000000..73e576d2 --- /dev/null +++ b/packages/branding/src/vocab.test.ts @@ -0,0 +1,35 @@ +import { describe, it, expect } from "vitest"; +import { VOCAB } from "./vocab.js"; + +describe("VOCAB", () => { + it("maps company to Workspace", () => { + expect(VOCAB.company).toBe("Workspace"); + }); + it("maps companies to Workspaces", () => { + expect(VOCAB.companies).toBe("Workspaces"); + }); + it("maps ceo to Project Manager", () => { + expect(VOCAB.ceo).toBe("Project Manager"); + }); + it("maps board to Owner", () => { + expect(VOCAB.board).toBe("Owner"); + }); + it("maps hire to Add", () => { + expect(VOCAB.hire).toBe("Add"); + }); + it("maps fire to Remove", () => { + expect(VOCAB.fire).toBe("Remove"); + }); + it("has appName as Nexus", () => { + expect(VOCAB.appName).toBe("Nexus"); + }); + it("has a non-empty tagline", () => { + expect(VOCAB.tagline).toBe("Open-source orchestration for your agents"); + }); + it("all values are non-empty strings", () => { + for (const [key, value] of Object.entries(VOCAB)) { + expect(typeof value, `key "${key}" should be a string`).toBe("string"); + expect(value.length, `key "${key}" should be non-empty`).toBeGreaterThan(0); + } + }); +}); diff --git a/packages/branding/src/vocab.ts b/packages/branding/src/vocab.ts new file mode 100644 index 00000000..d2e518d6 --- /dev/null +++ b/packages/branding/src/vocab.ts @@ -0,0 +1,15 @@ +export const VOCAB = { + // Entity renames (display only — code identifiers unchanged) + company: "Workspace", + companies: "Workspaces", + ceo: "Project Manager", + board: "Owner", + hire: "Add", + fire: "Remove", + + // Brand name + appName: "Nexus", + tagline: "Open-source orchestration for your agents", +} as const; + +export type VocabKey = keyof typeof VOCAB; diff --git a/packages/branding/tsconfig.json b/packages/branding/tsconfig.json new file mode 100644 index 00000000..5a24989c --- /dev/null +++ b/packages/branding/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": ["src"] +} diff --git a/packages/branding/vitest.config.ts b/packages/branding/vitest.config.ts new file mode 100644 index 00000000..ae847ff6 --- /dev/null +++ b/packages/branding/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + include: ["src/**/*.test.ts"], + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 19c9ffc4..eb9d72c3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -220,6 +220,12 @@ importers: specifier: ^5.7.3 version: 5.9.3 + packages/branding: + devDependencies: + typescript: + specifier: ^5.7.3 + version: 5.9.3 + packages/db: dependencies: '@paperclipai/shared':