@msn-control/liftoff 0.4.1 → 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 (108) hide show
  1. package/README.md +65 -256
  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.js +7 -1
  52. package/dist/args.js.map +1 -1
  53. package/dist/catalogs.d.ts +3 -1
  54. package/dist/catalogs.js +23 -0
  55. package/dist/catalogs.js.map +1 -1
  56. package/dist/code-apps-plugin.d.ts +13 -0
  57. package/dist/code-apps-plugin.js +69 -0
  58. package/dist/code-apps-plugin.js.map +1 -0
  59. package/dist/commands.js +282 -55
  60. package/dist/commands.js.map +1 -1
  61. package/dist/file-system.d.ts +16 -1
  62. package/dist/file-system.js +320 -10
  63. package/dist/file-system.js.map +1 -1
  64. package/dist/genai-templates.d.ts +6 -6
  65. package/dist/genai-templates.js +0 -3
  66. package/dist/genai-templates.js.map +1 -1
  67. package/dist/interactive.d.ts +40 -3
  68. package/dist/interactive.js +180 -24
  69. package/dist/interactive.js.map +1 -1
  70. package/dist/migrate-plan.d.ts +4 -4
  71. package/dist/migrate-plan.js +1 -1
  72. package/dist/migrate-plan.js.map +1 -1
  73. package/dist/planner.js +177 -40
  74. package/dist/planner.js.map +1 -1
  75. package/dist/power-apps-assets.d.ts +30 -0
  76. package/dist/power-apps-assets.js +131 -0
  77. package/dist/power-apps-assets.js.map +1 -0
  78. package/dist/power-apps-templates.d.ts +3 -0
  79. package/dist/power-apps-templates.js +140 -0
  80. package/dist/power-apps-templates.js.map +1 -0
  81. package/dist/power-apps-validation.d.ts +1 -0
  82. package/dist/power-apps-validation.js +79 -0
  83. package/dist/power-apps-validation.js.map +1 -0
  84. package/dist/project-dependencies.d.ts +1 -0
  85. package/dist/project-dependencies.js +12 -1
  86. package/dist/project-dependencies.js.map +1 -1
  87. package/dist/standard-templates.d.ts +4 -4
  88. package/dist/standard-templates.js.map +1 -1
  89. package/dist/templates.d.ts +2 -2
  90. package/dist/templates.js +196 -50
  91. package/dist/templates.js.map +1 -1
  92. package/dist/types.d.ts +73 -15
  93. package/dist/workstation.d.ts +10 -5
  94. package/dist/workstation.js +25 -10
  95. package/dist/workstation.js.map +1 -1
  96. package/docs/assets/liftoff-terminal.svg +33 -0
  97. package/docs/azure-deployment.md +66 -0
  98. package/docs/cli-reference.md +128 -0
  99. package/docs/configuration-and-manifests.md +102 -0
  100. package/docs/existing-repositories.md +87 -0
  101. package/docs/getting-started.md +114 -0
  102. package/docs/prerequisites.md +99 -0
  103. package/docs/project-structure.md +119 -0
  104. package/docs/safety-and-consent.md +98 -0
  105. package/docs/spec-workflows-and-agents.md +92 -0
  106. package/docs/troubleshooting.md +133 -0
  107. package/docs/workloads.md +128 -0
  108. package/package.json +8 -2
@@ -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.
@@ -0,0 +1,92 @@
1
+ # Spec workflows and agents
2
+
3
+ Spec-driven governance and coding-agent integration are common to every
4
+ Liftoff workload.
5
+
6
+ ## Choose a spec workflow
7
+
8
+ ### OpenSpec
9
+
10
+ OpenSpec organizes proposed behavior changes as reviewable artifacts before
11
+ implementation. Liftoff runs the pinned official OpenSpec initializer in
12
+ temporary staging and passes every selected coding agent in stable order.
13
+
14
+ Generated projects contain `openspec/` plus the selected agent integration
15
+ markers.
16
+
17
+ ### Spec Kit
18
+
19
+ Spec Kit provides a specification, planning, and implementation workflow.
20
+ Liftoff initializes the selected default coding agent first, adds every
21
+ secondary integration, and records the default separately from the full agent
22
+ set.
23
+
24
+ Generated projects contain `.specify/`, `specs/`, and the selected agent
25
+ integration markers.
26
+
27
+ Liftoff does not hand-write framework-owned core or integration output. It
28
+ executes the tested official initializer, confines its writes to allowed roots,
29
+ and validates the declared markers before merging.
30
+
31
+ ## Select coding agents
32
+
33
+ Liftoff supports:
34
+
35
+ - GitHub Copilot.
36
+ - Claude Code.
37
+ - Both agents together.
38
+
39
+ On a real TTY, use the arrow keys to move, Space to mark or unmark an agent,
40
+ and Enter to confirm. At least one agent is required.
41
+
42
+ When standard input is redirected, the deterministic fallback accepts a
43
+ comma-separated value such as:
44
+
45
+ ```text
46
+ copilot,claude
47
+ ```
48
+
49
+ Noninteractive commands use:
50
+
51
+ ```bash
52
+ --agents copilot,claude
53
+ ```
54
+
55
+ Spec Kit additionally requires `--default-agent copilot` or
56
+ `--default-agent claude` when both are selected. OpenSpec does not record a
57
+ default agent.
58
+
59
+ ## Readiness and ownership
60
+
61
+ The selected framework CLI and every selected agent are blocking workstation
62
+ requirements. Liftoff may detect Copilot through its CLI or supported VS Code
63
+ extensions. Claude Code is checked through version and health probes.
64
+
65
+ Framework files remain owned by the official initializer. Liftoff validates
66
+ them but excludes framework-owned output from durable artifact hashes so a
67
+ framework can manage its own lifecycle.
68
+
69
+ ## Optional Code Apps plugin
70
+
71
+ Power Apps projects can request Microsoft's
72
+ `code-apps-preview@power-platform-skills` plugin. The integration is optional,
73
+ Preview, and independent for each selected agent.
74
+
75
+ Liftoff runs only allowlisted read-only plugin-list probes. A missing or
76
+ unobservable plugin produces advisory guidance and never makes initialization
77
+ or doctor fail by itself.
78
+
79
+ Install the targeted plugin manually inside the selected agent:
80
+
81
+ ```text
82
+ /plugin marketplace add microsoft/power-platform-skills
83
+ /plugin install code-apps-preview@power-platform-skills
84
+ ```
85
+
86
+ Liftoff does not run Microsoft's broad marketplace installer and does not
87
+ invoke `/create-code-app`. The plugin's connector and deployment skills remain
88
+ available for post-creation work.
89
+
90
+ Changing the valid plugin preference in `liftoff.config.json` is reconciled by
91
+ `liftoff update`; it updates generated guidance and manifest intent without
92
+ creating API or infrastructure artifacts.