@ihyeon/flow-qa 0.0.0-stage → 0.1.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.ko.md +73 -0
  3. package/README.md +72 -2
  4. package/THIRD_PARTY_NOTICES.md +9 -0
  5. package/dist/bin/flow-qa.mjs +3 -0
  6. package/dist/examples/demo/server.js +31 -0
  7. package/dist/src/cli.js +285 -0
  8. package/dist/src/compiler.js +62 -0
  9. package/dist/src/engine.js +246 -0
  10. package/dist/src/i18n.js +98 -0
  11. package/dist/src/planner.js +112 -0
  12. package/dist/src/report.js +315 -0
  13. package/dist/src/schema.js +71 -0
  14. package/dist/src/ui/entry.js +109 -0
  15. package/dist/src/ui/evidence.js +85 -0
  16. package/dist/src/ui/public/app.js +360 -0
  17. package/dist/src/ui/public/display.js +56 -0
  18. package/dist/src/ui/public/fonts/dm-sans.woff2 +0 -0
  19. package/dist/src/ui/public/fonts/noto-kr-subset.woff2 +0 -0
  20. package/dist/src/ui/public/i18n.js +290 -0
  21. package/dist/src/ui/public/index.html +117 -0
  22. package/dist/src/ui/public/style.css +200 -0
  23. package/dist/src/ui/server.js +785 -0
  24. package/dist/src/workspace.js +88 -0
  25. package/docs/architecture.md +38 -0
  26. package/docs/releases.md +54 -0
  27. package/docs/ui.md +71 -0
  28. package/licenses/DM-Sans-LICENSE.txt +93 -0
  29. package/licenses/Noto-Sans-KR-LICENSE.txt +93 -0
  30. package/node_modules/@hyeonse/design-system/.github/workflows/ci.yml +21 -0
  31. package/node_modules/@hyeonse/design-system/.npmignore +5 -0
  32. package/node_modules/@hyeonse/design-system/AGENTS.md +10 -0
  33. package/node_modules/@hyeonse/design-system/LICENSE +21 -0
  34. package/node_modules/@hyeonse/design-system/README.md +67 -0
  35. package/node_modules/@hyeonse/design-system/THIRD_PARTY_NOTICES.md +5 -0
  36. package/node_modules/@hyeonse/design-system/dist/components.css +105 -0
  37. package/node_modules/@hyeonse/design-system/dist/preferences.d.ts +21 -0
  38. package/node_modules/@hyeonse/design-system/dist/preferences.js +69 -0
  39. package/node_modules/@hyeonse/design-system/dist/react.d.ts +21 -0
  40. package/node_modules/@hyeonse/design-system/dist/react.js +100 -0
  41. package/node_modules/@hyeonse/design-system/dist/tokens.css +75 -0
  42. package/node_modules/@hyeonse/design-system/docs/api.md +33 -0
  43. package/node_modules/@hyeonse/design-system/docs/assets/fonts/dm-sans.woff2 +0 -0
  44. package/node_modules/@hyeonse/design-system/docs/assets/fonts/noto-kr-subset.woff2 +0 -0
  45. package/node_modules/@hyeonse/design-system/docs/audit.md +29 -0
  46. package/node_modules/@hyeonse/design-system/docs/foundations.md +30 -0
  47. package/node_modules/@hyeonse/design-system/docs/verification.md +13 -0
  48. package/node_modules/@hyeonse/design-system/index.html +51 -0
  49. package/node_modules/@hyeonse/design-system/licenses/DM-Sans-LICENSE.txt +93 -0
  50. package/node_modules/@hyeonse/design-system/licenses/Noto-Sans-KR-LICENSE.txt +93 -0
  51. package/node_modules/@hyeonse/design-system/licenses/arla6ka-MIT.txt +21 -0
  52. package/node_modules/@hyeonse/design-system/package.json +35 -0
  53. package/node_modules/@hyeonse/design-system/scripts/audit-tokens.mjs +48 -0
  54. package/node_modules/@hyeonse/design-system/scripts/build.mjs +12 -0
  55. package/node_modules/@hyeonse/design-system/showcase.css +75 -0
  56. package/node_modules/@hyeonse/design-system/showcase.mjs +63 -0
  57. package/node_modules/@hyeonse/design-system/skills/hyeonse-design-system/SKILL.md +18 -0
  58. package/node_modules/@hyeonse/design-system/skills/hyeonse-design-system/references/api.md +7 -0
  59. package/node_modules/@hyeonse/design-system/skills/hyeonse-design-system/references/build.md +7 -0
  60. package/node_modules/@hyeonse/design-system/skills/hyeonse-design-system/references/foundations.md +7 -0
  61. package/node_modules/@hyeonse/design-system/skills/hyeonse-design-system/references/mapping.md +7 -0
  62. package/node_modules/@hyeonse/design-system/skills/hyeonse-design-system/references/migration.md +5 -0
  63. package/node_modules/@hyeonse/design-system/skills/hyeonse-design-system/references/review-docs.md +5 -0
  64. package/node_modules/@hyeonse/design-system/src/components.css +105 -0
  65. package/node_modules/@hyeonse/design-system/src/preferences.ts +87 -0
  66. package/node_modules/@hyeonse/design-system/src/react.tsx +161 -0
  67. package/node_modules/@hyeonse/design-system/src/tokens.css +75 -0
  68. package/node_modules/@hyeonse/design-system/tests/audit.test.mjs +30 -0
  69. package/node_modules/@hyeonse/design-system/tests/preferences.test.mjs +86 -0
  70. package/node_modules/@hyeonse/design-system/tsconfig.json +16 -0
  71. package/package.json +73 -4
@@ -0,0 +1,88 @@
1
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
+ import { resolve, dirname } from 'node:path';
3
+ import { createHash } from 'node:crypto';
4
+ import { configSchema, suiteSchema } from "./schema.js";
5
+ export const CONFIG_FILE = 'flowqa.config.json';
6
+ export async function readConfig(workspace) {
7
+ try {
8
+ return configSchema.parse(JSON.parse(await readFile(resolve(workspace, CONFIG_FILE), 'utf8')));
9
+ }
10
+ catch (error) {
11
+ if (error.code === 'ENOENT')
12
+ throw new Error('flowqa.config.json is missing. Run flow-qa init first.');
13
+ throw error;
14
+ }
15
+ }
16
+ export async function readSuite(path) {
17
+ return suiteSchema.parse(JSON.parse(await readFile(path, 'utf8')));
18
+ }
19
+ export async function writeJSON(path, data, exclusive = false) {
20
+ await mkdir(dirname(path), { recursive: true });
21
+ await writeFile(path, `${JSON.stringify(data, null, 2)}\n`, { flag: exclusive ? 'wx' : 'w', mode: 0o600 });
22
+ }
23
+ export function sha256(text) { return createHash('sha256').update(text).digest('hex'); }
24
+ export async function verifySuiteSource(suite, workspace) {
25
+ if (!suite.source)
26
+ return;
27
+ let source;
28
+ try {
29
+ source = await readFile(resolve(workspace, suite.source.file), 'utf8');
30
+ }
31
+ catch {
32
+ throw new Error('Cannot read the source flow for these cases. Restore the file or regenerate the cases from the specification.');
33
+ }
34
+ if (sha256(source) !== suite.source.sha256)
35
+ throw new Error('STALE_SUITE: The flow changed. Regenerate the cases from the current specification.');
36
+ }
37
+ export const demoFlow = `# Create and filter tasks\n\nThe target is the local demo app included with Flow QA. Each test starts with an empty list.\n\n## Confirmed requirements\n- Entering a title and adding it displays the title in the list.\n- Adding an empty title shows the error 'Enter a task title.'\n- A completed task disappears from the 'Active' filter and remains visible under 'All'.\n\n## UI contract\n- Title input: label 'Task title'\n- Add button: role button, name 'Add'\n- List: testId 'task-list'\n- Empty title error: role alert\n- Complete button: role button, name 'Complete'\n- Filters: role button, name 'Active' or 'All'\n\n## Execution scope\nOnly temporary items in the local demo are used. No external account, real payment, or persistent storage is involved.\n`;
38
+ export const demoSuite = suiteSchema.parse({
39
+ schemaVersion: 'flow-qa/suite-1', id: 'task-flow', title: 'Create and filter tasks',
40
+ requirements: [
41
+ { id: 'R1', text: 'A task is added with the entered title.' },
42
+ { id: 'R2', text: 'Adding an empty title shows an error.' },
43
+ { id: 'R3', text: 'Completed tasks are hidden from Active and remain under All.' },
44
+ ],
45
+ cases: [
46
+ { id: 'TC-001', title: 'Create a task with a title', requirementIds: ['R1'], preconditions: ['Empty list on a new page'], questions: [], steps: [
47
+ { type: 'open', path: '/' }, { type: 'fill', locator: { by: 'label', value: 'Task title' }, value: 'First QA run' },
48
+ { type: 'click', locator: { by: 'role', value: 'button', name: 'Add' } },
49
+ { type: 'assertText', locator: { by: 'testId', value: 'task-list' }, expected: 'First QA run', match: 'contains' },
50
+ ] },
51
+ { id: 'TC-002', title: 'Show an error for an empty title', requirementIds: ['R2'], preconditions: ['Empty list on a new page'], questions: [], steps: [
52
+ { type: 'open', path: '/' }, { type: 'click', locator: { by: 'role', value: 'button', name: 'Add' } },
53
+ { type: 'assertText', locator: { by: 'role', value: 'alert' }, expected: 'Enter a task title.', match: 'equals' },
54
+ ] },
55
+ { id: 'TC-003', title: 'Hide completed tasks from Active', requirementIds: ['R3'], preconditions: ['Empty list on a new page'], questions: [], steps: [
56
+ { type: 'open', path: '/' }, { type: 'fill', locator: { by: 'label', value: 'Task title' }, value: 'Task to complete' },
57
+ { type: 'click', locator: { by: 'role', value: 'button', name: 'Add' } },
58
+ { type: 'click', locator: { by: 'role', value: 'button', name: 'Complete' } },
59
+ { type: 'click', locator: { by: 'role', value: 'button', name: 'Active' } },
60
+ { type: 'assertVisible', locator: { by: 'text', value: 'Task to complete' }, visible: false },
61
+ { type: 'click', locator: { by: 'role', value: 'button', name: 'All' } },
62
+ { type: 'assertVisible', locator: { by: 'text', value: 'Task to complete' }, visible: true },
63
+ ] },
64
+ ],
65
+ });
66
+ export async function initWorkspace(workspace) {
67
+ const written = [];
68
+ const files = {
69
+ [CONFIG_FILE]: `${JSON.stringify(configSchema.parse({ schemaVersion: 'flow-qa/config-1', targets: { demo: { url: 'http://127.0.0.1:4178', description: 'Local task demo' } } }), null, 2)}\n`,
70
+ 'flows/task-flow.md': demoFlow,
71
+ 'cases/task-flow.json': `${JSON.stringify({ ...demoSuite, source: { file: 'flows/task-flow.md', sha256: sha256(demoFlow) } }, null, 2)}\n`,
72
+ '.gitignore': '.flowqa/\n.env\n.env.*\n',
73
+ '.flowqa/.gitignore': '*\n',
74
+ };
75
+ for (const [file, content] of Object.entries(files)) {
76
+ const path = resolve(workspace, file);
77
+ await mkdir(dirname(path), { recursive: true });
78
+ try {
79
+ await writeFile(path, content, { flag: 'wx', mode: 0o600 });
80
+ written.push(file);
81
+ }
82
+ catch (error) {
83
+ if (error.code !== 'EEXIST')
84
+ throw error;
85
+ }
86
+ }
87
+ return written;
88
+ }
@@ -0,0 +1,38 @@
1
+ # Architecture and verification boundaries
2
+
3
+ The local CLI and loopback web UI share one workspace format, case schema, execution path, and report contract. Flow QA runs browser tests against a target URL; it does not need the target application's source code.
4
+
5
+ ```mermaid
6
+ flowchart LR
7
+ A[Flow document] --> B[Planning prompt or planner model]
8
+ B --> C[JSON case suite]
9
+ C --> D[Schema and source-hash validation]
10
+ D --> E[Compile allowed steps to e2e code]
11
+ E --> F[tester-army/e2e browser run]
12
+ F --> G[QA report with attempts and evidence]
13
+ H[CLI / local UI] --> B
14
+ H --> D
15
+ H --> F
16
+ I[Optional agent model] --> F
17
+ ```
18
+
19
+ ## Decisions at each boundary
20
+
21
+ **Planning and execution are separate.** A `planner` designs cases from a flow; an `agent` is used only for `act` and `assertAgent` steps during execution. They are configured independently. Users review the generated JSON before running it, and fixed steps run without either model. Users choose model and target addresses; authentication values come from named environment variables rather than the config JSON.
22
+
23
+ **Only a defined vocabulary compiles.** The schema checks requirement references, assertions, step types, and inputs. It does not execute arbitrary code or shell commands from model output. Cases with unresolved `questions`, or steps that need an unavailable agent model, are blocked. `preconditions` describe required state; they are not an automatic setup contract.
24
+
25
+ **Source and evidence stay linked.** Planning records the source flow's SHA-256 hash in the suite. `validate`, `generate`, and `run` check it again and stop when the flow changed. Each execution writes a new directory with a suite snapshot, generated tests, raw engine output, and Markdown/JSON reports. Previous evidence is not reused as a current success. `compare` permits a direct comparison only for the same suite hash and target URL; it cannot establish that external data was unchanged.
26
+
27
+ **Blocked and failed mean different things.** An unreachable app or unresolved question is blocked; an assertion mismatch is failed. A pass after retry has its own status. Engine output is validated rather than treating missing results as passes. The report records observations, not a root-cause verdict on the product.
28
+
29
+ ## Ownership
30
+
31
+ | Area | Flow QA provides | External implementation or prerequisite |
32
+ | --- | --- | --- |
33
+ | Planning | Prompt, model connection, JSON schema validation | User-selected OpenAI-compatible model |
34
+ | Execution | Step compilation, target connection, orchestration, cancellation | [tester-army/e2e](https://github.com/tester-army/e2e), Chromium |
35
+ | Results | A fresh report per run, status interpretation, evidence links | Raw runs and evidence from the engine |
36
+ | UI | Local workflow screens and English/Korean language switch | [Hyeonse Design System](https://github.com/hyeonse-swing/hyeonse-design-system) tokens and preference utilities |
37
+
38
+ The UI binds only to `127.0.0.1` and serves approved report evidence, not arbitrary raw logs or HTML/SVG. Local reports may still contain data from the tested app and should be reviewed before sharing. This alpha does not manage login sessions, cap model spending, schedule CI runs, or support mobile devices.
@@ -0,0 +1,54 @@
1
+ # Alpha release and verification
2
+
3
+ ## 0.1.0-alpha.2
4
+
5
+ This update replaces the introductory video link with two UI screenshots. Runtime behavior is unchanged from alpha.1. Media files are not included in the npm tarball.
6
+
7
+ This public alpha provides a local CLI and UI, structured case validation, browser-run orchestration, and QA reports linked to evidence. Its bundled to-do app demo runs without a model.
8
+
9
+ - Package: [`@ihyeon/flow-qa@0.1.0-alpha.2`](https://www.npmjs.com/package/@ihyeon/flow-qa/v/0.1.0-alpha.2), with the `alpha` dist-tag
10
+ - Source and package: [GitHub alpha release](https://github.com/hyeonse-swing/flow-qa/releases/tag/v0.1.0-alpha.2)
11
+ - Public checks: [GitHub Actions](https://github.com/hyeonse-swing/flow-qa/actions/workflows/ci.yml)
12
+
13
+ ### Local evidence
14
+
15
+ Checked on macOS with Node.js 24.14.1 on 2026-10-08. The English-default and Korean UI share the same execution and data contracts.
16
+
17
+ | Check | Observed result |
18
+ | --- | --- |
19
+ | Types, unit tests, UI static checks | 45 tests, type checking, JavaScript syntax, and the design-system token audit passed |
20
+ | Real Chromium | Three normal cases passed; an intentional assertion failure and an unreachable app were classified separately |
21
+ | Package contents | Compiled CLI, UI, demo, and bundled design system included; workspace data, run results, and secret files excluded |
22
+ | Tarball in a fresh consumer workspace | Installed with Git execution disabled; CLI, UI, fonts, and the three actual cases passed |
23
+ | Language behavior in Chromium | English first visit, Korean switching, persisted preference, cross-tab sync, preserved edits and review, live run completion, localized Markdown downloads, and 390px viewport passed |
24
+ | Runtime dependency audit | `npm audit --omit=dev` found no known vulnerabilities at the time of the check |
25
+
26
+ These browser checks used a locally installed Chromium. They do not prove first install on a clean OS, authenticated behavior in another service, or real-model quality and cost. Dependency audit results are time-sensitive.
27
+
28
+ ### Reproduce
29
+
30
+ ```sh
31
+ npm ci
32
+ npm run check
33
+ npm run qa -- browser install
34
+ npm run demo:smoke
35
+ npm run smoke:ui
36
+ npm run check:package
37
+ npm run smoke:package
38
+ ```
39
+
40
+ `check:package` checks the distribution file list and required resources. `smoke:package` installs the tarball into a temporary consumer workspace, then checks the CLI, UI, and real browser run. It writes results to `output/package/tarball-smoke.json`, outside the published package.
41
+
42
+ Check the published registry version separately. The script requires the installed package name and version to match the current `package.json` exactly.
43
+
44
+ ```sh
45
+ FLOWQA_PACKAGE_SPEC=@ihyeon/flow-qa@0.1.0-alpha.2 npm run smoke:package
46
+ ```
47
+
48
+ Registry results are written to `output/package/registry-smoke.json`. GitHub CI checks types and tests, Chromium pass/fail/blocked cases, and tarball installation on Linux; its artifacts contain the check results. Confirm publication and CI independently on the package page and the workflow run for the relevant commit.
49
+
50
+ ### Scope and credits
51
+
52
+ This alpha does not provide login-session setup, a model-spending cap, scheduled CI runs, or a shared team server. Case planning and natural-language browser action use separately configured OpenAI-compatible APIs; local demo checks do not establish model quality or behavior in an external authenticated app. The UI library lists only top-level `cases/*.json` and linked `flows/*.md` files.
53
+
54
+ The browser engine is `e2e@0.16.0` with `@e2e-dev/web@0.11.1`. The design system is fetched from a pinned public HTTPS source and bundled with the npm package, so consumers do not need GitHub authentication to install it. See the [third-party notices](../THIRD_PARTY_NOTICES.md) for component licenses.
package/docs/ui.md ADDED
@@ -0,0 +1,71 @@
1
+ # Flow QA local UI
2
+
3
+ Use the target app's URL and a user flow to review cases, run them, and inspect results. The local example is a to-do app; the UI does not bundle an organization's product list, internal URLs, accounts, model catalog, work cases, or run history.
4
+
5
+ ## Start
6
+
7
+ Node.js 24 or later is required. Install the alpha and start the local demo:
8
+
9
+ ```sh
10
+ npm install -g @ihyeon/flow-qa@0.1.0-alpha.2
11
+ flow-qa browser install
12
+ flow-qa ui --demo
13
+ ```
14
+
15
+ The default UI address is `http://127.0.0.1:4310`. The command prints the demo app address. Use `flow-qa ui --demo --port 4311` for another port. Ctrl+C stops the active run and the servers started by this command.
16
+
17
+ To open an existing workspace:
18
+
19
+ ```sh
20
+ flow-qa ui
21
+ # or specify another Flow QA workspace
22
+ flow-qa ui --workspace ./my-qa --port 4311
23
+ ```
24
+
25
+ Create a workspace first with `flow-qa init ./my-qa`. From source, use `npm ci`, `npx playwright install chromium`, and `npm run ui:demo`. The server binds only to `127.0.0.1`; it is not a hosted team service.
26
+
27
+ The UI starts in **English**, regardless of browser language. Switch to **한국어** from the top bar. The selection is saved under `flowqa-language` in this browser and applies on the next visit. It changes product copy and the labels in Markdown reports downloaded from the UI; it does not translate user-written flows, target descriptions, case titles, target apps, or model responses. Saved `qa-report.json` and `qa-report.md` use English product wording and unchanged status codes. CLI messages default to English; `--lang en|ko` takes precedence over `FLOW_QA_LANG`.
28
+
29
+ ## Workflow
30
+
31
+ 1. **Connections:** Register a target name and URL. Planner and browser agent models have separate settings.
32
+ 2. **Scenario:** Describe the initial state, actions, screen elements, and expected results. If a planner is ready, ask it to create cases. Without a model, download the planning prompt and paste a JSON response from an AI you already use.
33
+ 3. **Review and save cases:** Expand each case to read preconditions, actions, expected results, and unresolved questions. Editing the JSON keeps the linked flow; if that source flow changes, design the cases again. Planning and running are separate actions. Editing inputs or connection settings alone does not call a model.
34
+ 4. **Run QA:** Review the saved case file, select a target, and check the review confirmation before running. If the file changes after review, reload and review it again. Fixed steps need no agent model. `act` and `assertAgent` require a compatible agent; missing models and unresolved questions are reported as blocked cases.
35
+ 5. **Case library and Run history:** Save cases as new files and load them again. Open run details to see each case, attempt, and evidence; download the Markdown or JSON report.
36
+
37
+ The top bar shows planning, running, and stopping states, plus a cancel button. A late planning response cannot change the draft after cancellation. The UI does not estimate progress inside an individual browser action. If the server disconnects, reconnect; runs started in another tab also appear. Refreshing settings rereads targets and models, so save edits first.
38
+
39
+ For each attempt, the report can open or download an approved screenshot or text evidence item. It serves only evidence linked to the report and marked as redacted or not needing redaction. It does not serve arbitrary files, raw run logs, HTML, or SVG. Markdown and JSON downloads summarize results but do not include evidence files. Keep the original run directory structure if you need relative evidence links in an offline Markdown report.
40
+
41
+ **Connections** shows whether Chromium is installed. A model key marked ready means only that the named environment variable exists; it does not prove authentication or model compatibility. Case review shows runnable and pre-blocked counts. Login and target reachability are established only by an actual run.
42
+
43
+ To enter fresh JSON after changing a scenario, open the JSON editor in case review and choose **New JSON draft**. Existing saved files remain; validate and save the new JSON before reviewing it for a run.
44
+
45
+ ## Display and language
46
+
47
+ The UI uses role tokens and preference utilities from `@hyeonse/design-system`, pinned to GitHub commit `38978c6a86f422fc0e63e919f600bc2dd3451e5c`. Flow QA implements its own workflow layout, buttons, and fields with those tokens.
48
+
49
+ The top-bar theme button and **Connections → Display settings** control theme, accent, density, corners, and motion. Preferences are saved under `flowqa-display-preferences` in the browser and shared across tabs. The device's reduced-motion setting takes priority. The saved preferences are applied before the token CSS appears on first load.
50
+
51
+ Local DM Sans and a Noto Sans KR subset are used for typography; missing Korean glyphs fall back to installed system fonts. See the [font and package notices](../THIRD_PARTY_NOTICES.md).
52
+
53
+ ## Model connections
54
+
55
+ In the UI, configure an OpenAI-compatible Chat Completions base URL, model ID, and the **name** of an environment variable containing an API key. A local model can be used if it supports the same contract; confirm its API, tool, and image capabilities separately.
56
+
57
+ There is no field for the token value. Supply keys to the environment that starts the UI server. Flow QA does not read `.env` files automatically and does not save keys in browser storage. Changing a variable name does not create its value.
58
+
59
+ Without a model, you can still download prompts, review existing cases, and run fixed steps. If a generated response does not satisfy the suite schema, the UI identifies fields to fix (for example, `cases.0.steps` means the first case's steps). Clarify missing expectations in the scenario and regenerate, or edit JSON from a downloaded prompt. There is no automatic retry. Canceling a request stops this app from accepting its result; it does not guarantee that the provider stops processing or charging.
60
+
61
+ The report displays token use and estimated cost only when supplied by the execution engine. Case-planning cost is separate; there is no total cost aggregation or spending cap.
62
+
63
+ ## Storage and limits
64
+
65
+ - A normal UI workspace uses `flowqa.config.json`, `flows/`, `cases/`, and `.flowqa/runs/` in the selected directory.
66
+ - Demo mode writes to `.flowqa/ui-demo-en/`, keeping earlier Korean demo data separate. On restart it reconnects the demo app to its new local URL and resets model settings; saved cases and run history remain. Switching the UI language does not translate either demo data or user-authored text.
67
+ - The UI library lists only top-level `cases/*.json` and their linked `flows/*.md`. Use the CLI to validate and run cases in nested directories.
68
+ - Saving creates a new case file. The UI does not overwrite or delete an existing one.
69
+ - Run history may contain data from the tested app. Inspect reports and evidence before downloading or sharing them.
70
+ - A failed assertion is an observed result, not proof of a product defect. Unverified cases are never shown as passed.
71
+ - This UI has no login-session capture, automatic regression recording, batch execution, CI scheduler, or team permissions. It uses the same run and report contract as the CLI.
@@ -0,0 +1,93 @@
1
+ Copyright 2014 The DM Sans Project Authors (https://github.com/googlefonts/dm-fonts) DMSans-Italic[opsz,wght].ttf: Copyright 2014 The DM Sans Project Authors (https://github.com/googlefonts/dm-fonts)
2
+
3
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
4
+ This license is copied below, and is also available with a FAQ at:
5
+ http://scripts.sil.org/OFL
6
+
7
+
8
+ -----------------------------------------------------------
9
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10
+ -----------------------------------------------------------
11
+
12
+ PREAMBLE
13
+ The goals of the Open Font License (OFL) are to stimulate worldwide
14
+ development of collaborative font projects, to support the font creation
15
+ efforts of academic and linguistic communities, and to provide a free and
16
+ open framework in which fonts may be shared and improved in partnership
17
+ with others.
18
+
19
+ The OFL allows the licensed fonts to be used, studied, modified and
20
+ redistributed freely as long as they are not sold by themselves. The
21
+ fonts, including any derivative works, can be bundled, embedded,
22
+ redistributed and/or sold with any software provided that any reserved
23
+ names are not used by derivative works. The fonts and derivatives,
24
+ however, cannot be released under any other type of license. The
25
+ requirement for fonts to remain under this license does not apply
26
+ to any document created using the fonts or their derivatives.
27
+
28
+ DEFINITIONS
29
+ "Font Software" refers to the set of files released by the Copyright
30
+ Holder(s) under this license and clearly marked as such. This may
31
+ include source files, build scripts and documentation.
32
+
33
+ "Reserved Font Name" refers to any names specified as such after the
34
+ copyright statement(s).
35
+
36
+ "Original Version" refers to the collection of Font Software components as
37
+ distributed by the Copyright Holder(s).
38
+
39
+ "Modified Version" refers to any derivative made by adding to, deleting,
40
+ or substituting -- in part or in whole -- any of the components of the
41
+ Original Version, by changing formats or by porting the Font Software to a
42
+ new environment.
43
+
44
+ "Author" refers to any designer, engineer, programmer, technical
45
+ writer or other person who contributed to the Font Software.
46
+
47
+ PERMISSION & CONDITIONS
48
+ Permission is hereby granted, free of charge, to any person obtaining
49
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
50
+ redistribute, and sell modified and unmodified copies of the Font
51
+ Software, subject to the following conditions:
52
+
53
+ 1) Neither the Font Software nor any of its individual components,
54
+ in Original or Modified Versions, may be sold by itself.
55
+
56
+ 2) Original or Modified Versions of the Font Software may be bundled,
57
+ redistributed and/or sold with any software, provided that each copy
58
+ contains the above copyright notice and this license. These can be
59
+ included either as stand-alone text files, human-readable headers or
60
+ in the appropriate machine-readable metadata fields within text or
61
+ binary files as long as those fields can be easily viewed by the user.
62
+
63
+ 3) No Modified Version of the Font Software may use the Reserved Font
64
+ Name(s) unless explicit written permission is granted by the corresponding
65
+ Copyright Holder. This restriction only applies to the primary font name as
66
+ presented to the users.
67
+
68
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69
+ Software shall not be used to promote, endorse or advertise any
70
+ Modified Version, except to acknowledge the contribution(s) of the
71
+ Copyright Holder(s) and the Author(s) or with their explicit written
72
+ permission.
73
+
74
+ 5) The Font Software, modified or unmodified, in part or in whole,
75
+ must be distributed entirely under this license, and must not be
76
+ distributed under any other license. The requirement for fonts to
77
+ remain under this license does not apply to any document created
78
+ using the Font Software.
79
+
80
+ TERMINATION
81
+ This license becomes null and void if any of the above conditions are
82
+ not met.
83
+
84
+ DISCLAIMER
85
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93
+ OTHER DEALINGS IN THE FONT SOFTWARE.
@@ -0,0 +1,93 @@
1
+ Google Inc.
2
+
3
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
4
+ This license is copied below, and is also available with a FAQ at:
5
+ http://scripts.sil.org/OFL
6
+
7
+
8
+ -----------------------------------------------------------
9
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10
+ -----------------------------------------------------------
11
+
12
+ PREAMBLE
13
+ The goals of the Open Font License (OFL) are to stimulate worldwide
14
+ development of collaborative font projects, to support the font creation
15
+ efforts of academic and linguistic communities, and to provide a free and
16
+ open framework in which fonts may be shared and improved in partnership
17
+ with others.
18
+
19
+ The OFL allows the licensed fonts to be used, studied, modified and
20
+ redistributed freely as long as they are not sold by themselves. The
21
+ fonts, including any derivative works, can be bundled, embedded,
22
+ redistributed and/or sold with any software provided that any reserved
23
+ names are not used by derivative works. The fonts and derivatives,
24
+ however, cannot be released under any other type of license. The
25
+ requirement for fonts to remain under this license does not apply
26
+ to any document created using the fonts or their derivatives.
27
+
28
+ DEFINITIONS
29
+ "Font Software" refers to the set of files released by the Copyright
30
+ Holder(s) under this license and clearly marked as such. This may
31
+ include source files, build scripts and documentation.
32
+
33
+ "Reserved Font Name" refers to any names specified as such after the
34
+ copyright statement(s).
35
+
36
+ "Original Version" refers to the collection of Font Software components as
37
+ distributed by the Copyright Holder(s).
38
+
39
+ "Modified Version" refers to any derivative made by adding to, deleting,
40
+ or substituting -- in part or in whole -- any of the components of the
41
+ Original Version, by changing formats or by porting the Font Software to a
42
+ new environment.
43
+
44
+ "Author" refers to any designer, engineer, programmer, technical
45
+ writer or other person who contributed to the Font Software.
46
+
47
+ PERMISSION & CONDITIONS
48
+ Permission is hereby granted, free of charge, to any person obtaining
49
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
50
+ redistribute, and sell modified and unmodified copies of the Font
51
+ Software, subject to the following conditions:
52
+
53
+ 1) Neither the Font Software nor any of its individual components,
54
+ in Original or Modified Versions, may be sold by itself.
55
+
56
+ 2) Original or Modified Versions of the Font Software may be bundled,
57
+ redistributed and/or sold with any software, provided that each copy
58
+ contains the above copyright notice and this license. These can be
59
+ included either as stand-alone text files, human-readable headers or
60
+ in the appropriate machine-readable metadata fields within text or
61
+ binary files as long as those fields can be easily viewed by the user.
62
+
63
+ 3) No Modified Version of the Font Software may use the Reserved Font
64
+ Name(s) unless explicit written permission is granted by the corresponding
65
+ Copyright Holder. This restriction only applies to the primary font name as
66
+ presented to the users.
67
+
68
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69
+ Software shall not be used to promote, endorse or advertise any
70
+ Modified Version, except to acknowledge the contribution(s) of the
71
+ Copyright Holder(s) and the Author(s) or with their explicit written
72
+ permission.
73
+
74
+ 5) The Font Software, modified or unmodified, in part or in whole,
75
+ must be distributed entirely under this license, and must not be
76
+ distributed under any other license. The requirement for fonts to
77
+ remain under this license does not apply to any document created
78
+ using the Font Software.
79
+
80
+ TERMINATION
81
+ This license becomes null and void if any of the above conditions are
82
+ not met.
83
+
84
+ DISCLAIMER
85
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93
+ OTHER DEALINGS IN THE FONT SOFTWARE.
@@ -0,0 +1,21 @@
1
+ name: Design system
2
+ on:
3
+ push:
4
+ pull_request:
5
+ permissions:
6
+ contents: read
7
+ jobs:
8
+ verify:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+ - uses: actions/setup-node@v4
13
+ with:
14
+ node-version: 22
15
+ cache: npm
16
+ - run: npm ci
17
+ - run: npm run check
18
+ - run: npm run build
19
+ - run: npm test
20
+ - run: git diff --exit-code -- dist
21
+ - run: npm pack --dry-run
@@ -0,0 +1,5 @@
1
+ node_modules
2
+ .DS_Store
3
+ *.log
4
+ *.tgz
5
+ output/
@@ -0,0 +1,10 @@
1
+ # Hyeonse Design System 작업 지침
2
+
3
+ 이 저장소는 개인 프로젝트용 디자인 시스템입니다. 기존 화면의 목적과 실제 사용 맥락을 먼저 확인하고, 역할 토큰과 검증 가능한 상태를 기준으로 작업합니다.
4
+
5
+ - 공개 계약은 `package.json`의 exports, `src/`, `docs/api.md`를 함께 확인합니다. 문서만 보고 존재하지 않는 컴포넌트를 가정하지 않습니다.
6
+ - 기존 포트폴리오의 디자인 원칙은 `docs/foundations.md`에 요약되어 있습니다. 원본 구현이 필요할 때만 `https://github.com/hyeonse-swing/hyeonse-portfolio/blob/main/DESIGN_SYSTEM.md`를 참고합니다.
7
+ - 새 화면이나 이관은 사용자 범위와 기존 동작을 보존합니다. 토큰 매핑은 색 값의 근접성보다 의미와 대비를 먼저 봅니다.
8
+ - 상태 변경은 키보드, 좁은 화면, 밝음·어두움, 기기 움직임 감소 설정에서 확인합니다. 확인하지 않은 상태를 통과했다고 기록하지 않습니다.
9
+ - 외부 사이트 게시, 커밋·푸시·PR 생성은 별도 요청 없이 진행하지 않습니다.
10
+ - `skills/hyeonse-design-system/SKILL.md`는 이 저장소와 함께 제공하는 개인용 작업 지침입니다. 설치하거나 전역 설정을 바꾸지 않습니다.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Hyeonse Im
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,67 @@
1
+ # Hyeonse Design System
2
+
3
+ 개인 프로젝트에서 같은 시각 언어와 화면 설정을 재사용하기 위한 작은 디자인 시스템입니다. 흰 바탕, 짙은 글자, 코발트 강조색을 기본으로 하며 포레스트·코랄 강조색과 다크 화면을 지원합니다. 출발점은 [포트폴리오의 실제 구현](https://github.com/hyeonse-swing/hyeonse-portfolio/blob/main/DESIGN_SYSTEM.md)입니다.
4
+
5
+ ## 사용
6
+
7
+ Node.js 22 이상과 npm을 사용합니다. npm 레지스트리에 게시하지 않고 GitHub 버전에서 설치합니다.
8
+
9
+ ```sh
10
+ npm install github:hyeonse-swing/hyeonse-design-system#v0.1.0
11
+ ```
12
+
13
+ 배포하는 앱에서는 검증한 전체 커밋 SHA로 고정하는 것을 권장합니다. 빌드된 `dist/`가 저장소에 포함되어 설치 시 별도 빌드는 필요하지 않습니다. 저장소를 개발하거나 견본을 확인할 때는 다음을 실행합니다.
14
+
15
+ ```sh
16
+ cd hyeonse-design-system
17
+ npm ci
18
+ npm run build
19
+ npm run check
20
+ npm test
21
+ python3 -m http.server 8000
22
+ ```
23
+
24
+ 브라우저에서 `http://localhost:8000/`을 열면 [쇼케이스](index.html)를 볼 수 있습니다. 빌드된 `dist/`를 참조하므로 먼저 `npm run build`를 실행해야 합니다.
25
+
26
+ 개인용 스킬은 소비 프로젝트에서 다음 명령으로 추가할 수 있습니다.
27
+
28
+ ```sh
29
+ npx skills add hyeonse-swing/hyeonse-design-system --skill hyeonse-design-system
30
+ ```
31
+
32
+ CSS만 필요한 화면에는 두 파일을 순서대로 불러옵니다.
33
+
34
+ ```css
35
+ @import '@hyeonse/design-system/tokens.css';
36
+ @import '@hyeonse/design-system/components.css';
37
+ ```
38
+
39
+ React 화면에서는 `@hyeonse/design-system/react`의 `PreferencesProvider`, `ThemeToggle`, `PreferencesPanel`, `usePreferences`를 사용합니다. 초기 테마 깜빡임을 줄이려면 `@hyeonse/design-system/preferences`의 `preferenceScript`를 문서 `<head>`에 CSS보다 먼저 삽입하세요. 다른 저장 키가 필요하면 `createPreferenceScript(storageKey)`를 사용하고 Provider에도 같은 `storageKey`를 전달합니다. 기본 저장 키는 `hyeonse-site-preferences`입니다.
40
+
41
+ ```tsx
42
+ import { PreferencesProvider, ThemeToggle, PreferencesPanel } from '@hyeonse/design-system/react';
43
+ import { preferenceScript } from '@hyeonse/design-system/preferences';
44
+ import '@hyeonse/design-system/tokens.css';
45
+ import '@hyeonse/design-system/components.css';
46
+
47
+ // 서버 문서의 <head> 안에서 CSS보다 먼저: <script dangerouslySetInnerHTML={{ __html: preferenceScript }} />
48
+ export function DisplaySettings() {
49
+ return <PreferencesProvider><ThemeToggle locale="ko" /><PreferencesPanel locale="ko" /></PreferencesProvider>;
50
+ }
51
+ ```
52
+
53
+ 설정 키나 이벤트 이름을 바꾸는 경우에는 [API 문서](docs/api.md)의 적용 범위를 확인하세요. 글꼴 파일은 [출처와 라이선스](THIRD_PARTY_NOTICES.md)를 확인한 뒤 제품 자산으로 따로 제공해야 합니다.
54
+
55
+ ## 구성
56
+
57
+ - [기초 규칙](docs/foundations.md): 색의 역할, 글자, 밀도, 모서리, 움직임.
58
+ - [API와 통합](docs/api.md): CSS 선택자와 TypeScript·React 공개 API.
59
+ - [개인용 스킬](skills/hyeonse-design-system/SKILL.md): 새 화면 제작, 확장, 토큰 매핑, 이관, 리뷰와 문서화의 작업 기준.
60
+
61
+ `src/`가 배포 코드의 기준이며 쇼케이스는 그 출력을 검토하는 정적 문서입니다. 쇼케이스의 예시 마크업은 CSS 상태 견본입니다. 라이브러리에서 일반 Button·Input React 컴포넌트를 제공한다는 의미는 아닙니다.
62
+
63
+ [실제 통합 검증 기록](docs/verification.md)에는 포트폴리오 이관 전후 비교와 확인 범위를 남겼습니다.
64
+
65
+ ## 소비 앱의 CSS 점검
66
+
67
+ 패키지 빌드 후 소비 앱 루트에서 `hds-audit <consumer-root> [config-relative-path]`를 실행할 수 있습니다. 기본 설정 파일은 소비 앱 루트의 `design-system.audit.json`입니다. [설정 형식과 한계](docs/audit.md)를 확인하세요. 이 검사는 CSS의 원시 색상 사용과 공유 토큰 재정의를 점검하며, TypeScript·JavaScript·3D 머티리얼까지 검사했다는 뜻은 아닙니다.
@@ -0,0 +1,5 @@
1
+ # 제3자 자료
2
+
3
+ 이 저장소의 시각 규칙과 구현은 [개인 포트폴리오 디자인 시스템](https://github.com/hyeonse-swing/hyeonse-portfolio/blob/main/DESIGN_SYSTEM.md)을 기반으로 합니다. 작업 흐름의 참고 자료는 [Arlan Marat의 `arla6ka/skills`](https://github.com/arla6ka/skills/tree/e6ca7a5ff640c133ad1290b1271a23324f255155/skills)입니다. 참조한 정확한 리비전은 `e6ca7a5ff640c133ad1290b1271a23324f255155`입니다. 원본은 MIT License이며 저작권 고지 전문은 [licenses/arla6ka-MIT.txt](licenses/arla6ka-MIT.txt)에 보존했습니다. 이 저장소에는 원본의 여러 스킬을 복제하지 않고 개인 작업에 맞춘 하나의 스킬을 작성했습니다.
4
+
5
+ 쇼케이스의 DM Sans와 Noto Sans KR 글꼴 파일은 기존 포트폴리오 자산에서 복사했습니다. 각 라이선스 전문은 [DM Sans](licenses/DM-Sans-LICENSE.txt), [Noto Sans KR](licenses/Noto-Sans-KR-LICENSE.txt)에 있습니다. 한국어 서브셋은 기존 포트폴리오의 공개 문구용이므로 새 화면의 전체 한국어 문자 지원을 보장하지 않습니다.