@msn-control/liftoff 0.4.0 → 0.5.0

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 (123) hide show
  1. package/README.md +65 -224
  2. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/UPSTREAM_LICENSE.txt +21 -0
  3. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/catalog.json +520 -0
  4. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/packaged/gitignore +27 -0
  5. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/README.md +25 -0
  6. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/components.json +22 -0
  7. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/eslint.config.js +23 -0
  8. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/index.html +13 -0
  9. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/package-lock.json +6597 -0
  10. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/package.json +60 -0
  11. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/public/power-apps.svg +55 -0
  12. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/App.tsx +17 -0
  13. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/assets/react.svg +1 -0
  14. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/mode-toggle.tsx +37 -0
  15. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/badge.tsx +46 -0
  16. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/button.tsx +60 -0
  17. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/calendar.tsx +211 -0
  18. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/card.tsx +92 -0
  19. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/chart.tsx +355 -0
  20. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/checkbox.tsx +32 -0
  21. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/command.tsx +184 -0
  22. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/dialog.tsx +141 -0
  23. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/dropdown-menu.tsx +257 -0
  24. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/input.tsx +21 -0
  25. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/label.tsx +22 -0
  26. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/popover.tsx +46 -0
  27. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/progress.tsx +29 -0
  28. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/select.tsx +185 -0
  29. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/separator.tsx +26 -0
  30. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/skeleton.tsx +13 -0
  31. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/table.tsx +114 -0
  32. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/tabs.tsx +66 -0
  33. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/textarea.tsx +18 -0
  34. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/tooltip.tsx +61 -0
  35. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/hooks/use-theme.ts +11 -0
  36. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/index.css +131 -0
  37. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/lib/utils.ts +6 -0
  38. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/main.tsx +10 -0
  39. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/pages/_layout.tsx +31 -0
  40. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/pages/home.tsx +59 -0
  41. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/pages/not-found.tsx +14 -0
  42. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/providers/query-provider.tsx +26 -0
  43. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/providers/sonner-provider.tsx +23 -0
  44. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/providers/theme-provider.tsx +64 -0
  45. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/router.tsx +24 -0
  46. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/tsconfig.app.json +34 -0
  47. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/tsconfig.json +13 -0
  48. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/tsconfig.node.json +26 -0
  49. package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/vite.config.ts +19 -0
  50. package/assets/power-apps-code-app/README.md +27 -0
  51. package/dist/args.d.ts +33 -0
  52. package/dist/args.js +100 -38
  53. package/dist/args.js.map +1 -1
  54. package/dist/catalogs.d.ts +3 -1
  55. package/dist/catalogs.js +23 -0
  56. package/dist/catalogs.js.map +1 -1
  57. package/dist/cli.js +6 -1
  58. package/dist/cli.js.map +1 -1
  59. package/dist/code-apps-plugin.d.ts +13 -0
  60. package/dist/code-apps-plugin.js +69 -0
  61. package/dist/code-apps-plugin.js.map +1 -0
  62. package/dist/commands.d.ts +4 -0
  63. package/dist/commands.js +669 -321
  64. package/dist/commands.js.map +1 -1
  65. package/dist/file-system.d.ts +16 -1
  66. package/dist/file-system.js +320 -10
  67. package/dist/file-system.js.map +1 -1
  68. package/dist/framework-adapters.d.ts +5 -2
  69. package/dist/framework-adapters.js +5 -2
  70. package/dist/framework-adapters.js.map +1 -1
  71. package/dist/genai-templates.d.ts +6 -6
  72. package/dist/genai-templates.js +0 -3
  73. package/dist/genai-templates.js.map +1 -1
  74. package/dist/interactive.d.ts +80 -6
  75. package/dist/interactive.js +338 -142
  76. package/dist/interactive.js.map +1 -1
  77. package/dist/migrate-plan.d.ts +4 -4
  78. package/dist/migrate-plan.js +1 -1
  79. package/dist/migrate-plan.js.map +1 -1
  80. package/dist/planner.d.ts +5 -0
  81. package/dist/planner.js +197 -53
  82. package/dist/planner.js.map +1 -1
  83. package/dist/power-apps-assets.d.ts +30 -0
  84. package/dist/power-apps-assets.js +131 -0
  85. package/dist/power-apps-assets.js.map +1 -0
  86. package/dist/power-apps-templates.d.ts +3 -0
  87. package/dist/power-apps-templates.js +140 -0
  88. package/dist/power-apps-templates.js.map +1 -0
  89. package/dist/power-apps-validation.d.ts +1 -0
  90. package/dist/power-apps-validation.js +79 -0
  91. package/dist/power-apps-validation.js.map +1 -0
  92. package/dist/process-runner.js +9 -6
  93. package/dist/process-runner.js.map +1 -1
  94. package/dist/project-dependencies.d.ts +7 -4
  95. package/dist/project-dependencies.js +16 -4
  96. package/dist/project-dependencies.js.map +1 -1
  97. package/dist/published-verifier.js +1 -1
  98. package/dist/published-verifier.js.map +1 -1
  99. package/dist/standard-templates.d.ts +4 -4
  100. package/dist/standard-templates.js.map +1 -1
  101. package/dist/templates.d.ts +2 -2
  102. package/dist/templates.js +196 -50
  103. package/dist/templates.js.map +1 -1
  104. package/dist/terminal.d.ts +99 -3
  105. package/dist/terminal.js +482 -66
  106. package/dist/terminal.js.map +1 -1
  107. package/dist/types.d.ts +73 -15
  108. package/dist/workstation.d.ts +10 -5
  109. package/dist/workstation.js +25 -10
  110. package/dist/workstation.js.map +1 -1
  111. package/docs/assets/liftoff-terminal.svg +33 -0
  112. package/docs/azure-deployment.md +66 -0
  113. package/docs/cli-reference.md +128 -0
  114. package/docs/configuration-and-manifests.md +102 -0
  115. package/docs/existing-repositories.md +87 -0
  116. package/docs/getting-started.md +114 -0
  117. package/docs/prerequisites.md +99 -0
  118. package/docs/project-structure.md +119 -0
  119. package/docs/safety-and-consent.md +98 -0
  120. package/docs/spec-workflows-and-agents.md +92 -0
  121. package/docs/troubleshooting.md +133 -0
  122. package/docs/workloads.md +128 -0
  123. package/package.json +8 -2
@@ -0,0 +1,102 @@
1
+ # Configuration and manifests
2
+
3
+ Generated projects have two Liftoff root files with different ownership.
4
+
5
+ ## `liftoff.config.json`: developer-owned desired state
6
+
7
+ Liftoff writes configuration once during initialization and does not
8
+ machine-rewrite it afterward.
9
+
10
+ Supported edits are reconciled by `liftoff update`:
11
+
12
+ - API workloads can add or remove environments and enable applicable generated
13
+ areas such as the frontend.
14
+ - Power Apps can change the optional Code Apps plugin preference.
15
+
16
+ Workload kind, API stack, GenAI pattern, spec workflow, selected agents, and a
17
+ user-supplied Power Apps starter source change are not ordinary updates.
18
+
19
+ A Power Apps configuration contains only applicable fields:
20
+
21
+ ```json
22
+ {
23
+ "projectName": "sales-hub",
24
+ "projectType": "power-apps-code-app",
25
+ "specWorkflow": "openspec",
26
+ "agents": ["github-copilot"],
27
+ "codeAppsPlugin": false
28
+ }
29
+ ```
30
+
31
+ API, cloud, region, frontend, and environment fields are rejected for this
32
+ workload rather than silently ignored.
33
+
34
+ ## `liftoff.manifest.json`: CLI-owned compatibility record
35
+
36
+ New projects use manifest schema v4. Its common project identity includes the
37
+ name, spec workflow, selected agents, and applicable Spec Kit default. A
38
+ discriminated `project.workload` object contains only fields valid for one
39
+ workload:
40
+
41
+ - `genai`: API stack, pattern, cloud, region, frontend, and environments.
42
+ - `standard`: API stack, cloud, region, frontend, and environments.
43
+ - `power-apps-code-app`: immutable starter repository, template path, commit,
44
+ and Code Apps plugin preference.
45
+
46
+ The manifest also records:
47
+
48
+ - Generating Liftoff version.
49
+ - Official framework adapter, state, and tested contract version when known.
50
+ - Durable artifact logical names.
51
+ - OS-neutral path-part arrays.
52
+ - `sha256:` content hashes.
53
+
54
+ Power Apps source identity uses explicit repository, path, and 40-character
55
+ commit fields. It is not inferred from mutable URLs or generated file paths.
56
+
57
+ Treat the manifest as CLI-owned. Restore it from version control or regenerate
58
+ with the matching Liftoff version when validation reports malformed identity,
59
+ paths, or hashes.
60
+
61
+ ## Compatibility
62
+
63
+ Readers support schemas v2, v3, and v4:
64
+
65
+ - V2 normalizes the legacy flat API identity and records framework state as
66
+ uncertain without inventing agents.
67
+ - V3 normalizes flat GenAI or API identity plus framework and agent metadata.
68
+ - V4 represents the discriminated workload model, including Power Apps.
69
+
70
+ A read-only `liftoff update` leaves an old manifest byte-for-byte unchanged. A
71
+ successful apply writes v4 only after the file transaction succeeds. Skipped
72
+ conflicts retain their recorded hashes.
73
+
74
+ ## Artifact ownership
75
+
76
+ Durable Liftoff artifacts carry logical names and hashes. That lets validate,
77
+ doctor, and update distinguish:
78
+
79
+ - Current template bytes.
80
+ - An untouched file with a template upgrade.
81
+ - A developer edit that conflicts with a template change.
82
+ - A named artifact moved by the template.
83
+ - Missing, new, and orphaned artifacts.
84
+
85
+ Framework-owned OpenSpec and Spec Kit files are validated separately and are
86
+ not claimed in durable hashes. One-time seed files are also excluded so they
87
+ can follow their own lifecycle.
88
+
89
+ ## Contract conventions
90
+
91
+ - Writers use `artifactVersion` 4; readers support v2, v3, and v4.
92
+ - Artifact logical names and catalog identifiers are append-only.
93
+ - Rendering is deterministic and does not depend on timestamps, host versions,
94
+ or network state.
95
+ - `.liftoff/` is reserved for future CLI-managed state.
96
+ - Machine-readable paths are path-part arrays, never platform-joined strings.
97
+ - Exit codes are 0 for success or clean, 1 for failure, and 2 for detected
98
+ drift in check mode.
99
+ - JSON outputs carry a numeric top-level `schemaVersion`.
100
+
101
+ See [safety and consent](safety-and-consent.md) for reconciliation and rollback
102
+ behavior.
@@ -0,0 +1,87 @@
1
+ # Existing repositories
2
+
3
+ Liftoff chooses its target from the current directory and Git worktree
4
+ discovery before it stages any output.
5
+
6
+ ## Exact Git root: initialize in place
7
+
8
+ When the current directory is exactly the root reported by
9
+ `git rev-parse --show-toplevel`, `liftoff init` uses that directory as the
10
+ target:
11
+
12
+ ```bash
13
+ cd existing-repository
14
+ liftoff init
15
+ ```
16
+
17
+ With no project name, Liftoff derives project identity from the repository
18
+ directory. Supplying a name changes the generated project identity but still
19
+ does not create a child folder:
20
+
21
+ ```bash
22
+ liftoff init customer-portal
23
+ ```
24
+
25
+ ## Other locations: create a named child
26
+
27
+ In a non-Git directory, or in a directory below but not equal to a Git root, a
28
+ project name produces a child:
29
+
30
+ ```text
31
+ workspace/
32
+ `-- customer-portal/
33
+ |-- liftoff.config.json
34
+ `-- liftoff.manifest.json
35
+ ```
36
+
37
+ This distinction prevents an invocation deep inside an existing repository
38
+ from unexpectedly treating that subdirectory as the repository root.
39
+
40
+ ## Non-empty targets
41
+
42
+ Liftoff never blindly replaces a target tree. It:
43
+
44
+ 1. Renders Liftoff-owned files in temporary staging.
45
+ 2. Runs the official OpenSpec or Spec Kit initializer in staging.
46
+ 3. Rejects unexpected roots, nested Git metadata, and unsafe paths.
47
+ 4. Compares every destination before writing.
48
+ 5. Lists different regular files as one replacement set.
49
+ 6. Requires explicit overwrite permission before replacing that set.
50
+ 7. Applies the authorized merge transactionally and rolls back handled
51
+ failures.
52
+
53
+ Unrelated existing files are preserved. Structural collisions, symlinks,
54
+ unsafe ancestors, and an existing `liftoff.manifest.json` are blockers that
55
+ `--force` cannot bypass.
56
+
57
+ See [safety and consent](safety-and-consent.md) for the complete permission
58
+ model.
59
+
60
+ ## Existing Liftoff project
61
+
62
+ If the target already contains `liftoff.manifest.json`, do not run init again.
63
+ Use:
64
+
65
+ ```bash
66
+ liftoff validate
67
+ liftoff update
68
+ liftoff update --apply
69
+ ```
70
+
71
+ Update is a read-only drift check unless `--apply` is present.
72
+
73
+ ## Existing non-Liftoff application
74
+
75
+ Use migration when you want a fresh governed scaffold and a filtered source
76
+ copy:
77
+
78
+ ```bash
79
+ liftoff migrate ../legacy-app --region eastus --agents copilot,claude --yes
80
+ ```
81
+
82
+ Migration requires a new or empty sibling target, runs the same readiness and
83
+ framework pipeline, and leaves the source byte-for-byte unchanged. `--force`
84
+ does not permit a non-empty migration target.
85
+
86
+ Arbitrary existing Power Apps application migration is not currently
87
+ supported.
@@ -0,0 +1,114 @@
1
+ # Getting started
2
+
3
+ Liftoff is an interactive project initializer for governed GenAI applications,
4
+ standard APIs, and Power Apps code apps.
5
+
6
+ ## 1. Install the CLI
7
+
8
+ Liftoff requires Node.js 20.19 or newer. Power Apps code app projects require
9
+ Node.js 22.12 or newer for their generated framework.
10
+
11
+ The canonical release registry is `https://registry.npmjs.org`:
12
+
13
+ ```bash
14
+ npm view @msn-control/liftoff@latest version --registry=https://registry.npmjs.org
15
+ npm install -g @msn-control/liftoff@latest --registry=https://registry.npmjs.org
16
+ liftoff --version
17
+ ```
18
+
19
+ Versions before 0.3.0 are unsupported and must not be used for new projects.
20
+ If your organization requires a managed npm registry, query
21
+ `@msn-control/liftoff@latest` through that registry and compare the version with
22
+ canonical npm. Stop if the mirror is older or rejects the explicit current
23
+ version; ask the mirror owner to synchronize or approve the release. Liftoff
24
+ does not modify `.npmrc` or bypass registry policy.
25
+
26
+ See [prerequisites](prerequisites.md) for the complete plan-derived tool model.
27
+
28
+ ## 2. Start interactive initialization
29
+
30
+ From the directory that should contain the project, run:
31
+
32
+ ```bash
33
+ liftoff init
34
+ ```
35
+
36
+ The guided flow asks for:
37
+
38
+ 1. Project identity and workload: GenAI, API, or Power Apps code app.
39
+ 2. Only the architecture choices applicable to that workload.
40
+ 3. OpenSpec or Spec Kit.
41
+ 4. One or both coding agents. On a real TTY, Space toggles agents and Enter
42
+ confirms the selection.
43
+ 5. A Spec Kit default agent when both agents are selected.
44
+ 6. The optional Preview Code Apps plugin preference for Power Apps projects.
45
+ 7. Plan confirmation, workstation readiness, and any separate install or
46
+ overwrite permissions that are needed.
47
+
48
+ Liftoff renders into temporary staging, runs the official framework initializer
49
+ there, validates the complete result, and only then merges it into the target.
50
+
51
+ ## 3. Understand the target
52
+
53
+ At the exact root of an existing Git worktree, `liftoff init` initializes that
54
+ root in place. A supplied project name changes project identity; it does not
55
+ create a child folder.
56
+
57
+ In a non-Git directory, or from a directory below but not equal to a Git root,
58
+ a project name creates a named child directory.
59
+
60
+ Read [existing repositories](existing-repositories.md) before initializing a
61
+ non-empty target.
62
+
63
+ ## 4. Validate the result
64
+
65
+ Run maintenance commands from the generated project root:
66
+
67
+ ```bash
68
+ liftoff validate
69
+ liftoff doctor
70
+ ```
71
+
72
+ `validate` checks durable generated artifacts and framework markers. `doctor`
73
+ adds read-only workstation, runtime, authentication, dependency, and
74
+ workload-specific diagnostics.
75
+
76
+ Next steps depend on the selected workload:
77
+
78
+ - GenAI and API projects: copy `.env.example` to `.env`, install the generated
79
+ stack dependencies, then use `liftoff dev` and `liftoff infra` to print local
80
+ development and infrastructure commands.
81
+ - Power Apps projects: run `npm ci`, then `npm run dev`. Environment binding,
82
+ connector addition, and `power-apps push` are deliberately deferred.
83
+
84
+ See [workloads](workloads.md) for exact generated outputs and deferred actions.
85
+
86
+ ## Noninteractive automation
87
+
88
+ Use `liftoff plan` to resolve choices and preview requirements without writing
89
+ files or running installers:
90
+
91
+ ```bash
92
+ liftoff plan --type power-apps-code-app --spec openspec --agents copilot
93
+ ```
94
+
95
+ Automation can pass the same options to `liftoff init`. Use `--yes` for project
96
+ defaults and confirmation only. It does not authorize file replacement,
97
+ machine-level tools, or project dependency installation. Those permissions
98
+ remain independent.
99
+
100
+ See the [CLI reference](cli-reference.md) and
101
+ [safety and consent](safety-and-consent.md) before automating initialization.
102
+
103
+ ## Existing application migration
104
+
105
+ `liftoff migrate <source>` scans a non-Liftoff application, creates a fresh
106
+ sibling scaffold, and stages a filtered source copy for guided migration. The
107
+ source remains byte-for-byte unchanged.
108
+
109
+ ```bash
110
+ liftoff migrate ../legacy-app --region eastus --agents copilot,claude --yes
111
+ ```
112
+
113
+ Power Apps migration from an arbitrary existing application is not part of the
114
+ current workload contract.
@@ -0,0 +1,99 @@
1
+ # Prerequisites
2
+
3
+ Liftoff derives workstation and project requirements from the complete resolved
4
+ plan. A Power Apps project is not asked to install API or infrastructure tools,
5
+ and a Go API is not asked to install Python.
6
+
7
+ ## Baseline
8
+
9
+ - Liftoff CLI: Node.js 20.19 or newer.
10
+ - Power Apps code app: Node.js 22.12 or newer.
11
+ - Selected framework: the Liftoff-tested OpenSpec or Spec Kit contract.
12
+ - Selected agents: GitHub Copilot, Claude Code, or both.
13
+
14
+ API workloads additionally require their selected Python, Node.js, or Go
15
+ runtime. GenAI uses Python 3.12 and the Python/FastAPI/PydanticAI stack.
16
+
17
+ ## Blocking and advisory checks
18
+
19
+ Blocking checks must be ready before initialization can safely complete:
20
+
21
+ - Required runtime and minimum version.
22
+ - Selected spec framework CLI.
23
+ - Every selected coding agent.
24
+
25
+ Advisory checks describe useful but deferrable capabilities:
26
+
27
+ - Docker CLI and daemon health for API workloads.
28
+ - OpenTofu for generated Azure infrastructure.
29
+ - Azure CLI and observable authentication health.
30
+ - Optional Code Apps plugin state for Power Apps.
31
+
32
+ Authentication checks are read-only. Liftoff never stores credentials or signs
33
+ in to a cloud or agent on your behalf.
34
+
35
+ ## Preview requirements without writes
36
+
37
+ `liftoff plan` shows both generated artifacts and workstation requirements
38
+ without writing files or running installers:
39
+
40
+ ```bash
41
+ liftoff plan --type power-apps-code-app --spec openspec --agents copilot,claude
42
+ ```
43
+
44
+ ## Tool installation consent
45
+
46
+ Liftoff prints allowlisted commands before running them. Machine-level
47
+ installation requires `--install-tools` or separate interactive approval.
48
+
49
+ - macOS recipes use Homebrew, npm, or `uv`.
50
+ - Windows recipes use WinGet, npm, or `uv`.
51
+ - Linux system packages are never installed with automatic elevation. Liftoff
52
+ prints distribution-appropriate official guidance; npm and `uv` framework
53
+ recipes remain separately consented.
54
+
55
+ An install that changes `PATH` is re-probed when possible and may require a new
56
+ terminal. Do not treat installer success as readiness until the corresponding
57
+ probe passes.
58
+
59
+ ## Project dependency consent
60
+
61
+ Project-local dependency setup is separate from workstation tools and requires
62
+ `--install-dependencies` or interactive approval after a successful project
63
+ merge.
64
+
65
+ For Power Apps, Liftoff runs only the root locked install:
66
+
67
+ ```bash
68
+ npm ci
69
+ ```
70
+
71
+ The generated `package.json` and `package-lock.json` are validated before
72
+ installation and protected from installer mutation. If dependency setup is
73
+ skipped or fails, Liftoff prints the exact resume command rather than claiming
74
+ the project is ready.
75
+
76
+ GenAI and API projects use their generated stack-native locked dependency
77
+ commands.
78
+
79
+ ## Power Apps local CLI
80
+
81
+ The Power Apps CLI is supplied by the generated project dependency graph.
82
+ Liftoff checks it without downloading another package:
83
+
84
+ ```bash
85
+ npx --no-install power-apps --version
86
+ ```
87
+
88
+ If `node_modules` is absent, run `npm ci` first. Environment binding and cloud
89
+ authentication remain separate later actions.
90
+
91
+ ## Agent detection
92
+
93
+ Copilot can be detected through its CLI or supported VS Code extensions.
94
+ Claude Code is checked with its version and doctor commands. When both are
95
+ selected, both must be ready.
96
+
97
+ The optional Code Apps plugin uses independent, read-only probes for each
98
+ selected agent. A missing executable, timeout, or unsupported plugin-list
99
+ result is reported as not observable rather than silently treated as missing.
@@ -0,0 +1,119 @@
1
+ # Generated project structure
2
+
3
+ Generated paths are logical examples. Liftoff uses platform-correct filesystem
4
+ handling on Windows, macOS, and Linux, and manifests store path-part arrays
5
+ instead of joined strings.
6
+
7
+ ## GenAI and API projects
8
+
9
+ ```text
10
+ project/
11
+ |-- README.md
12
+ |-- liftoff.config.json
13
+ |-- liftoff.manifest.json
14
+ |-- .env.example
15
+ |-- Dockerfile
16
+ |-- docker-compose.yml
17
+ |-- backend/
18
+ |-- database/
19
+ | |-- alembic.ini or stack-native migration config
20
+ | |-- migrations/
21
+ | `-- models/ or schema/
22
+ |-- environments/
23
+ | |-- dev/
24
+ | |-- test/
25
+ | `-- prod/
26
+ |-- infrastructure/
27
+ | `-- opentofu/
28
+ | `-- azure/
29
+ |-- openspec/ or .specify/
30
+ |-- frontend/ # only when selected
31
+ |-- functions/<worker-name>/ # only for worker-enabled GenAI patterns
32
+ `-- migration/legacy/ # only after liftoff migrate
33
+ ```
34
+
35
+ ### Core areas
36
+
37
+ - `backend` contains the selected API stack and Scalar/OpenAPI wiring. Python
38
+ uses `backend/apis`, Node.js uses `backend/src`, and Go uses
39
+ `backend/cmd/api` plus `backend/internal`.
40
+ - `backend/orchestration` appears only in GenAI projects and contains
41
+ PydanticAI agents, prompts, model configuration, and integration boundaries.
42
+ - `database` contains SQLAlchemy/Alembic for Python, Drizzle for Node.js, or
43
+ pgx/Goose for Go.
44
+ - `environments/<env>` contains environment-specific backend settings and
45
+ Functions settings when a worker is generated.
46
+ - `docker-compose.yml` starts the selected backend, PostgreSQL, Redis,
47
+ Azurite, and Mailpit. GenAI projects use pgvector where needed and include an
48
+ optional Langfuse profile.
49
+ - `infrastructure/opentofu/azure` contains modules, environment tfvars, local
50
+ state configuration, and a remote-state example.
51
+ - `openspec` is created for OpenSpec. `.specify` and `specs` are created for
52
+ Spec Kit.
53
+
54
+ ### Conditional areas
55
+
56
+ - `frontend` is generated only when selected. It uses Vue 3 and Tailwind with
57
+ a generic API starter or a GenAI experience matched to the pattern.
58
+ - `functions/<worker-name>` appears for worker-enabled RAG, agent, multi-agent,
59
+ and workflow patterns.
60
+ - `backend/workers` contains backend-adjacent or containerized worker code,
61
+ separate from Azure Functions runtime files.
62
+ - `migration/legacy` contains the filtered source copy created by migration.
63
+
64
+ ## Power Apps code app
65
+
66
+ ```text
67
+ project/
68
+ |-- README.md
69
+ |-- THIRD_PARTY_NOTICES.md
70
+ |-- liftoff.config.json
71
+ |-- liftoff.manifest.json
72
+ |-- package.json
73
+ |-- package-lock.json
74
+ |-- index.html
75
+ |-- vite.config.ts
76
+ |-- eslint.config.js
77
+ |-- tsconfig.json
78
+ |-- public/
79
+ |-- src/
80
+ | |-- App.tsx
81
+ | |-- main.tsx
82
+ | |-- router.tsx
83
+ | |-- components/
84
+ | |-- hooks/
85
+ | |-- pages/
86
+ | `-- providers/
87
+ `-- openspec/ or .specify/
88
+ ```
89
+
90
+ This root follows the pinned official Microsoft starter. It includes the
91
+ Power Apps SDK, Vite plugin, and project-local CLI through locked npm
92
+ dependencies.
93
+
94
+ Liftoff intentionally does not generate `backend/`, `database/`,
95
+ `docker-compose.yml`, `environments/`, `infrastructure/`, or
96
+ `power.config.json` for this workload.
97
+
98
+ ## GenAI integration configuration
99
+
100
+ Generated GenAI projects expose real configuration boundaries instead of
101
+ success-shaped placeholders:
102
+
103
+ - `PYDANTIC_AI_MODEL` selects the production model. An unconfigured production
104
+ invocation fails clearly.
105
+ - Redis Streams uses `REDIS_URL` and `REDIS_STREAM_NAME`.
106
+ - Azure Service Bus uses `SERVICE_BUS_QUEUE_NAME` and either
107
+ `SERVICE_BUS_CONNECTION_STRING` or
108
+ `SERVICE_BUS_FULLY_QUALIFIED_NAMESPACE`; `AZURE_CLIENT_ID` selects a
109
+ user-assigned managed identity.
110
+ - Langfuse requires both `LANGFUSE_PUBLIC_KEY` and
111
+ `LANGFUSE_SECRET_KEY`, with optional `LANGFUSE_HOST`. Without both keys,
112
+ tracing is explicitly disabled.
113
+ - Frontends read `VITE_API_BASE_URL`, call the route selected by the pattern or
114
+ API stack, and expose loading, response, and failure states.
115
+ - Backends allow the local frontend origin by default.
116
+ `CORS_ALLOWED_ORIGINS` configures additional origins.
117
+
118
+ Generated backend, messaging, tracing, orchestration, and frontend tests do not
119
+ require a live model, Redis, Service Bus, or Langfuse service.
@@ -0,0 +1,98 @@
1
+ # Safety and consent
2
+
3
+ Liftoff separates project decisions, file replacement, workstation tools, and
4
+ project dependencies. No one permission implies another.
5
+
6
+ ## Consent flags
7
+
8
+ | Flag | Authorizes | Does not authorize |
9
+ | --- | --- | --- |
10
+ | `--yes` | Project defaults and plan confirmation | File replacement, machine installs, or project dependencies |
11
+ | `--force` | Only listed and validated regular-file replacements | Manifest guards, symlinks, structural collisions, tools, dependencies, or non-empty migration targets |
12
+ | `--install-tools` | Allowlisted workstation installation commands | Project decisions, overwrites, or project dependencies |
13
+ | `--install-dependencies` | Locked project-local dependency commands after a successful merge | Machine tools, project decisions, or overwrites |
14
+
15
+ Interactive sessions ask separately at the point each permission is needed.
16
+
17
+ ## Staged initialization
18
+
19
+ Initialization does not write generated files directly into the destination.
20
+ Liftoff:
21
+
22
+ 1. Resolves and validates a project plan.
23
+ 2. Renders Liftoff-owned artifacts into a temporary staging directory.
24
+ 3. Runs the official OpenSpec or Spec Kit initializer in staging.
25
+ 4. Rejects nested Git metadata, unexpected framework roots, symlinks, and
26
+ malformed output.
27
+ 5. Validates the full staged project.
28
+ 6. Computes one immutable destination preflight.
29
+ 7. Shows every different regular file that would be replaced.
30
+ 8. Applies only an authorized preflight.
31
+
32
+ Unrelated destination files are preserved.
33
+
34
+ ## Overwrite boundaries
35
+
36
+ A different regular file can be replaced only after explicit permission.
37
+ Structural collisions are not overridable:
38
+
39
+ - A generated file collides with a directory or another non-file entry.
40
+ - An ancestor is not a directory.
41
+ - A path is a symlink or escapes the project root through one.
42
+ - The destination already contains `liftoff.manifest.json`.
43
+ - A migration target is non-empty.
44
+
45
+ `--force` cannot weaken these guards.
46
+
47
+ ## Atomic writes and rollback
48
+
49
+ Individual project files use temporary-file replacement. Initialization keeps
50
+ backups for replaced files and records created files and directories. A handled
51
+ merge failure restores or removes those entries in reverse order.
52
+
53
+ `liftoff update --apply` preflights all affected paths and applies generated
54
+ file, move, delete, and manifest mutations as one rollback-capable
55
+ transaction. Schema upgrades are committed only after the other mutations
56
+ succeed. A corrected retry converges from the restored state.
57
+
58
+ If automatic rollback itself cannot safely restore a path because another
59
+ process changed it, Liftoff reports the incomplete rollback rather than
60
+ overwriting unknown bytes.
61
+
62
+ ## Update ownership
63
+
64
+ `liftoff update` is read-only by default:
65
+
66
+ - Clean generated files remain unchanged.
67
+ - New, missing, untouched-upgrade, and clean-move states can be applied.
68
+ - Developer edits that also differ from the current template are conflicts.
69
+ - Conflicts are skipped unless `--apply --force` is explicitly supplied.
70
+ - Orphans are reported and left on disk for manual review.
71
+
72
+ Power Apps reconciliation reads only the packaged immutable starter. It does
73
+ not fetch the upstream repository. Workload kind and user-edited starter
74
+ repository, template path, or commit changes are rejected before artifact
75
+ access.
76
+
77
+ ## Framework and seed ownership
78
+
79
+ OpenSpec and Spec Kit core/integration output is owned by their official
80
+ initializers. Liftoff validates the selected contract and agent markers but
81
+ does not claim framework-owned files in durable artifact hashes.
82
+
83
+ One-time seed content is also omitted from durable hashes so it can follow its
84
+ own lifecycle after generation.
85
+
86
+ ## Credentials and external actions
87
+
88
+ Generated files contain configuration boundaries, not real credentials.
89
+ Liftoff does not:
90
+
91
+ - Modify `.npmrc` to bypass a managed registry.
92
+ - Store cloud or agent credentials.
93
+ - Perform cloud sign-in.
94
+ - Apply OpenTofu.
95
+ - Bind or push a Power Apps code app.
96
+ - Run Microsoft's broad Code Apps marketplace installer.
97
+
98
+ Those actions require their own review, authentication, and consent.