Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/semantic-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ jobs:
- name: Enforce Oxford spelling
run: make spelling
- run: bun install --frozen-lockfile
- run: bun run docs:check
- run: bun semantic
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ SPELLING_HELPER_PYTEST = PYTHONPATH=scripts $(UV_ENV) $(UV) run --no-project \
--python 3.14 --with pathspec==$(PATHSPEC_VERSION) --with pytest==9.0.2 \
--with pytest-cov==7.0.0 python -m pytest

.PHONY: check-fmt typecheck lint test spelling spelling-config \
.PHONY: check-fmt typecheck docs-check lint test spelling spelling-config \
spelling-config-write spelling-phrase-check spelling-helper-test

check-fmt:
Expand All @@ -24,6 +24,11 @@ check-fmt:
typecheck:
bun check:types

# Zero-tolerance documentation gate: TypeDoc's notDocumented validation over
# src (typedoc.json); also runs inside `bun test:all`. Emits no artefacts.
docs-check:
bun run docs:check

lint:
bun lint

Expand Down
56 changes: 45 additions & 11 deletions bun.lock

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"fmt": "bunx biome format --write src tests tools scripts package.json biome.jsonc bunfig.toml",
"lint": "bunx biome ci src tests tools",
"check:types": "tsc --noEmit --skipLibCheck",
"docs:check": "typedoc --options typedoc.json",
"test": "bun test --preload ./tests/setup-happy-dom.ts --preload ./tests/setup-snapshot-guard.ts",
"test:a11y": "vitest --run --config vitest.a11y.config.ts",
"test:a11y:watch": "vitest --watch --config vitest.a11y.config.ts",
Expand All @@ -24,7 +25,7 @@
"lint:class-duplicates": "bun run scripts/find-near-duplicate-classes.ts",
"lint:hardcoded-strings": "bun run scripts/check-hardcoded-strings.ts",
"lint:imports": "bun run scripts/lint-import-boundaries.ts",
"test:all": "bun lint && bun check:types && bun test && bun run test:a11y && bun run lint:ftl-vars && bun run semantic && bun test:e2e",
"test:all": "bun lint && bun check:types && bun run docs:check && bun test && bun run test:a11y && bun run lint:ftl-vars && bun run semantic && bun test:e2e",
"ff": "bunx --bun @tailwindcss/cli --input src/index.css --output tmp/tailwind.css --verbose && rm -f tmp/tailwind.css && bun run test:all"
},
"dependencies": {
Expand All @@ -48,6 +49,7 @@
"i18next-browser-languagedetector": "^8.2.0",
"i18next-fluent": "^2.0.0",
"i18next-fluent-backend": "^1.0.0",
"playwright-core": "^1.61.1",
"react": "^19.2.7",
"react-dom": "^19.2.7",
"react-i18next": "^17.0.9",
Expand Down Expand Up @@ -82,6 +84,7 @@
"style-dictionary": "^5.5.0",
"stylelint": "^17.14.0",
"stylelint-declaration-strict-value": "^1.10.11",
"typedoc": "^0.28.20",
"typescript": "^6.0.3",
"vite": "^8.1.4",
"vitest": "^4.1.10"
Expand Down
1 change: 1 addition & 0 deletions src/app/layout/mobile-shell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { JSX, ReactNode } from "react";

import { useDisplayMode } from "../providers/display-mode-provider";

/** Props accepted by {@link MobileShell}. */
export interface MobileShellProps {
/** Main content rendered inside the framed device shell. */
children: ReactNode;
Expand Down
4 changes: 4 additions & 0 deletions src/app/observability/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,13 @@ function log(level: LogLevel, message: string, context?: Record<string, unknown>
* the `TelemetrySink` port).
*/
export const appLogger = {
/** Logs a debug-level entry; use for verbose diagnostic detail. */
debug: (message: string, context?: Record<string, unknown>) => log("debug", message, context),
/** Logs an info-level entry; use for routine operational events. */
info: (message: string, context?: Record<string, unknown>) => log("info", message, context),
/** Logs a warn-level entry; use for recoverable, unexpected conditions. */
warn: (message: string, context?: Record<string, unknown>) => log("warn", message, context),
/** Logs an error-level entry, optionally attaching the causing error. */
error: (message: string, context?: Record<string, unknown>, error?: unknown) =>
log("error", message, context, error),
};
Expand Down
15 changes: 15 additions & 0 deletions src/app/providers/display-mode-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import { appLogger } from "../observability/logger";

const STORAGE_KEY = "vibecoder.displayMode";

/**
* Layout mode for the shell: `"hosted"` frames content in a fixed mobile
* viewport, `"full-browser"` fills the available browser window.
*/
export type DisplayMode = "hosted" | "full-browser";

const DESKTOP_DEFAULT_MODE: DisplayMode = "hosted";
Expand Down Expand Up @@ -80,10 +84,17 @@ function detectPreferredDisplayMode(): DisplayMode {
return DESKTOP_DEFAULT_MODE;
}

/** Props accepted by {@link DisplayModeProvider}. */
export interface DisplayModeProviderProps {
/** Subtree that gains access to the display mode context. */
children: ReactNode;
}

/**
* Supplies the current {@link DisplayMode} to descendants, seeding it from
* `localStorage` or a media-query-based default, and persisting subsequent
* user choices back to `localStorage`.
*/
export function DisplayModeProvider({ children }: DisplayModeProviderProps): JSX.Element {
const storedMode = readStoredMode();
const [mode, setModeState] = useState<DisplayMode>(() => {
Expand Down Expand Up @@ -176,6 +187,10 @@ export function DisplayModeProvider({ children }: DisplayModeProviderProps): JSX
return <DisplayModeContext.Provider value={value}>{children}</DisplayModeContext.Provider>;
}

/**
* Reads the {@link DisplayModeContextValue} from the nearest
* {@link DisplayModeProvider}. Throws if called outside one.
*/
export function useDisplayMode(): DisplayModeContextValue {
const context = useContext(DisplayModeContext);
if (!context) {
Expand Down
1 change: 1 addition & 0 deletions src/app/routes/app-routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ declare module "@tanstack/react-router" {
}
}

/** Props accepted by {@link AppRoutes}. */
export interface AppRoutesProps {
/**
* Optional router instance. Tests can supply their own router to control the
Expand Down
4 changes: 3 additions & 1 deletion src/application/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* @file Application layer barrel.
* Application layer barrel.
*
* The application layer wires domain services together into use-case
* implementations, hosts XState machines for workflow orchestration, and
Expand All @@ -8,6 +8,8 @@
*
* See `docs/adr-002-adopt-hexagonal-architecture-for-domain-boundaries.md`
* and `docs/adr-003-use-xstate-for-workflow-orchestration.md` for rationale.
*
* @module
*/

export type { AppMachineAction, AppMachineEvent, AppMachineStateValue } from "./machines";
Expand Down
30 changes: 24 additions & 6 deletions src/application/machines/app.machine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,18 @@ import { createMachine } from "xstate";
* Events accepted by the application boot workflow machine.
*/
export type AppMachineEvent =
| { readonly type: "BOOT_READY" }
| { readonly type: "BOOT_FAILED" }
| { readonly type: "RETRY_BOOT" };
| {
/** Signals that the boot sequence completed successfully. */
readonly type: "BOOT_READY";
}
| {
/** Signals that the boot sequence failed. */
readonly type: "BOOT_FAILED";
}
| {
/** Requests a retry of a failed boot sequence. */
readonly type: "RETRY_BOOT";
};

/**
* State values exposed by the application boot workflow machine.
Expand All @@ -37,9 +46,18 @@ export type AppMachineStateValue = "booting" | "failed" | "title";
* Named actions emitted by boot workflow transitions for adapters to observe.
*/
export type AppMachineAction =
| { readonly type: "recordBootFailed" }
| { readonly type: "recordBootRetryRequested" }
| { readonly type: "recordBootSucceeded" };
| {
/** Emitted when a boot attempt fails. */
readonly type: "recordBootFailed";
}
| {
/** Emitted when a retry is requested after a boot failure. */
readonly type: "recordBootRetryRequested";
}
| {
/** Emitted when a boot attempt succeeds. */
readonly type: "recordBootSucceeded";
};

/**
* XState machine that models boot success, boot failure, and retry reachability.
Expand Down
4 changes: 3 additions & 1 deletion src/application/machines/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
/**
* @file Application machine exports.
* Application machine exports.
*
* This barrel keeps inbound adapters and tests on the accepted
* `src/application/machines/` boundary without exposing future machine
* internals before their roadmap slices exist.
*
* @module
*/

export type { AppMachineAction, AppMachineEvent, AppMachineStateValue } from "./app.machine";
Expand Down
2 changes: 2 additions & 0 deletions src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ export function LoadingBackdrop(): JSX.Element {

/** Props accepted by the {@link AppRoot} bootstrap wrapper. */
export interface AppRootProps {
/** Component to render inside the Suspense boundary; defaults to {@link App}. */
readonly AppComponent?: ComponentType;
/** Suspense fallback; defaults to {@link LoadingBackdrop} when omitted. */
readonly fallback?: ReactNode;
}

Expand Down
7 changes: 7 additions & 0 deletions tsconfig.typedoc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"skipLibCheck": true
},
"include": ["src"]
}
49 changes: 49 additions & 0 deletions typedoc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"$schema": "https://typedoc.org/schema.json",

"tsconfig": "tsconfig.typedoc.json",
"entryPoints": ["src"],
"entryPointStrategy": "expand",

"exclude": [
"**/*.d.ts",
"**/*.gen.*",
"**/*.generated.*",
"**/__generated__/**",
"**/tests/**",
"**/test/**",
"**/fixtures/**"
],

"emit": "none",
"commentStyle": "jsdoc",

"excludeExternals": true,
"excludeInternal": true,
"excludePrivate": true,
"excludeProtected": true,

"validation": {
"notDocumented": true,
"notExported": false,
"invalidLink": false,
"invalidPath": false,
"rewrittenLink": false,
"unusedMergeModuleWith": false
},

"requiredToBeDocumented": [
"Enum",
"EnumMember",
"Variable",
"Function",
"Class",
"Interface",
"Property",
"Method",
"Accessor",
"TypeAlias"
],

"treatValidationWarningsAsErrors": true
}
Loading