openuispec 0.1.27 → 0.1.29
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.
- package/README.md +52 -55
- package/cli/configure-target.ts +416 -0
- package/cli/index.ts +14 -3
- package/cli/init.ts +241 -55
- package/cli/target-presets.json +746 -0
- package/docs/implementation-notes.md +47 -10
- package/docs/release-notes-v0.1.26.md +1 -1
- package/docs/release-notes-v0.1.28.md +25 -0
- package/docs/stress-test-maturity-report.md +1 -1
- package/drift/index.ts +31 -11
- package/examples/taskflow/AGENTS.md +113 -0
- package/examples/taskflow/CLAUDE.md +113 -0
- package/examples/taskflow/backend/.gitkeep +1 -0
- package/examples/taskflow/generated/android/TaskFlow/README.md +43 -0
- package/examples/taskflow/generated/android/TaskFlow/app/build.gradle.kts +76 -0
- package/examples/taskflow/generated/android/TaskFlow/app/proguard-rules.pro +1 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/AndroidManifest.xml +21 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/MainActivity.kt +19 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/TaskFlowApp.kt +283 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/model/DomainModels.kt +106 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/model/SampleData.kt +57 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/components/Common.kt +109 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/screens/HomeScreen.kt +112 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/screens/ProjectsScreen.kt +61 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/screens/SettingsScreen.kt +82 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/screens/TaskDetailScreen.kt +111 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/sheets/Sheets.kt +77 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/theme/Color.kt +30 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/theme/Theme.kt +86 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/java/uz/rsteam/taskflow/ui/theme/Type.kt +57 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/res/values/strings.xml +155 -0
- package/examples/taskflow/generated/android/TaskFlow/app/src/main/res/values/themes.xml +4 -0
- package/examples/taskflow/generated/android/TaskFlow/build.gradle.kts +5 -0
- package/examples/taskflow/generated/android/TaskFlow/gradle/gradle-daemon-jvm.properties +12 -0
- package/examples/taskflow/generated/android/TaskFlow/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/examples/taskflow/generated/android/TaskFlow/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/examples/taskflow/generated/android/TaskFlow/gradle.properties +4 -0
- package/examples/taskflow/generated/android/TaskFlow/gradlew +18 -0
- package/examples/taskflow/generated/android/TaskFlow/gradlew.bat +12 -0
- package/examples/taskflow/generated/android/TaskFlow/settings.gradle.kts +18 -0
- package/examples/taskflow/generated/ios/TaskFlow/README.md +21 -0
- package/examples/taskflow/generated/ios/TaskFlow/Resources/en.lproj/Localizable.strings +115 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/App/TaskFlowApp.swift +24 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Components/AppChrome.swift +150 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Flows/TaskEditorSheet.swift +220 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Models/DomainModels.swift +122 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/CalendarView.swift +21 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/HomeView.swift +201 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/ProfileEditView.swift +48 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/ProjectDetailView.swift +59 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/ProjectsView.swift +63 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/SettingsView.swift +85 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Screens/TaskDetailView.swift +219 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Support/AppModel.swift +320 -0
- package/examples/taskflow/generated/ios/TaskFlow/Sources/TaskFlow/Support/AppSupport.swift +41 -0
- package/examples/taskflow/generated/ios/TaskFlow/project.yml +26 -0
- package/examples/taskflow/generated/web/TaskFlow/README.md +19 -0
- package/examples/taskflow/generated/web/TaskFlow/index.html +12 -0
- package/examples/taskflow/generated/web/TaskFlow/package-lock.json +1908 -0
- package/examples/taskflow/generated/web/TaskFlow/package.json +24 -0
- package/examples/taskflow/generated/web/TaskFlow/src/App.tsx +58 -0
- package/examples/taskflow/generated/web/TaskFlow/src/AppShell.tsx +55 -0
- package/examples/taskflow/generated/web/TaskFlow/src/components/Common.tsx +82 -0
- package/examples/taskflow/generated/web/TaskFlow/src/components/Modals.tsx +191 -0
- package/examples/taskflow/generated/web/TaskFlow/src/components/Nav.tsx +41 -0
- package/examples/taskflow/generated/web/TaskFlow/src/generated/messages.ts +131 -0
- package/examples/taskflow/generated/web/TaskFlow/src/hooks.ts +25 -0
- package/examples/taskflow/generated/web/TaskFlow/src/i18n.ts +39 -0
- package/examples/taskflow/generated/web/TaskFlow/src/locales.en.json +111 -0
- package/examples/taskflow/generated/web/TaskFlow/src/main.tsx +13 -0
- package/examples/taskflow/generated/web/TaskFlow/src/screens/HomeScreen.tsx +111 -0
- package/examples/taskflow/generated/web/TaskFlow/src/screens/ProjectsScreen.tsx +82 -0
- package/examples/taskflow/generated/web/TaskFlow/src/screens/SettingsScreens.tsx +132 -0
- package/examples/taskflow/generated/web/TaskFlow/src/screens/TaskDetail.tsx +105 -0
- package/examples/taskflow/generated/web/TaskFlow/src/store.ts +216 -0
- package/examples/taskflow/generated/web/TaskFlow/src/styles.css +617 -0
- package/examples/taskflow/generated/web/TaskFlow/src/types.ts +64 -0
- package/examples/taskflow/generated/web/TaskFlow/src/utils.ts +78 -0
- package/examples/taskflow/generated/web/TaskFlow/tsconfig.json +21 -0
- package/examples/taskflow/generated/web/TaskFlow/vite.config.ts +6 -0
- package/examples/taskflow/openuispec/README.md +54 -0
- package/examples/taskflow/{openuispec.yaml → openuispec/openuispec.yaml} +2 -0
- package/examples/todo-orbit/AGENTS.md +48 -22
- package/examples/todo-orbit/CLAUDE.md +48 -22
- package/examples/todo-orbit/backend/.gitkeep +1 -0
- package/examples/todo-orbit/openuispec/README.md +9 -4
- package/examples/todo-orbit/openuispec/openuispec.yaml +2 -0
- package/package.json +1 -1
- package/prepare/index.ts +811 -25
- package/schema/openuispec.schema.json +10 -0
- package/schema/semantic-lint.ts +36 -12
- package/schema/validate.ts +9 -4
- package/status/index.ts +16 -3
- /package/examples/taskflow/{contracts → openuispec/contracts}/README.md +0 -0
- /package/examples/taskflow/{contracts → openuispec/contracts}/action_trigger.yaml +0 -0
- /package/examples/taskflow/{contracts → openuispec/contracts}/collection.yaml +0 -0
- /package/examples/taskflow/{contracts → openuispec/contracts}/data_display.yaml +0 -0
- /package/examples/taskflow/{contracts → openuispec/contracts}/feedback.yaml +0 -0
- /package/examples/taskflow/{contracts → openuispec/contracts}/input_field.yaml +0 -0
- /package/examples/taskflow/{contracts → openuispec/contracts}/nav_container.yaml +0 -0
- /package/examples/taskflow/{contracts → openuispec/contracts}/surface.yaml +0 -0
- /package/examples/taskflow/{contracts → openuispec/contracts}/x_media_player.yaml +0 -0
- /package/examples/taskflow/{flows → openuispec/flows}/create_task.yaml +0 -0
- /package/examples/taskflow/{flows → openuispec/flows}/edit_task.yaml +0 -0
- /package/examples/taskflow/{locales → openuispec/locales}/en.json +0 -0
- /package/examples/taskflow/{platform → openuispec/platform}/android.yaml +0 -0
- /package/examples/taskflow/{platform → openuispec/platform}/ios.yaml +0 -0
- /package/examples/taskflow/{platform → openuispec/platform}/web.yaml +0 -0
- /package/examples/taskflow/{screens → openuispec/screens}/calendar.yaml +0 -0
- /package/examples/taskflow/{screens → openuispec/screens}/home.yaml +0 -0
- /package/examples/taskflow/{screens → openuispec/screens}/profile_edit.yaml +0 -0
- /package/examples/taskflow/{screens → openuispec/screens}/project_detail.yaml +0 -0
- /package/examples/taskflow/{screens → openuispec/screens}/projects.yaml +0 -0
- /package/examples/taskflow/{screens → openuispec/screens}/settings.yaml +0 -0
- /package/examples/taskflow/{screens → openuispec/screens}/task_detail.yaml +0 -0
- /package/examples/taskflow/{tokens → openuispec/tokens}/color.yaml +0 -0
- /package/examples/taskflow/{tokens → openuispec/tokens}/elevation.yaml +0 -0
- /package/examples/taskflow/{tokens → openuispec/tokens}/icons.yaml +0 -0
- /package/examples/taskflow/{tokens → openuispec/tokens}/layout.yaml +0 -0
- /package/examples/taskflow/{tokens → openuispec/tokens}/motion.yaml +0 -0
- /package/examples/taskflow/{tokens → openuispec/tokens}/spacing.yaml +0 -0
- /package/examples/taskflow/{tokens → openuispec/tokens}/themes.yaml +0 -0
- /package/examples/taskflow/{tokens → openuispec/tokens}/typography.yaml +0 -0
|
@@ -36,24 +36,57 @@
|
|
|
36
36
|
|
|
37
37
|
## `prepare` command
|
|
38
38
|
|
|
39
|
-
- `openuispec prepare --target <target>` is the operational bridge between spec
|
|
39
|
+
- `openuispec prepare --target <target>` is the operational bridge between the spec and AI implementation work.
|
|
40
|
+
- `openuispec configure-target <target>` is the target stack selection step that feeds `prepare`.
|
|
41
|
+
- it should offer preset defaults for known stacks
|
|
42
|
+
- it must still allow custom values when the project uses frameworks or libraries outside the catalog
|
|
43
|
+
- `openuispec init --no-configure-targets` should remain available for users who want to defer target stack decisions until later
|
|
44
|
+
- It should support two modes:
|
|
45
|
+
1. bootstrap mode when no target snapshot exists yet
|
|
46
|
+
2. update mode when a target snapshot exists
|
|
40
47
|
- It should be documented as:
|
|
41
|
-
1.
|
|
42
|
-
2. compute semantic spec changes since that baseline
|
|
43
|
-
3. produce
|
|
48
|
+
1. if no snapshot exists, produce a first-time generation bundle from the manifest and current spec files
|
|
49
|
+
2. if a snapshot exists, compute semantic spec changes since that baseline
|
|
50
|
+
3. produce the target work bundle with likely target scope
|
|
44
51
|
- Current output includes:
|
|
45
52
|
- project and target
|
|
46
53
|
- output directory
|
|
47
54
|
- likely code roots
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
55
|
+
- mode (`bootstrap` or `update`)
|
|
56
|
+
- baseline commit info when available
|
|
57
|
+
- target stack summary from `platform/<target>.yaml`
|
|
58
|
+
- selected option refs for known preset values
|
|
59
|
+
- semantic change summary for update mode
|
|
60
|
+
- per-spec-file work items or first-time generation spec inventory
|
|
61
|
+
- best-effort candidate target files for update mode
|
|
52
62
|
- next-step guidance
|
|
63
|
+
- Selected option refs should be package-manager oriented, not artifact web pages:
|
|
64
|
+
- Android: Gradle plugin ids plus `group:artifact:{latest}` library coordinates
|
|
65
|
+
- Web: npm package specs like `react-router@{latest}`
|
|
66
|
+
- iOS: package identifiers plus docs links
|
|
67
|
+
- `prepare` must also carry dependency guidance explaining that these refs are anchors only.
|
|
68
|
+
- AI should add supporting build, plugin, repository, annotation-processing, runtime, dev, and test dependencies required by the chosen stack and current toolchain
|
|
69
|
+
- AI should resolve exact versions and wiring from current platform docs instead of assuming the preset list is exhaustive
|
|
70
|
+
- Bootstrap mode should surface soft warnings when configured framework/stack values are custom and therefore not covered by preset dependency refs.
|
|
71
|
+
- these warnings should explain that dependency guidance is incomplete, not silently omit the missing refs
|
|
72
|
+
- Bootstrap mode should also carry explicit generation constraints for the target:
|
|
73
|
+
- localization rules
|
|
74
|
+
- use target-native runtime localization resources
|
|
75
|
+
- forbid in-memory string maps embedded in app code
|
|
76
|
+
- file structure rules
|
|
77
|
+
- forbid single-file app output
|
|
78
|
+
- require separate screen/component/support/resource modules
|
|
79
|
+
- platform setup rules
|
|
80
|
+
- refresh current target/framework setup guidance before generation
|
|
81
|
+
- do not rely on stale memory for project layout, resource wiring, navigation APIs, or packaging conventions
|
|
82
|
+
- target-specific directory expectations for generated code
|
|
83
|
+
- backend generation context
|
|
84
|
+
- if the manifest declares `api.endpoints`, `generation.code_roots.backend` is required
|
|
85
|
+
- `prepare` should surface the resolved backend root so AI can inspect backend code when generating API clients
|
|
53
86
|
- Important positioning:
|
|
54
87
|
- `prepare` does not generate code
|
|
55
88
|
- `prepare` does not verify code correctness
|
|
56
|
-
- `prepare` packages the spec delta into scoped implementation work for AI or developers
|
|
89
|
+
- `prepare` packages either the current spec or the spec delta into scoped implementation work for AI or developers
|
|
57
90
|
|
|
58
91
|
## Semantic linting
|
|
59
92
|
|
|
@@ -86,6 +119,7 @@
|
|
|
86
119
|
- `openuispec status` is the cross-target overview command.
|
|
87
120
|
- Current output includes, per target:
|
|
88
121
|
- output directory
|
|
122
|
+
- whether the output directory exists
|
|
89
123
|
- snapshot present or missing
|
|
90
124
|
- snapshot timestamp
|
|
91
125
|
- baseline kind / commit / branch
|
|
@@ -95,6 +129,7 @@
|
|
|
95
129
|
- note for missing or legacy snapshots
|
|
96
130
|
- Important positioning:
|
|
97
131
|
- `status` answers "which targets are behind shared spec changes?"
|
|
132
|
+
- `status` should distinguish "needs generation" from "needs baseline"
|
|
98
133
|
- `status` does not verify code alignment
|
|
99
134
|
- Real-world behavior to document:
|
|
100
135
|
- if `web` was re-snapshotted after the new baseline metadata was added, but `ios` and `android` still have older state files, `status` should show:
|
|
@@ -111,5 +146,7 @@
|
|
|
111
146
|
5. `openuispec prepare --target <target>`
|
|
112
147
|
6. update target UI code
|
|
113
148
|
7. build/run and review
|
|
114
|
-
8.
|
|
149
|
+
8. ensure the target output directory exists
|
|
150
|
+
9. `openuispec drift --snapshot --target <target>`
|
|
115
151
|
- `drift --snapshot` should continue to be described as bookkeeping/baselining, not as proof that the target implementation matches the spec.
|
|
152
|
+
- If the target output directory does not exist yet, the CLI should direct the user to run code generation first instead of implying that snapshot can initialize an empty target.
|
|
@@ -11,7 +11,7 @@ This release expands OpenUISpec as a spec-management and AI-orchestration tool f
|
|
|
11
11
|
Drift snapshots now record the git baseline commit and branch for each target.
|
|
12
12
|
|
|
13
13
|
- `openuispec prepare --target <target>`
|
|
14
|
-
Produces
|
|
14
|
+
Produces the target work bundle with:
|
|
15
15
|
- semantic change summary
|
|
16
16
|
- likely code roots
|
|
17
17
|
- candidate target files
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# OpenUISpec v0.1.28
|
|
2
|
+
|
|
3
|
+
This patch supersedes `v0.1.27`.
|
|
4
|
+
|
|
5
|
+
## Fixes
|
|
6
|
+
|
|
7
|
+
- Fixed the drift/prepare onboarding dead-end for targets that have not been generated yet.
|
|
8
|
+
- `drift --snapshot` now keeps the guard against baselining an empty target.
|
|
9
|
+
- Missing-snapshot guidance now tells users to generate the target output first when the output directory does not exist.
|
|
10
|
+
- Improved `status` to distinguish:
|
|
11
|
+
- targets that need generation
|
|
12
|
+
- targets that need a baseline snapshot
|
|
13
|
+
- Updated workflow docs and generated project templates to describe the generation-first requirement before snapshotting.
|
|
14
|
+
- Stabilized the affected CLI tests in this repo by invoking TypeScript entrypoints through the `tsx` loader path instead of the IPC-based binary wrapper.
|
|
15
|
+
|
|
16
|
+
## Recommended workflow
|
|
17
|
+
|
|
18
|
+
1. `openuispec validate`
|
|
19
|
+
2. `openuispec validate semantic`
|
|
20
|
+
3. `openuispec status`
|
|
21
|
+
4. `openuispec drift --target <target> --explain`
|
|
22
|
+
5. `openuispec prepare --target <target>`
|
|
23
|
+
6. update target UI
|
|
24
|
+
7. ensure the target output directory exists
|
|
25
|
+
8. `openuispec drift --snapshot --target <target>`
|
|
@@ -14,7 +14,7 @@ This assessment stress-tested the project at four layers:
|
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
npm ci
|
|
17
|
-
npm run validate # from examples/taskflow (workspace script)
|
|
17
|
+
npm run validate # from examples/taskflow/openuispec (workspace script)
|
|
18
18
|
npx tsx ../../../schema/validate.ts # from examples/todo-orbit/openuispec
|
|
19
19
|
npx tsc --noEmit
|
|
20
20
|
for t in ios android web; do
|
package/drift/index.ts
CHANGED
|
@@ -73,7 +73,7 @@ export interface ExplainResult {
|
|
|
73
73
|
|
|
74
74
|
// ── helpers ───────────────────────────────────────────────────────────
|
|
75
75
|
|
|
76
|
-
function listFiles(dir: string, ext: string): string[] {
|
|
76
|
+
export function listFiles(dir: string, ext: string): string[] {
|
|
77
77
|
try {
|
|
78
78
|
return readdirSync(dir)
|
|
79
79
|
.filter((f) => f.endsWith(ext))
|
|
@@ -106,7 +106,7 @@ function parseSpecDocument(relPath: string, content: string): unknown {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
/** Read the status field from a screen or flow YAML file. */
|
|
109
|
-
function readStatus(filePath: string): string {
|
|
109
|
+
export function readStatus(filePath: string): string {
|
|
110
110
|
try {
|
|
111
111
|
const doc = YAML.parse(readFileSync(filePath, "utf-8"));
|
|
112
112
|
if (doc && typeof doc === "object") {
|
|
@@ -123,12 +123,12 @@ function readStatus(filePath: string): string {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
/** Returns true if a file is a screen or flow (has status semantics). */
|
|
126
|
-
function hasStatusSemantics(relPath: string): boolean {
|
|
126
|
+
export function hasStatusSemantics(relPath: string): boolean {
|
|
127
127
|
const dir = dirname(relPath);
|
|
128
128
|
return dir === "screens" || dir === "flows";
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
function discoverSpecFiles(projectDir: string): string[] {
|
|
131
|
+
export function discoverSpecFiles(projectDir: string): string[] {
|
|
132
132
|
const manifest = join(projectDir, "openuispec.yaml");
|
|
133
133
|
if (!existsSync(manifest)) {
|
|
134
134
|
console.error(`Error: No openuispec.yaml found in ${projectDir}`);
|
|
@@ -434,11 +434,14 @@ export function findProjectDir(cwd: string): string {
|
|
|
434
434
|
process.exit(1);
|
|
435
435
|
}
|
|
436
436
|
|
|
437
|
+
/** Read and parse the manifest YAML. */
|
|
438
|
+
export function readManifest(projectDir: string): Record<string, any> {
|
|
439
|
+
return YAML.parse(readFileSync(join(projectDir, "openuispec.yaml"), "utf-8"));
|
|
440
|
+
}
|
|
441
|
+
|
|
437
442
|
/** Read the project name from the manifest. */
|
|
438
443
|
export function readProjectName(projectDir: string): string {
|
|
439
|
-
const doc =
|
|
440
|
-
readFileSync(join(projectDir, "openuispec.yaml"), "utf-8")
|
|
441
|
-
);
|
|
444
|
+
const doc = readManifest(projectDir);
|
|
442
445
|
return doc.project?.name ?? basename(projectDir);
|
|
443
446
|
}
|
|
444
447
|
|
|
@@ -466,6 +469,26 @@ export function stateFilePath(projectDir: string, projectName: string, target: s
|
|
|
466
469
|
return join(resolveOutputDir(projectDir, projectName, target), STATE_FILE);
|
|
467
470
|
}
|
|
468
471
|
|
|
472
|
+
function missingSnapshotMessage(
|
|
473
|
+
cwd: string,
|
|
474
|
+
projectDir: string,
|
|
475
|
+
projectName: string,
|
|
476
|
+
target: string
|
|
477
|
+
): string {
|
|
478
|
+
const outDir = resolveOutputDir(projectDir, projectName, target);
|
|
479
|
+
if (!existsSync(outDir)) {
|
|
480
|
+
return (
|
|
481
|
+
`No snapshot found for target "${target}".\n` +
|
|
482
|
+
`Output directory not found: ${relative(cwd, outDir)}\n` +
|
|
483
|
+
`Run code generation for "${target}" first, then run: openuispec drift --snapshot --target ${target}`
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
return (
|
|
487
|
+
`No snapshot found for target "${target}".\n` +
|
|
488
|
+
`Run: openuispec drift --snapshot --target ${target}`
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
|
|
469
492
|
export function discoverTargets(projectDir: string, projectName: string): string[] {
|
|
470
493
|
const outputDirs = readOutputDirs(projectDir);
|
|
471
494
|
const targets: string[] = [];
|
|
@@ -626,10 +649,7 @@ export function loadTargetDrift(
|
|
|
626
649
|
const projectName = readProjectName(projectDir);
|
|
627
650
|
const statePath = stateFilePath(projectDir, projectName, target);
|
|
628
651
|
if (!existsSync(statePath)) {
|
|
629
|
-
console.error(
|
|
630
|
-
`No snapshot found for target "${target}".\n` +
|
|
631
|
-
`Run: openuispec drift --snapshot --target ${target}`
|
|
632
|
-
);
|
|
652
|
+
console.error(missingSnapshotMessage(cwd, projectDir, projectName, target));
|
|
633
653
|
process.exit(1);
|
|
634
654
|
}
|
|
635
655
|
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<!-- openuispec-rules-start -->
|
|
2
|
+
<!-- openuispec-rules-version: 0.1.28 -->
|
|
3
|
+
# OpenUISpec — AI Assistant Rules
|
|
4
|
+
# ================================
|
|
5
|
+
# This project uses OpenUISpec to define UI as a semantic spec.
|
|
6
|
+
# Spec files are the single source of truth for all UI across platforms.
|
|
7
|
+
# Targets: "ios", "android", "web"
|
|
8
|
+
|
|
9
|
+
## IMPORTANT — Read the specification before working with spec files
|
|
10
|
+
|
|
11
|
+
The spec format, file schemas, and generation rules are defined in the installed `openuispec` package.
|
|
12
|
+
You MUST read the reference files listed below before creating, editing, or generating from any spec file.
|
|
13
|
+
Do NOT guess the file format — skipping this step will produce invalid YAML that fails validation.
|
|
14
|
+
|
|
15
|
+
**Find the package in this order:**
|
|
16
|
+
1. `node_modules/openuispec/` (project dependency)
|
|
17
|
+
2. Run `npm root -g` → `<prefix>/openuispec/` (global install)
|
|
18
|
+
3. Online: `https://openuispec.rsteam.uz/llms-full.txt` (if not installed)
|
|
19
|
+
|
|
20
|
+
**Reference files inside the package (read in this order):**
|
|
21
|
+
1. `README.md` — schema tables, file format reference, root wrapper keys
|
|
22
|
+
2. `spec/openuispec-v0.1.md` — full specification (contracts, layout, expressions, adaptive, etc.)
|
|
23
|
+
3. `examples/taskflow/openuispec/` — complete working example with all file types
|
|
24
|
+
4. `schema/` — JSON Schemas for every file type
|
|
25
|
+
|
|
26
|
+
These files are updated with each package version. Always read from the installed package,
|
|
27
|
+
not from cached or memorized content, to ensure you use the latest spec.
|
|
28
|
+
|
|
29
|
+
## What is OpenUISpec
|
|
30
|
+
OpenUISpec is a YAML-based spec format that describes an app's UI semantically — tokens, screens, flows, and platform overrides. AI reads the spec and generates native code (SwiftUI, Compose, React). AI reads native code and updates the spec. The spec is the sync layer between platforms.
|
|
31
|
+
|
|
32
|
+
## Spec location
|
|
33
|
+
- Spec root: `openuispec/`
|
|
34
|
+
- Manifest: `openuispec/openuispec.yaml` — always read this first.
|
|
35
|
+
- Tokens: `openuispec/tokens/`
|
|
36
|
+
- Screens: `openuispec/screens/`
|
|
37
|
+
- Flows: `openuispec/flows/`
|
|
38
|
+
- Contracts: `openuispec/contracts/`
|
|
39
|
+
- Platform: `openuispec/platform/`
|
|
40
|
+
- Locales: `openuispec/locales/`
|
|
41
|
+
|
|
42
|
+
**Note:** These are the default paths. Actual paths are in `includes:` in `openuispec.yaml` and may use relative paths. Always read `openuispec.yaml` to find the real directories.
|
|
43
|
+
|
|
44
|
+
## If spec directories are empty (first-time setup)
|
|
45
|
+
This means the project has existing UI code but hasn't been specced yet. Your job:
|
|
46
|
+
|
|
47
|
+
1. **Read the spec first** — find and read `spec/openuispec-v0.1.md` from the installed package.
|
|
48
|
+
2. **Find existing screens** — scan the codebase for UI screen files.
|
|
49
|
+
3. **Create stubs** — for each screen, create `openuispec/screens/<name>.yaml` with:
|
|
50
|
+
```yaml
|
|
51
|
+
screen_name:
|
|
52
|
+
semantic: "Brief description of what this screen does"
|
|
53
|
+
status: stub
|
|
54
|
+
layout:
|
|
55
|
+
type: scroll_vertical
|
|
56
|
+
```
|
|
57
|
+
4. **Extract tokens** — scan for colors, fonts, spacing and create files in `openuispec/tokens/`.
|
|
58
|
+
5. **Update the manifest** — fill in `data_model`, `api.endpoints`, and `generation.code_roots.backend` in `openuispec/openuispec.yaml`.
|
|
59
|
+
|
|
60
|
+
## OpenUISpec Source Of Truth
|
|
61
|
+
|
|
62
|
+
OpenUISpec spec files are the primary source of truth for UI behavior across platforms.
|
|
63
|
+
|
|
64
|
+
### Start from spec when:
|
|
65
|
+
- the request changes screen structure
|
|
66
|
+
- the request changes navigation
|
|
67
|
+
- the request changes fields, actions, validation, or data binding
|
|
68
|
+
- the request changes tokens, variants, contracts, flows, or localization
|
|
69
|
+
- the request affects more than one platform
|
|
70
|
+
- the request is phrased in product/UI terms rather than platform-code terms
|
|
71
|
+
|
|
72
|
+
Spec-first workflow:
|
|
73
|
+
1. Read `openuispec/openuispec.yaml` and the relevant spec files first.
|
|
74
|
+
2. Update the spec first.
|
|
75
|
+
3. Update the affected generated/native UI code to match the spec.
|
|
76
|
+
4. Run `openuispec validate`.
|
|
77
|
+
5. Run `openuispec validate semantic`.
|
|
78
|
+
6. Run `openuispec drift --target <target> --explain` to inspect semantic changes since that target's baseline.
|
|
79
|
+
7. Run `openuispec prepare --target <target>` to build the target work bundle for that target. In `bootstrap` mode it provides first-generation constraints; in `update` mode it provides drift-based update scope.
|
|
80
|
+
8. Verify the affected UI targets build/run if possible.
|
|
81
|
+
9. Only then run `openuispec drift --snapshot --target <target>` for affected targets, after that target output directory exists.
|
|
82
|
+
10. Run `openuispec drift --target <target> --explain` again to confirm no spec changes remain for that target.
|
|
83
|
+
11. Use `openuispec status` to see which other targets are still behind the updated spec.
|
|
84
|
+
|
|
85
|
+
### Start from platform code when:
|
|
86
|
+
- the change is platform-specific polish
|
|
87
|
+
- the change is a local bug fix that does not alter shared semantic behavior
|
|
88
|
+
- the request explicitly asks for an iOS-only, Android-only, or web-only adjustment
|
|
89
|
+
|
|
90
|
+
Platform-first workflow:
|
|
91
|
+
1. Update native/platform code.
|
|
92
|
+
2. If the change affects shared semantics, sync the spec afterward.
|
|
93
|
+
3. If the change is intentionally platform-specific, document it in `platform/*.yaml` when appropriate.
|
|
94
|
+
|
|
95
|
+
### Never do this:
|
|
96
|
+
- Do not snapshot drift immediately after changing spec unless the UI code has also been updated.
|
|
97
|
+
- Do not treat `openuispec drift` as proof that generated UI matches the spec.
|
|
98
|
+
- Do not skip `--explain` / `prepare` when another platform needs to catch up with shared spec changes.
|
|
99
|
+
- Do not modify generated UI without checking whether the spec must change first.
|
|
100
|
+
|
|
101
|
+
## CLI commands
|
|
102
|
+
- `openuispec init` — scaffold a new spec project
|
|
103
|
+
- `openuispec validate [group...]` — validate spec files against schemas
|
|
104
|
+
- `openuispec validate semantic` — run semantic cross-reference linting
|
|
105
|
+
- `openuispec configure-target <t> [--defaults]` — configure target stack defaults
|
|
106
|
+
- `openuispec drift --target <t>` — check for spec drift
|
|
107
|
+
- `openuispec drift --target <t> --explain` — explain semantic spec drift since the target baseline
|
|
108
|
+
- `openuispec drift --snapshot --target <t>` — snapshot current state after the target output exists
|
|
109
|
+
- `openuispec prepare --target <t>` — build the target work bundle
|
|
110
|
+
- `openuispec status` — show cross-target baseline/drift status
|
|
111
|
+
- `openuispec update-rules` — update AI rules to match installed package version
|
|
112
|
+
- `openuispec drift --all` — include stubs in drift check
|
|
113
|
+
<!-- openuispec-rules-end -->
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<!-- openuispec-rules-start -->
|
|
2
|
+
<!-- openuispec-rules-version: 0.1.28 -->
|
|
3
|
+
# OpenUISpec — AI Assistant Rules
|
|
4
|
+
# ================================
|
|
5
|
+
# This project uses OpenUISpec to define UI as a semantic spec.
|
|
6
|
+
# Spec files are the single source of truth for all UI across platforms.
|
|
7
|
+
# Targets: "ios", "android", "web"
|
|
8
|
+
|
|
9
|
+
## IMPORTANT — Read the specification before working with spec files
|
|
10
|
+
|
|
11
|
+
The spec format, file schemas, and generation rules are defined in the installed `openuispec` package.
|
|
12
|
+
You MUST read the reference files listed below before creating, editing, or generating from any spec file.
|
|
13
|
+
Do NOT guess the file format — skipping this step will produce invalid YAML that fails validation.
|
|
14
|
+
|
|
15
|
+
**Find the package in this order:**
|
|
16
|
+
1. `node_modules/openuispec/` (project dependency)
|
|
17
|
+
2. Run `npm root -g` → `<prefix>/openuispec/` (global install)
|
|
18
|
+
3. Online: `https://openuispec.rsteam.uz/llms-full.txt` (if not installed)
|
|
19
|
+
|
|
20
|
+
**Reference files inside the package (read in this order):**
|
|
21
|
+
1. `README.md` — schema tables, file format reference, root wrapper keys
|
|
22
|
+
2. `spec/openuispec-v0.1.md` — full specification (contracts, layout, expressions, adaptive, etc.)
|
|
23
|
+
3. `examples/taskflow/openuispec/` — complete working example with all file types
|
|
24
|
+
4. `schema/` — JSON Schemas for every file type
|
|
25
|
+
|
|
26
|
+
These files are updated with each package version. Always read from the installed package,
|
|
27
|
+
not from cached or memorized content, to ensure you use the latest spec.
|
|
28
|
+
|
|
29
|
+
## What is OpenUISpec
|
|
30
|
+
OpenUISpec is a YAML-based spec format that describes an app's UI semantically — tokens, screens, flows, and platform overrides. AI reads the spec and generates native code (SwiftUI, Compose, React). AI reads native code and updates the spec. The spec is the sync layer between platforms.
|
|
31
|
+
|
|
32
|
+
## Spec location
|
|
33
|
+
- Spec root: `openuispec/`
|
|
34
|
+
- Manifest: `openuispec/openuispec.yaml` — always read this first.
|
|
35
|
+
- Tokens: `openuispec/tokens/`
|
|
36
|
+
- Screens: `openuispec/screens/`
|
|
37
|
+
- Flows: `openuispec/flows/`
|
|
38
|
+
- Contracts: `openuispec/contracts/`
|
|
39
|
+
- Platform: `openuispec/platform/`
|
|
40
|
+
- Locales: `openuispec/locales/`
|
|
41
|
+
|
|
42
|
+
**Note:** These are the default paths. Actual paths are in `includes:` in `openuispec.yaml` and may use relative paths. Always read `openuispec.yaml` to find the real directories.
|
|
43
|
+
|
|
44
|
+
## If spec directories are empty (first-time setup)
|
|
45
|
+
This means the project has existing UI code but hasn't been specced yet. Your job:
|
|
46
|
+
|
|
47
|
+
1. **Read the spec first** — find and read `spec/openuispec-v0.1.md` from the installed package.
|
|
48
|
+
2. **Find existing screens** — scan the codebase for UI screen files.
|
|
49
|
+
3. **Create stubs** — for each screen, create `openuispec/screens/<name>.yaml` with:
|
|
50
|
+
```yaml
|
|
51
|
+
screen_name:
|
|
52
|
+
semantic: "Brief description of what this screen does"
|
|
53
|
+
status: stub
|
|
54
|
+
layout:
|
|
55
|
+
type: scroll_vertical
|
|
56
|
+
```
|
|
57
|
+
4. **Extract tokens** — scan for colors, fonts, spacing and create files in `openuispec/tokens/`.
|
|
58
|
+
5. **Update the manifest** — fill in `data_model`, `api.endpoints`, and `generation.code_roots.backend` in `openuispec/openuispec.yaml`.
|
|
59
|
+
|
|
60
|
+
## OpenUISpec Source Of Truth
|
|
61
|
+
|
|
62
|
+
OpenUISpec spec files are the primary source of truth for UI behavior across platforms.
|
|
63
|
+
|
|
64
|
+
### Start from spec when:
|
|
65
|
+
- the request changes screen structure
|
|
66
|
+
- the request changes navigation
|
|
67
|
+
- the request changes fields, actions, validation, or data binding
|
|
68
|
+
- the request changes tokens, variants, contracts, flows, or localization
|
|
69
|
+
- the request affects more than one platform
|
|
70
|
+
- the request is phrased in product/UI terms rather than platform-code terms
|
|
71
|
+
|
|
72
|
+
Spec-first workflow:
|
|
73
|
+
1. Read `openuispec/openuispec.yaml` and the relevant spec files first.
|
|
74
|
+
2. Update the spec first.
|
|
75
|
+
3. Update the affected generated/native UI code to match the spec.
|
|
76
|
+
4. Run `openuispec validate`.
|
|
77
|
+
5. Run `openuispec validate semantic`.
|
|
78
|
+
6. Run `openuispec drift --target <target> --explain` to inspect semantic changes since that target's baseline.
|
|
79
|
+
7. Run `openuispec prepare --target <target>` to build the target work bundle for that target. In `bootstrap` mode it provides first-generation constraints; in `update` mode it provides drift-based update scope.
|
|
80
|
+
8. Verify the affected UI targets build/run if possible.
|
|
81
|
+
9. Only then run `openuispec drift --snapshot --target <target>` for affected targets, after that target output directory exists.
|
|
82
|
+
10. Run `openuispec drift --target <target> --explain` again to confirm no spec changes remain for that target.
|
|
83
|
+
11. Use `openuispec status` to see which other targets are still behind the updated spec.
|
|
84
|
+
|
|
85
|
+
### Start from platform code when:
|
|
86
|
+
- the change is platform-specific polish
|
|
87
|
+
- the change is a local bug fix that does not alter shared semantic behavior
|
|
88
|
+
- the request explicitly asks for an iOS-only, Android-only, or web-only adjustment
|
|
89
|
+
|
|
90
|
+
Platform-first workflow:
|
|
91
|
+
1. Update native/platform code.
|
|
92
|
+
2. If the change affects shared semantics, sync the spec afterward.
|
|
93
|
+
3. If the change is intentionally platform-specific, document it in `platform/*.yaml` when appropriate.
|
|
94
|
+
|
|
95
|
+
### Never do this:
|
|
96
|
+
- Do not snapshot drift immediately after changing spec unless the UI code has also been updated.
|
|
97
|
+
- Do not treat `openuispec drift` as proof that generated UI matches the spec.
|
|
98
|
+
- Do not skip `--explain` / `prepare` when another platform needs to catch up with shared spec changes.
|
|
99
|
+
- Do not modify generated UI without checking whether the spec must change first.
|
|
100
|
+
|
|
101
|
+
## CLI commands
|
|
102
|
+
- `openuispec init` — scaffold a new spec project
|
|
103
|
+
- `openuispec validate [group...]` — validate spec files against schemas
|
|
104
|
+
- `openuispec validate semantic` — run semantic cross-reference linting
|
|
105
|
+
- `openuispec configure-target <t> [--defaults]` — configure target stack defaults
|
|
106
|
+
- `openuispec drift --target <t>` — check for spec drift
|
|
107
|
+
- `openuispec drift --target <t> --explain` — explain semantic spec drift since the target baseline
|
|
108
|
+
- `openuispec drift --snapshot --target <t>` — snapshot current state after the target output exists
|
|
109
|
+
- `openuispec prepare --target <t>` — build the target work bundle
|
|
110
|
+
- `openuispec status` — show cross-target baseline/drift status
|
|
111
|
+
- `openuispec update-rules` — update AI rules to match installed package version
|
|
112
|
+
- `openuispec drift --all` — include stubs in drift check
|
|
113
|
+
<!-- openuispec-rules-end -->
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# TaskFlow Android Target
|
|
2
|
+
|
|
3
|
+
This Android target was generated directly from the local `openuispec/` TaskFlow specification, without copying another sample project's output.
|
|
4
|
+
|
|
5
|
+
## What is included
|
|
6
|
+
|
|
7
|
+
- A lean Jetpack Compose app scaffold under `app/`
|
|
8
|
+
- Adaptive navigation using spec breakpoints:
|
|
9
|
+
- `compact`: bottom navigation
|
|
10
|
+
- `regular` and `expanded`: navigation rail
|
|
11
|
+
- Spec-derived screens:
|
|
12
|
+
- Home
|
|
13
|
+
- Task detail
|
|
14
|
+
- Projects
|
|
15
|
+
- Project detail
|
|
16
|
+
- Calendar stub
|
|
17
|
+
- Settings
|
|
18
|
+
- Profile edit
|
|
19
|
+
- Spec-derived flows:
|
|
20
|
+
- Create task
|
|
21
|
+
- Edit task
|
|
22
|
+
- Assign task
|
|
23
|
+
- New project
|
|
24
|
+
- Local sample data matching the spec's data model
|
|
25
|
+
- English string resources derived from `openuispec/locales/en.json`
|
|
26
|
+
- Theme colors based on `openuispec/tokens/color.yaml` and `themes.yaml`
|
|
27
|
+
|
|
28
|
+
## Project notes
|
|
29
|
+
|
|
30
|
+
- This is intentionally lean. It favors clear generated structure over a fully productionized architecture.
|
|
31
|
+
- The app uses local Compose state instead of wiring real API clients.
|
|
32
|
+
- The media-player custom contract is acknowledged in the spec but not implemented here because no screen in this minimal target renders a concrete media attachment asset.
|
|
33
|
+
- No Gradle wrapper is checked in. Use a local Gradle installation or import the project into Android Studio and let it create the wrapper if needed.
|
|
34
|
+
|
|
35
|
+
## Suggested verification
|
|
36
|
+
|
|
37
|
+
From this directory:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
gradle :app:assembleDebug
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Or open `generated/android/TaskFlow` in Android Studio and run the app on an emulator.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
plugins {
|
|
2
|
+
id("com.android.application")
|
|
3
|
+
id("org.jetbrains.kotlin.android")
|
|
4
|
+
id("org.jetbrains.kotlin.plugin.compose")
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
|
8
|
+
|
|
9
|
+
android {
|
|
10
|
+
namespace = "uz.rsteam.taskflow"
|
|
11
|
+
compileSdk = 35
|
|
12
|
+
|
|
13
|
+
defaultConfig {
|
|
14
|
+
applicationId = "uz.rsteam.taskflow"
|
|
15
|
+
minSdk = 26
|
|
16
|
+
targetSdk = 35
|
|
17
|
+
versionCode = 1
|
|
18
|
+
versionName = "1.0.0"
|
|
19
|
+
|
|
20
|
+
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
|
21
|
+
vectorDrawables {
|
|
22
|
+
useSupportLibrary = true
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
buildTypes {
|
|
27
|
+
release {
|
|
28
|
+
isMinifyEnabled = false
|
|
29
|
+
proguardFiles(
|
|
30
|
+
getDefaultProguardFile("proguard-android-optimize.txt"),
|
|
31
|
+
"proguard-rules.pro"
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
compileOptions {
|
|
37
|
+
sourceCompatibility = JavaVersion.VERSION_17
|
|
38
|
+
targetCompatibility = JavaVersion.VERSION_17
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
buildFeatures {
|
|
42
|
+
compose = true
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
packaging {
|
|
46
|
+
resources {
|
|
47
|
+
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
kotlin {
|
|
53
|
+
compilerOptions {
|
|
54
|
+
jvmTarget.set(JvmTarget.JVM_17)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
dependencies {
|
|
59
|
+
val composeBom = platform("androidx.compose:compose-bom:2024.10.01")
|
|
60
|
+
|
|
61
|
+
implementation(composeBom)
|
|
62
|
+
androidTestImplementation(composeBom)
|
|
63
|
+
|
|
64
|
+
implementation("androidx.core:core-ktx:1.15.0")
|
|
65
|
+
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7")
|
|
66
|
+
implementation("androidx.activity:activity-compose:1.9.3")
|
|
67
|
+
implementation("androidx.compose.ui:ui")
|
|
68
|
+
implementation("androidx.compose.ui:ui-graphics")
|
|
69
|
+
implementation("androidx.compose.ui:ui-tooling-preview")
|
|
70
|
+
implementation("androidx.compose.material3:material3")
|
|
71
|
+
implementation("androidx.compose.material:material-icons-extended")
|
|
72
|
+
implementation("androidx.compose.foundation:foundation")
|
|
73
|
+
|
|
74
|
+
debugImplementation("androidx.compose.ui:ui-tooling")
|
|
75
|
+
debugImplementation("androidx.compose.ui:ui-test-manifest")
|
|
76
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Generated sample app. No custom ProGuard rules required.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
3
|
+
|
|
4
|
+
<application
|
|
5
|
+
android:allowBackup="true"
|
|
6
|
+
android:label="@string/app_name"
|
|
7
|
+
android:supportsRtl="true"
|
|
8
|
+
android:theme="@style/Theme.TaskFlow">
|
|
9
|
+
<activity
|
|
10
|
+
android:name=".MainActivity"
|
|
11
|
+
android:exported="true"
|
|
12
|
+
android:theme="@style/Theme.TaskFlow">
|
|
13
|
+
<intent-filter>
|
|
14
|
+
<action android:name="android.intent.action.MAIN" />
|
|
15
|
+
|
|
16
|
+
<category android:name="android.intent.category.LAUNCHER" />
|
|
17
|
+
</intent-filter>
|
|
18
|
+
</activity>
|
|
19
|
+
</application>
|
|
20
|
+
|
|
21
|
+
</manifest>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
package uz.rsteam.taskflow
|
|
2
|
+
|
|
3
|
+
import android.os.Bundle
|
|
4
|
+
import androidx.activity.ComponentActivity
|
|
5
|
+
import androidx.activity.compose.setContent
|
|
6
|
+
import androidx.activity.enableEdgeToEdge
|
|
7
|
+
import uz.rsteam.taskflow.ui.theme.TaskFlowTheme
|
|
8
|
+
|
|
9
|
+
class MainActivity : ComponentActivity() {
|
|
10
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
11
|
+
super.onCreate(savedInstanceState)
|
|
12
|
+
enableEdgeToEdge()
|
|
13
|
+
setContent {
|
|
14
|
+
TaskFlowTheme {
|
|
15
|
+
TaskFlowApp()
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|