@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.
- package/README.md +65 -224
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/UPSTREAM_LICENSE.txt +21 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/catalog.json +520 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/packaged/gitignore +27 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/README.md +25 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/components.json +22 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/eslint.config.js +23 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/index.html +13 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/package-lock.json +6597 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/package.json +60 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/public/power-apps.svg +55 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/App.tsx +17 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/assets/react.svg +1 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/mode-toggle.tsx +37 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/badge.tsx +46 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/button.tsx +60 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/calendar.tsx +211 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/card.tsx +92 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/chart.tsx +355 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/checkbox.tsx +32 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/command.tsx +184 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/dialog.tsx +141 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/dropdown-menu.tsx +257 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/input.tsx +21 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/label.tsx +22 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/popover.tsx +46 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/progress.tsx +29 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/select.tsx +185 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/separator.tsx +26 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/skeleton.tsx +13 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/table.tsx +114 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/tabs.tsx +66 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/textarea.tsx +18 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/components/ui/tooltip.tsx +61 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/hooks/use-theme.ts +11 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/index.css +131 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/lib/utils.ts +6 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/main.tsx +10 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/pages/_layout.tsx +31 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/pages/home.tsx +59 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/pages/not-found.tsx +14 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/providers/query-provider.tsx +26 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/providers/sonner-provider.tsx +23 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/providers/theme-provider.tsx +64 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/src/router.tsx +24 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/tsconfig.app.json +34 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/tsconfig.json +13 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/tsconfig.node.json +26 -0
- package/assets/power-apps-code-app/3438c352483e40982f6c5c0fc36fd71f8e7adbbb/starter/vite.config.ts +19 -0
- package/assets/power-apps-code-app/README.md +27 -0
- package/dist/args.d.ts +33 -0
- package/dist/args.js +100 -38
- package/dist/args.js.map +1 -1
- package/dist/catalogs.d.ts +3 -1
- package/dist/catalogs.js +23 -0
- package/dist/catalogs.js.map +1 -1
- package/dist/cli.js +6 -1
- package/dist/cli.js.map +1 -1
- package/dist/code-apps-plugin.d.ts +13 -0
- package/dist/code-apps-plugin.js +69 -0
- package/dist/code-apps-plugin.js.map +1 -0
- package/dist/commands.d.ts +4 -0
- package/dist/commands.js +669 -321
- package/dist/commands.js.map +1 -1
- package/dist/file-system.d.ts +16 -1
- package/dist/file-system.js +320 -10
- package/dist/file-system.js.map +1 -1
- package/dist/framework-adapters.d.ts +5 -2
- package/dist/framework-adapters.js +5 -2
- package/dist/framework-adapters.js.map +1 -1
- package/dist/genai-templates.d.ts +6 -6
- package/dist/genai-templates.js +0 -3
- package/dist/genai-templates.js.map +1 -1
- package/dist/interactive.d.ts +80 -6
- package/dist/interactive.js +338 -142
- package/dist/interactive.js.map +1 -1
- package/dist/migrate-plan.d.ts +4 -4
- package/dist/migrate-plan.js +1 -1
- package/dist/migrate-plan.js.map +1 -1
- package/dist/planner.d.ts +5 -0
- package/dist/planner.js +197 -53
- package/dist/planner.js.map +1 -1
- package/dist/power-apps-assets.d.ts +30 -0
- package/dist/power-apps-assets.js +131 -0
- package/dist/power-apps-assets.js.map +1 -0
- package/dist/power-apps-templates.d.ts +3 -0
- package/dist/power-apps-templates.js +140 -0
- package/dist/power-apps-templates.js.map +1 -0
- package/dist/power-apps-validation.d.ts +1 -0
- package/dist/power-apps-validation.js +79 -0
- package/dist/power-apps-validation.js.map +1 -0
- package/dist/process-runner.js +9 -6
- package/dist/process-runner.js.map +1 -1
- package/dist/project-dependencies.d.ts +7 -4
- package/dist/project-dependencies.js +16 -4
- package/dist/project-dependencies.js.map +1 -1
- package/dist/published-verifier.js +1 -1
- package/dist/published-verifier.js.map +1 -1
- package/dist/standard-templates.d.ts +4 -4
- package/dist/standard-templates.js.map +1 -1
- package/dist/templates.d.ts +2 -2
- package/dist/templates.js +196 -50
- package/dist/templates.js.map +1 -1
- package/dist/terminal.d.ts +99 -3
- package/dist/terminal.js +482 -66
- package/dist/terminal.js.map +1 -1
- package/dist/types.d.ts +73 -15
- package/dist/workstation.d.ts +10 -5
- package/dist/workstation.js +25 -10
- package/dist/workstation.js.map +1 -1
- package/docs/assets/liftoff-terminal.svg +33 -0
- package/docs/azure-deployment.md +66 -0
- package/docs/cli-reference.md +128 -0
- package/docs/configuration-and-manifests.md +102 -0
- package/docs/existing-repositories.md +87 -0
- package/docs/getting-started.md +114 -0
- package/docs/prerequisites.md +99 -0
- package/docs/project-structure.md +119 -0
- package/docs/safety-and-consent.md +98 -0
- package/docs/spec-workflows-and-agents.md +92 -0
- package/docs/troubleshooting.md +133 -0
- package/docs/workloads.md +128 -0
- 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.
|