Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
378807b
chore(@hyperfrontend/workspace): update roadmap docs
AndrewRedican Apr 16, 2026
d02e740
docs(@hyperfrontend/workspace): add final stretch roadmap
AndrewRedican Apr 17, 2026
f3f6d63
feat(lib-questions): new package for terminal questions
AndrewRedican Apr 17, 2026
3b9b434
feat(docs-site): list new lib questions in the docs site
AndrewRedican Apr 17, 2026
bd4ce29
docs(docs-site): list questions package in the root readme file of th…
AndrewRedican Apr 17, 2026
0a60e3e
ci(@hyperfrontend/workspace): update ci-libraries to detect question …
AndrewRedican Apr 17, 2026
40cf971
ci(@hyperfrontend/workspace): update pipeline to upload code coverage…
AndrewRedican Apr 17, 2026
d47d64e
revert(e2e-lib-questions): drop iife and umd tests that do not apply
AndrewRedican Apr 17, 2026
0e857fd
chore: update versions for lib-questions
AndrewRedican Apr 17, 2026
e9ca502
chore(@hyperfrontend/workspace): update library-generators skill
AndrewRedican Apr 17, 2026
1a9949e
fix(docs-site): add missing navigation details for questions library
AndrewRedican Apr 20, 2026
031f3f5
chore(e2e-lib-questions): update integrity value of questions libraray
AndrewRedican Apr 20, 2026
0d22f26
chore(@hyperfrontend/workspace): add claude code extension to devcont…
AndrewRedican Apr 20, 2026
9c6fa27
feat(eslint-rules): improve docs-site-route eslint rule
AndrewRedican Apr 20, 2026
c0d715b
chore(@hyperfrontend/workspace): relocate skills to optimize codebase…
AndrewRedican Apr 20, 2026
d4f9857
docs(@hyperfrontend/workspace): update features implementation plan
AndrewRedican Apr 20, 2026
94b2ccd
fix(lib-versioning): make first-release idempotent on re-run
AndrewRedican Apr 20, 2026
bf8b7f2
chore: update versions for lib-questions, lib-versioning
AndrewRedican Apr 20, 2026
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
File renamed without changes.
File renamed without changes.
97 changes: 97 additions & 0 deletions .claude/skills/library-generators/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
name: library-generators
version: 1.1.0
description: Use @hyperfrontend/package generators to create, promote, rename, or move libraries. Use when scaffolding a new library, promoting internal to publishable, renaming a project, or relocating a library directory.
allowed-tools:
- Read
- Write
- Edit
- Terminal
---

# Library Generators

All support `--dry-run`.

---

## Commands

```bash
# Create internal library
nx generate @hyperfrontend/package:library --name=my-utils --type=util --description="..."

# Create nested (libs/utils/my)
nx generate @hyperfrontend/package:library --name=my-utils --directory=libs/utils --type=util --description="..."

# Create publishable
nx generate @hyperfrontend/package:library --name=my-utils --type=util --description="..." --publishable

# Promote to publishable
nx generate @hyperfrontend/package:make-publishable --project=lib-my-utils

# Rename
nx generate @hyperfrontend/package:rename --project=lib-my-utils --newName=my-helpers

# Move
nx generate @hyperfrontend/package:move --project=lib-my-utils --destination=libs/utils
```

---

## make-publishable Manual Steps

Generator creates E2E project + CI status workflow. **6 manual entries required:**

| Step | File | Entry |
| ---- | ------------------------------------------------------- | ---------------------------- |
| 1 | `.github/workflows/ci-libraries.yml` | Path filter + matrix entry |
| 2 | `.github/workflows/ci-main.yml` | Coverage entry in LIBS array |
| 3 | `README.md` | Row in packages table |
| 4 | `apps/docs-site/scripts/generate-docs.ts` | LIBRARIES array entry |
| 5 | `apps/docs-site/src/lib/content.ts` | LIBRARIES array entry |
| 6 | `apps/docs-site/src/app/docs/libraries/{slug}/page.tsx` | Page route file |

See `library-ci-workflows` skill for steps 1–2.

---

## Docs-Site Page Template

```tsx
import type { Metadata } from 'next'
import { LibraryDocPage } from '@/components/library-doc-page'
import { getLibraryMetadata } from '@/lib/metadata'

export function generateMetadata(): Metadata {
return getLibraryMetadata('my-lib')
}

export default function MyLibPage() {
return (
<LibraryDocPage
title="My Lib"
packageName="@hyperfrontend/my-lib"
slug="my-lib"
category="core"
fallbackDescription="One-line description."
fallbackFeatures={['Feature 1', 'Feature 2']}
/>
)
}
```

---

## content.ts Entry Template

```typescript
{
name: 'My Lib',
packageName: '@hyperfrontend/my-lib',
slug: 'my-lib',
readmePath: 'libs/my-lib/README.md',
entryPoints: ['libs/my-lib/src/index.ts'],
category: 'core',
},
```
3 changes: 2 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"shd101wyy.markdown-preview-enhanced",
"github.vscode-github-actions",
"yzhang.markdown-all-in-one",
"ritwickdey.liveserver"
"ritwickdey.liveserver",
"anthropic.claude-code"
],
"settings": {
"editor.formatOnSave": true,
Expand Down
50 changes: 0 additions & 50 deletions .github/skills/library-generators/SKILL.md

This file was deleted.

17 changes: 17 additions & 0 deletions .github/workflows/ci-lib-questions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: lib-questions

on:
workflow_run:
workflows: [libraries]
types: [completed]
branches: [main]

permissions:
actions: read

jobs:
status:
uses: ./.github/workflows/_lib-status.yml
with:
project-name: lib-questions
library-path: libs/questions
3 changes: 3 additions & 0 deletions .github/workflows/ci-libraries.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ jobs:
- 'libs/utils/json/**'
project-scope:
- 'libs/project-scope/**'
questions:
- 'libs/questions/**'
versioning:
- 'libs/versioning/**'
list-utils:
Expand Down Expand Up @@ -117,6 +119,7 @@ jobs:
add_if_changed "${{ steps.filter.outputs.json-utils }}" "lib-json-utils" "libs/utils/json" "json-utils"
add_if_changed "${{ steps.filter.outputs.list-utils }}" "lib-list-utils" "libs/utils/list" "list-utils"
add_if_changed "${{ steps.filter.outputs.project-scope }}" "lib-project-scope" "libs/project-scope" "project-scope"
add_if_changed "${{ steps.filter.outputs.questions }}" "lib-questions" "libs/questions" "questions"
add_if_changed "${{ steps.filter.outputs.versioning }}" "lib-versioning" "libs/versioning" "versioning"
add_if_changed "${{ steps.filter.outputs.random-generator-utils }}" "lib-random-generator-utils" "libs/utils/random-generator" "random-generator-utils"
add_if_changed "${{ steps.filter.outputs.string-utils }}" "lib-string-utils" "libs/utils/string" "string-utils"
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ci-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ jobs:
"network-protocol:libs/network-protocol"
"nexus:libs/nexus"
"project-scope:libs/project-scope"
"questions:libs/questions"
"state-machine:libs/state-machine"
"versioning:libs/versioning"
"data-utils:libs/utils/data"
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ This launches a development environment where you can debug and interact with yo
| [logging](https://github.com/AndrewRedican/hyperfrontend/blob/main/libs/logging) | Structured logging utilities for applications · [📖 docs](https://www.hyperfrontend.dev/docs/libraries/logging/) |
| [network-protocol](https://github.com/AndrewRedican/hyperfrontend/blob/main/libs/network-protocol) | Network protocol implementation with channels, routing, and security · [📖 docs](https://www.hyperfrontend.dev/docs/libraries/network-protocol/) |
| [project-scope](https://github.com/AndrewRedican/hyperfrontend/blob/main/libs/project-scope) | Project analysis, technology stack detection, and transactional virtual file system · [📖 docs](https://www.hyperfrontend.dev/docs/libraries/project-scope/) |
| [questions](https://github.com/AndrewRedican/hyperfrontend/blob/main/libs/questions) | Terminal prompting library with composable, functional API · [📖 docs](https://www.hyperfrontend.dev/docs/libraries/questions/) |
| [random-generator-utils](https://github.com/AndrewRedican/hyperfrontend/blob/main/libs/utils/random-generator) | Random number and data generation utilities · [📖 docs](https://www.hyperfrontend.dev/docs/libraries/utils/random-generator/) |
| [state-machine](https://github.com/AndrewRedican/hyperfrontend/blob/main/libs/state-machine) | State machine implementation with lifecycle management, actions, and reducers · [📖 docs](https://www.hyperfrontend.dev/docs/libraries/state-machine/) |
| [string-utils](https://github.com/AndrewRedican/hyperfrontend/blob/main/libs/utils/string) | String manipulation utilities for browser and Node.js environments · [📖 docs](https://www.hyperfrontend.dev/docs/libraries/utils/string/) |
Expand Down
2 changes: 2 additions & 0 deletions apps/docs-site/scripts/generate-docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ const LIBRARIES: LibraryConfig[] = [
{ name: 'Time Utils', packageName: '@hyperfrontend/time-utils', slug: 'time-utils', srcPath: 'libs/utils/time', category: 'utils' },
{ name: 'UI Utils', packageName: '@hyperfrontend/ui-utils', slug: 'ui-utils', srcPath: 'libs/utils/ui', category: 'utils' },
{ name: 'Features Plugin', packageName: '@hyperfrontend/features', slug: 'features', srcPath: 'plugins/features', category: 'plugin' },
{ name: 'Questions', packageName: '@hyperfrontend/questions', slug: 'questions', srcPath: 'libs/questions', category: 'supporting' },
]

/**
Expand All @@ -235,6 +236,7 @@ const LIBRARY_SLUGS: Record<string, string> = {
'project-scope': 'project-scope',
'state-machine': 'state-machine',
logging: 'logging',
questions: 'questions',
'web-worker': 'web-worker',
versioning: 'versioning',
}
Expand Down
26 changes: 26 additions & 0 deletions apps/docs-site/src/app/docs/libraries/questions/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { Metadata } from 'next'
import { LibraryDocPage } from '@/components/library-doc-page'
import { getLibraryMetadata } from '@/lib/metadata'

export function generateMetadata(): Metadata {
return getLibraryMetadata('questions')
}

export default function QuestionsPage() {
return (
<LibraryDocPage
title="Questions"
packageName="@hyperfrontend/questions"
slug="questions"
category="supporting"
fallbackDescription="Terminal prompting library with composable, functional API for text, select, confirm, and multiselect prompts."
fallbackFeatures={[
'Pure function prompts returning Promise<PromptOutcome<T>> for predictable, testable results',
'Composable API for building complex interactive CLI flows',
'Full TypeScript support with discriminated unions for prompt outcomes',
'Zero external dependencies — uses only Node.js built-ins and @hyperfrontend utilities',
'Searchable multiselect with type-to-filter functionality for large option lists',
]}
/>
)
}
8 changes: 8 additions & 0 deletions apps/docs-site/src/lib/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,14 @@ export const LIBRARIES: LibraryInfo[] = [
entryPoints: ['libs/utils/ui/src/index.ts'],
category: 'utils',
},
{
name: 'Questions',
packageName: '@hyperfrontend/questions',
slug: 'questions',
readmePath: 'libs/questions/README.md',
entryPoints: ['libs/questions/src/index.ts'],
category: 'supporting',
},
{
name: 'Features Plugin',
packageName: '@hyperfrontend/features',
Expand Down
1 change: 1 addition & 0 deletions apps/docs-site/src/lib/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const coreLibraries: NavItem[] = [
*/
const supportingLibraries: NavItem[] = [
{ slug: 'logging', packageName: '@hyperfrontend/logging', href: '/docs/libraries/logging' },
{ slug: 'questions', packageName: '@hyperfrontend/questions', href: '/docs/libraries/questions' },
{ slug: 'state-machine', packageName: '@hyperfrontend/state-machine', href: '/docs/libraries/state-machine' },
{
slug: 'versioning',
Expand Down
13 changes: 13 additions & 0 deletions apps/package-e2e/questions/jest.config.cjs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { Config } from 'jest'

const config: Config = {
displayName: 'e2e-lib-questions-cjs',
testEnvironment: 'node',
transform: {
'^.+\\.tsx?$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.json' }],
},
testMatch: ['<rootDir>/src/cjs.spec.ts'],
moduleNameMapper: {},
}

export default config
23 changes: 23 additions & 0 deletions apps/package-e2e/questions/jest.config.esm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { Config } from 'jest'

const config: Config = {
displayName: 'e2e-lib-questions-esm',
testEnvironment: 'node',
extensionsToTreatAsEsm: ['.ts'],
transform: {
'^.+\\.(ts|tsx|js|mjs)$': [
'ts-jest',
{
tsconfig: '<rootDir>/tsconfig.json',
useESM: true,
},
],
},
transformIgnorePatterns: [
// Transform @hyperfrontend packages since they use ESM
'node_modules/(?!@hyperfrontend/)',
],
testMatch: ['<rootDir>/src/esm.spec.ts'],
}

export default config
27 changes: 27 additions & 0 deletions apps/package-e2e/questions/jest.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Jest setup for browser bundle tests.
* Cleans up window globals between tests.
*/

// jsdom doesn't provide TextEncoder/TextDecoder by default
import { TextEncoder, TextDecoder } from 'util'

Object.assign(global, { TextEncoder, TextDecoder })

beforeEach(() => {
// Clear any globals that may have been set by previous tests
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if ((window as any).HyperfrontendQuestions !== undefined) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
;(window as any).HyperfrontendQuestions = undefined
}
} catch {
// Property may not be deletable, that's ok
}
})

afterEach(() => {
// Remove any added script elements
document.head.querySelectorAll('script').forEach((script) => script.remove())
})
Loading
Loading