@msn-control/liftoff 0.6.1 → 0.7.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.
@@ -24,8 +24,9 @@ plan -> init or migrate -> validate and doctor -> update -> dev and infra helper
24
24
  | `liftoff migrate <source>` | Creates a new sibling scaffold and filtered source copy without changing the source |
25
25
  | `liftoff validate [project]` | Validates manifest identity, durable files, workload metadata, and framework markers |
26
26
  | `liftoff doctor [project]` | Runs read-only workload-derived project and workstation diagnostics |
27
- | `liftoff update [project]` | Reports drift and, in an interactive terminal, explains impact and asks before applying |
28
- | `liftoff update --apply` | Applies safe changes, preserves unforced conflicts, and records the resulting manifest |
27
+ | `liftoff update [project]` | Applies safe managed drift immediately, preserves unforced conflicts and orphans, and records the resulting manifest |
28
+ | `liftoff update --check` | Reports drift without preflight or mutation; exits 0 when clean and 2 when drift exists |
29
+ | `liftoff update --force` | Applies safe changes and overwrites only the exact guarded conflicts reported by update |
29
30
  | `liftoff dev` | Prints workload-appropriate local development commands; it does not execute them |
30
31
  | `liftoff infra` | Prints OpenTofu guidance for API workloads and reports infrastructure as not applicable for Power Apps |
31
32
  | `liftoff patterns` | Lists GenAI patterns |
@@ -64,30 +65,46 @@ Consent options are documented in [safety and consent](safety-and-consent.md).
64
65
 
65
66
  ```bash
66
67
  liftoff update
68
+ liftoff update --force
67
69
  liftoff update --json
68
- liftoff update --apply
69
- liftoff update --apply --force
70
+ liftoff update --check
71
+ liftoff update --check --json
70
72
  ```
71
73
 
72
- With interactive input and output, plain `liftoff update` first reports drift
73
- and its impact. Safe managed changes use a default-No confirmation. Local or
74
- user-owned conflicts are listed separately and require another default-No
75
- confirmation before replacement. Liftoff collects both decisions before any
76
- preflight or write.
74
+ Plain `liftoff update` is imperative and prompt-free. It applies safe new,
75
+ missing, untouched-upgrade, clean-move, and recorded-state changes in
76
+ interactive terminals, redirected streams, and automation. Local or user-owned
77
+ conflicts are skipped and reported. Orphans are reported without deletion.
77
78
 
78
- With redirected input or output, plain update remains a read-only check and
79
- prints the explicit apply command. `--json` also remains prompt-free and
80
- read-only unless combined with `--apply`. Explicit `--apply` and
81
- `--apply --force` bypass prompts for automation.
79
+ Use `--check` whenever no project bytes may change. Human check mode prints each
80
+ drift state and recommends plain update for safe changes or a reviewed
81
+ `--force` invocation for conflicts. `--check --force` is invalid because check
82
+ mode never authorizes writes.
82
83
 
83
- The impact summary identifies affected dependency definitions, but update does
84
- not install dependencies. Orphans are reported without deletion. Transaction
85
- snapshots restore a failed update, but Liftoff retains no backup after a
86
- successful overwrite; commit or copy local work first.
84
+ `--json` selects output format, not safety. `liftoff update --json` applies safe
85
+ changes and emits the versioned apply result. `liftoff update --check --json`
86
+ is the read-only automation gate.
87
87
 
88
- `--force` is valid only with `--apply`. It overwrites reported file conflicts;
89
- it does not permit workload, API stack, GenAI pattern, framework, selected
90
- agent, or user-supplied Power Apps starter identity changes.
88
+ Update never installs dependencies. Transaction snapshots restore a failed
89
+ update, but Liftoff retains no backup after a successful overwrite; commit or
90
+ copy local work before using `--force`. Force does not permit workload, API
91
+ stack, GenAI pattern, framework, selected-agent, or user-supplied Power Apps
92
+ starter identity changes, and it cannot bypass project-boundary, symlink,
93
+ structural-collision, or manifest guards.
94
+
95
+ ### Migration from 0.6.x
96
+
97
+ The `--apply` flag was removed in 0.7.0. These are historical 0.6.x commands,
98
+ not current syntax:
99
+
100
+ | Historical 0.6.x command | 0.7.0 replacement |
101
+ | --- | --- |
102
+ | `liftoff update` when used as a read-only check | `liftoff update --check` |
103
+ | `liftoff update --apply` | `liftoff update` |
104
+ | `liftoff update --apply --force` | `liftoff update --force` |
105
+
106
+ Invoking removed syntax fails during argument parsing, before project discovery
107
+ or filesystem access.
91
108
 
92
109
  ## JSON and exit codes
93
110
 
@@ -97,15 +114,18 @@ Machine-readable maintenance contracts bypass decorative presentation:
97
114
  liftoff validate --json
98
115
  liftoff doctor --json
99
116
  liftoff update --json
117
+ liftoff update --check --json
100
118
  ```
101
119
 
102
120
  Each JSON object has a top-level numeric `schemaVersion`.
121
+ Operational warnings, such as a dirty-worktree warning before JSON apply, are
122
+ written to stderr so stdout remains one parseable JSON object.
103
123
 
104
124
  Exit codes:
105
125
 
106
126
  - `0`: success or a clean check.
107
127
  - `1`: invalid input, unsafe state, or command failure.
108
- - `2`: a read-only check or declined interactive update found drift.
128
+ - `2`: explicit update check mode found drift.
109
129
 
110
130
  Raw installer, framework, and dependency child stdout and stderr are forwarded
111
131
  unchanged.
@@ -67,10 +67,9 @@ Readers support schemas v2, v3, and v4:
67
67
  - V3 normalizes flat GenAI or API identity plus framework and agent metadata.
68
68
  - V4 represents the discriminated workload model, including Power Apps.
69
69
 
70
- A non-interactive or JSON check, or a declined interactive update, leaves an
71
- old manifest byte-for-byte unchanged. A successful explicit or interactively
72
- accepted apply writes v4 only after the file transaction succeeds. Skipped
73
- conflicts retain their recorded hashes.
70
+ `liftoff update --check`, including `--check --json`, leaves an old manifest
71
+ byte-for-byte unchanged. A successful plain update writes v4 only after the
72
+ file transaction succeeds. Skipped conflicts retain their recorded hashes.
74
73
 
75
74
  ## Artifact ownership
76
75
 
@@ -64,15 +64,15 @@ Use:
64
64
 
65
65
  ```bash
66
66
  liftoff validate
67
+ liftoff update --check
67
68
  liftoff update
68
- liftoff update --apply
69
69
  ```
70
70
 
71
- In an interactive terminal, plain update reports drift and impact, then asks
72
- with a default of No before applying safe managed changes. Local or user-owned
73
- conflicts require a separate default-No overwrite decision. Redirected and
74
- JSON checks remain read-only and prompt-free; use `--apply` for explicit
75
- automation consent.
71
+ Use `--check` first when the invocation must be read-only. Plain update applies
72
+ safe managed changes immediately and without prompting in terminals and
73
+ automation, while preserving conflicts and orphans. Review every reported
74
+ conflict and commit or copy local work before choosing `liftoff update --force`.
75
+ For CI drift gates, use `liftoff update --check --json`.
76
76
 
77
77
  ## Existing non-Liftoff application
78
78
 
@@ -8,7 +8,7 @@ project dependencies. No one permission implies another.
8
8
  | Flag | Authorizes | Does not authorize |
9
9
  | --- | --- | --- |
10
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 |
11
+ | `--force` | During init, listed regular-file replacements; during update, exact reported conflicts | Manifest guards, symlinks, structural collisions, tools, dependencies, or non-empty migration targets |
12
12
  | `--install-tools` | Allowlisted workstation installation commands | Project decisions, overwrites, or project dependencies |
13
13
  | `--install-dependencies` | Locked project-local dependency commands after a successful merge | Machine tools, project decisions, or overwrites |
14
14
 
@@ -50,11 +50,10 @@ Individual project files use temporary-file replacement. Initialization keeps
50
50
  backups for replaced files and records created files and directories. A handled
51
51
  merge failure restores or removes those entries in reverse order.
52
52
 
53
- An accepted interactive update or `liftoff update --apply` preflights all
54
- affected paths and applies generated file, move, delete, and manifest mutations
55
- as one rollback-capable transaction. Schema upgrades are committed only after
56
- the other mutations succeed. A corrected retry converges from the restored
57
- state.
53
+ Plain `liftoff update` preflights all affected paths and applies generated file,
54
+ move, delete, and manifest mutations as one rollback-capable transaction.
55
+ Schema upgrades are committed only after the other mutations succeed. A
56
+ corrected retry converges from the restored state.
58
57
 
59
58
  If automatic rollback itself cannot safely restore a path because another
60
59
  process changed it, Liftoff reports the incomplete rollback rather than
@@ -65,24 +64,25 @@ does not retain them as backups after success.
65
64
 
66
65
  ## Update ownership
67
66
 
68
- Plain `liftoff update` always reports drift before any write:
67
+ Update mode is selected explicitly rather than from terminal interactivity:
69
68
 
70
69
  - Clean generated files remain unchanged.
71
- - In an interactive terminal, new, missing, untouched-upgrade, clean-move, and
72
- recorded-state changes are summarized and offered through a default-No
73
- confirmation.
74
- - With redirected input or output, or with `--json`, update remains a
75
- prompt-free read-only check unless `--apply` is explicitly supplied.
70
+ - Plain `liftoff update` immediately applies safe new, missing,
71
+ untouched-upgrade, clean-move, and recorded-state changes without prompting,
72
+ including with redirected input or output.
73
+ - `liftoff update --check` is read-only and performs no preflight or mutation.
74
+ - `liftoff update --json` applies safe changes and returns an apply result;
75
+ `liftoff update --check --json` is the read-only machine drift gate.
76
76
  - Developer edits that also differ from the current template are conflicts.
77
- - Safe-update consent does not authorize conflicts. Interactive conflicts are
78
- listed by portable relative path and require a separate default-No overwrite
79
- confirmation; automation uses `--apply --force`.
77
+ - Default update skips conflicts and lists them by portable relative path.
78
+ After reviewing every listed overwrite, `liftoff update --force` extends the
79
+ transaction only to those guarded conflicts.
80
80
  - Orphans are reported and left on disk for manual review.
81
81
  - Dependency definitions may be updated, but update never installs
82
82
  dependencies.
83
83
 
84
- All interactive decisions are collected before preflight or mutation.
85
- Declining the safe update changes nothing and leaves drift exit code 2.
84
+ `--force` cannot be combined with `--check` and cannot weaken project-boundary,
85
+ symlink, collision, manifest, or transaction guards.
86
86
 
87
87
  Power Apps reconciliation reads only the packaged immutable starter. It does
88
88
  not fetch the upstream repository. Workload kind and user-edited starter
@@ -98,6 +98,23 @@ does not claim framework-owned files in durable artifact hashes.
98
98
  One-time seed content is also omitted from durable hashes so it can follow its
99
99
  own lifecycle after generation.
100
100
 
101
+ ## Telemetry boundary
102
+
103
+ Liftoff sends only a recognized command name, CLI version, and zero/nonzero
104
+ outcome after a command completes. It creates no persistent installation or
105
+ session identifier and sends no arguments, paths, project data, errors, timing,
106
+ or host details.
107
+
108
+ Telemetry is enabled by default after a one-time disclosure. Set
109
+ `LIFTOFF_TELEMETRY=0` or `DO_NOT_TRACK=1` to disable it; `CI=true` disables it
110
+ automatically. Delivery is one bounded HTTPS attempt and cannot change command
111
+ output or exit status.
112
+
113
+ Azure necessarily handles a source network address while routing HTTPS, but
114
+ Liftoff does not include it in the event, derive geolocation from it, or persist
115
+ it in the product telemetry table. See [telemetry and privacy](telemetry.md) for
116
+ the exact fields, Azure boundary, OpenTofu deployment, and 180-day retention.
117
+
101
118
  ## Credentials and external actions
102
119
 
103
120
  Generated files contain configuration boundaries, not real credentials.
@@ -88,5 +88,6 @@ invoke `/create-code-app`. The plugin's connector and deployment skills remain
88
88
  available for post-creation work.
89
89
 
90
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.
91
+ plain `liftoff update`; it immediately updates generated guidance and manifest
92
+ intent without creating API or infrastructure artifacts. Use
93
+ `liftoff update --check` to inspect that drift without writing.
@@ -0,0 +1,168 @@
1
+ # Telemetry and privacy
2
+
3
+ Liftoff collects a small aggregate event to understand which CLI commands are
4
+ useful and whether they exit with zero or nonzero status. Telemetry is enabled
5
+ by default, disclosed before the first eligible command, and never required for
6
+ the CLI to work. It creates no persistent installation or session identifier.
7
+
8
+ ## Event contract
9
+
10
+ Each recognized command can send at most one event after it finishes:
11
+
12
+ ```json
13
+ {
14
+ "schemaVersion": 1,
15
+ "event": "command_executed",
16
+ "command": "infra:plan",
17
+ "cliVersion": "0.6.1",
18
+ "outcome": "success"
19
+ }
20
+ ```
21
+
22
+ `outcome` is `success` for exit code zero and `failure` for every nonzero exit
23
+ code. It is an exit-status class, not an error diagnosis. Help requests are
24
+ recorded as `help`, and rejected input that never resolves to a recognized
25
+ command is not recorded.
26
+
27
+ Liftoff does **not** send:
28
+
29
+ - An installation, user, device, or session identifier.
30
+ - A client timestamp or duration.
31
+ - Arguments, flags, paths, project names, config values, manifests, or generated
32
+ content.
33
+ - Error text, stack traces, operating-system details, Node.js version, cloud,
34
+ workload, region, or environment choices.
35
+ - A source IP address or derived location in the event.
36
+
37
+ Liftoff creates no telemetry queue and stores no event locally. Its only local
38
+ telemetry state is a numeric disclosure version in the platform configuration
39
+ directory.
40
+
41
+ ## Disable telemetry
42
+
43
+ Set either variable before running Liftoff:
44
+
45
+ ```bash
46
+ export LIFTOFF_TELEMETRY=0
47
+ export DO_NOT_TRACK=1
48
+ ```
49
+
50
+ On PowerShell:
51
+
52
+ ```powershell
53
+ $env:LIFTOFF_TELEMETRY = "0"
54
+ $env:DO_NOT_TRACK = "1"
55
+ ```
56
+
57
+ Telemetry is also disabled when `CI=true`. Disabled runs do not show the notice,
58
+ create telemetry state, or initialize network transport.
59
+
60
+ ## Delivery and failure behavior
61
+
62
+ The CLI makes one HTTPS request after command completion with a maximum
63
+ one-second delivery budget. It does not retry, buffer, read a response body, or
64
+ report telemetry failures. Offline use, command output, JSON stdout, and the
65
+ original exit status remain unchanged when the service is unavailable.
66
+
67
+ ## Azure processing and retention
68
+
69
+ The public endpoint is a strict-schema plain Node.js service in Azure Container
70
+ Apps. It counts streamed bytes before parsing, rejects unknown or additional
71
+ fields, and adds server-side `TimeGenerated`. A managed identity then writes only
72
+ these Liftoff-defined columns through an Azure Monitor data collection rule:
73
+
74
+ ```text
75
+ TimeGenerated, EventName, SchemaVersion, Command, CliVersion, Outcome
76
+ ```
77
+
78
+ Azure Monitor adds standard workspace system columns after the data collection
79
+ rule transformation. Those platform columns contain tenant, type, item, and
80
+ billing metadata; they are not additional Liftoff event fields and are not
81
+ populated from the request body, source IP, or derived geolocation.
82
+
83
+ Azure networking necessarily handles the source network address while routing
84
+ HTTPS. Liftoff does not copy that address into the event, derive geolocation
85
+ from it, forward it to the data collection rule, or configure the product
86
+ workspace to persist Container Apps ingress or console telemetry. The Container
87
+ Apps environment has persistent platform logs disabled, and the gateway has no
88
+ Application Insights connection string or instrumentation key.
89
+
90
+ Accepted events are stored in `LiftoffCommandEvents_CL` in the operator-selected
91
+ Azure region for 180 days of analytics and total retention, with no additional
92
+ long-term retention. Query access uses Microsoft Entra ID and Azure RBAC.
93
+ Aggregate counts are directional because a public, unauthenticated endpoint can
94
+ receive forged events.
95
+
96
+ ## Operator deployment boundary
97
+
98
+ Production telemetry resources are created and managed in the fixed resource
99
+ group `rg-liftoff-prod`. OpenTofu owns the group, applies deletion protection,
100
+ and deploys ACR Basic, a commit-pinned ACR build task, a Container Apps
101
+ environment, one warm Container App replica, managed identity, workspace,
102
+ custom table, data collection endpoint, and data collection rule.
103
+
104
+ The registry contains only the already-public gateway image. Administrator
105
+ credentials and anonymous pull are disabled; the Container App uses its
106
+ resource-scoped `AcrPull` identity. A full public Git commit SHA identifies the
107
+ build tag; the running Container App is pinned to the resolved `sha256` manifest
108
+ digest, never a branch, `latest`, or tag-only reference.
109
+
110
+ OpenTofu state storage remains in a separate enforced Azure Network Security
111
+ Perimeter. Its explicit operator IPv4 `/32` CIDRs live only in ignored local
112
+ inputs, and Entra authentication plus storage-scoped RBAC remain required. The
113
+ Container App needs no Function host/deployment storage, package blob, or Azure
114
+ Files share.
115
+
116
+ The gateway uses the smallest Container Apps Consumption allocation: 0.25 vCPU,
117
+ 0.5 GiB, one minimum replica, and five maximum replicas. Keeping one replica
118
+ ready prevents scale-to-zero cold starts from consuming the client's one-second
119
+ delivery budget. It adds reduced idle compute cost plus ACR Basic cost.
120
+
121
+ From the repository root, operators build and validate with:
122
+
123
+ ```bash
124
+ npm ci --prefix services/telemetry-ingest
125
+ npm run check --prefix services/telemetry-ingest
126
+ npm run package --prefix services/telemetry-ingest
127
+ npm run smoke:container --prefix services/telemetry-ingest
128
+ tofu -chdir=infrastructure/opentofu/telemetry fmt -check
129
+ tofu -chdir=infrastructure/opentofu/telemetry init -backend=false
130
+ tofu -chdir=infrastructure/opentofu/telemetry validate
131
+ ```
132
+
133
+ Real environments must use access-controlled remote state and Entra
134
+ authentication. Before apply, review the subscription, region, unique resource
135
+ suffix, full public source revision, immutable image digest,
136
+ `rg-liftoff-prod` deletion protection, ACR administrator and anonymous-access
137
+ disablement, managed-identity roles, one-to-five replica bounds, disabled
138
+ persistent platform logs, six-column schema, 180-day retention, ingestion
139
+ quota, and state perimeter rules. Operator CIDRs live only in ignored local
140
+ inputs. If the operator IP changes, update and apply the bootstrap access rule
141
+ through the Azure control plane before retrying backend access. Use the same
142
+ reviewed production variable file for every plan, apply, and emergency
143
+ disablement so region, image revision, and quota inputs cannot fall back to
144
+ defaults.
145
+ Every infrastructure lifecycle action uses `tofu`; Liftoff does not use Bicep,
146
+ `azd`, Terraform CLI, or ad hoc Azure resource commands for this service.
147
+
148
+ Standard GitHub-hosted runners run static validation only. They do not plan or
149
+ apply production because their dynamic networks are not admitted to the
150
+ perimeter.
151
+
152
+ After apply, operators must verify the registry identity boundary, one ready
153
+ replica, sub-second endpoint response, synthetic allowlisted event, six
154
+ Liftoff-defined columns, expected Azure system columns, server time, retention,
155
+ and absence of request, IP, geolocation, Container Apps platform/console, or
156
+ Application Insights records before compiling the endpoint into a Liftoff
157
+ release.
158
+
159
+ The final production architecture contains no Function App, FC1 plan, product
160
+ storage, OneDeploy action, or production storage-perimeter association.
161
+
162
+ For emergency disablement, apply the OpenTofu configuration with
163
+ `ingestion_enabled=false`, then publish a patch with client delivery disabled.
164
+ Rollback preserves `rg-liftoff-prod`; do not destroy the protected production
165
+ resource group.
166
+
167
+ Normal `liftoff` commands never authenticate to Azure, read OpenTofu state, or
168
+ deploy telemetry infrastructure.
@@ -67,15 +67,13 @@ hand-edited unsafe path.
67
67
 
68
68
  ## Update reports conflicts or orphans
69
69
 
70
- In an interactive terminal, `liftoff update` shows an impact summary and asks
71
- before applying safe managed changes. The default answer is No.
72
-
73
- - Local or user-owned conflicts are listed separately and require their own
74
- default-No overwrite confirmation.
75
- - With redirected input or output, review the report and apply safe changes
76
- with `liftoff update --apply`.
77
- - For prompt-free conflict replacement, use `liftoff update --apply --force`
78
- only after reviewing every listed path.
70
+ `liftoff update` applies safe managed changes immediately and skips conflicts.
71
+
72
+ - Use `liftoff update --check` for a read-only human report or
73
+ `liftoff update --check --json` for an automation drift gate.
74
+ - Local or user-owned conflicts remain untouched by default.
75
+ - Use `liftoff update --force` only after reviewing every listed path and
76
+ deciding that each overwrite is intended.
79
77
  - Orphans are never deleted automatically.
80
78
  - Update reports dependency-definition impact but does not install
81
79
  dependencies.
package/docs/workloads.md CHANGED
@@ -126,3 +126,7 @@ created the application.
126
126
  workload. It does not convert among GenAI, API, and Power Apps or change an API
127
127
  stack, GenAI pattern, or user-supplied starter identity. Initialize a fresh
128
128
  project or use a supported migration flow instead.
129
+
130
+ Plain update applies safe changes immediately for every workload. Use
131
+ `liftoff update --check` for read-only inspection and review all reported
132
+ conflicts before using `liftoff update --force`; orphans remain untouched.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@msn-control/liftoff",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "Interactive CLI for governed GenAI, API, and Power Apps code app projects.",
5
5
  "type": "module",
6
6
  "license": "GPL-3.0-only",
@@ -1,23 +0,0 @@
1
- import type { ReconcileEntry } from './reconcile.js';
2
- export declare const dependencyDefinitionLogicalNames: readonly ["backend-pyproject", "function-worker-requirements", "node-backend-package", "node-backend-lock", "go-backend-module", "go-backend-checksums", "frontend-package", "frontend-lock", "power-apps-package", "power-apps-lock"];
3
- export interface UpdateImpact {
4
- readonly creates: readonly string[];
5
- readonly restores: readonly string[];
6
- readonly replacements: readonly string[];
7
- readonly moves: readonly string[];
8
- readonly recordedStateRefreshes: readonly string[];
9
- readonly conflicts: readonly string[];
10
- readonly managedPathsRemoved: readonly string[];
11
- readonly managedPathsRemovedOnOverwrite: readonly string[];
12
- readonly orphansPreserved: readonly string[];
13
- readonly dependencyDefinitions: readonly string[];
14
- readonly safeActionCount: number;
15
- readonly localOrUserOwnedFilesAtRisk: number;
16
- readonly manifestWillUpdate: boolean;
17
- readonly installsDependencies: false;
18
- readonly deletesOrphans: false;
19
- readonly retainsBackupAfterSuccess: false;
20
- readonly hasSafeActions: boolean;
21
- readonly hasActionableChanges: boolean;
22
- }
23
- export declare function buildUpdateImpact(entries: readonly ReconcileEntry[]): UpdateImpact;
@@ -1,127 +0,0 @@
1
- import { manifestDisplayPath } from './file-system.js';
2
- export const dependencyDefinitionLogicalNames = Object.freeze([
3
- 'backend-pyproject',
4
- 'function-worker-requirements',
5
- 'node-backend-package',
6
- 'node-backend-lock',
7
- 'go-backend-module',
8
- 'go-backend-checksums',
9
- 'frontend-package',
10
- 'frontend-lock',
11
- 'power-apps-package',
12
- 'power-apps-lock'
13
- ]);
14
- const dependencyDefinitionLogicalNameSet = new Set(dependencyDefinitionLogicalNames);
15
- function comparePortable(left, right) {
16
- return left < right ? -1 : left > right ? 1 : 0;
17
- }
18
- function displayEntry(entry) {
19
- const current = manifestDisplayPath(entry.pathParts);
20
- return entry.previousPathParts
21
- ? `${manifestDisplayPath(entry.previousPathParts)} => ${current}`
22
- : current;
23
- }
24
- function freezeSorted(values) {
25
- return Object.freeze(values.sort(comparePortable));
26
- }
27
- function isActionable(entry) {
28
- return entry.status !== 'orphan' &&
29
- (entry.status !== 'unchanged' || entry.refreshHash === true);
30
- }
31
- export function buildUpdateImpact(entries) {
32
- const creates = [];
33
- const restores = [];
34
- const replacements = [];
35
- const moves = [];
36
- const recordedStateRefreshes = [];
37
- const conflicts = [];
38
- const managedPathsRemoved = [];
39
- const managedPathsRemovedOnOverwrite = [];
40
- const orphansPreserved = [];
41
- const dependencyDefinitions = [];
42
- for (const entry of entries) {
43
- switch (entry.status) {
44
- case 'new':
45
- creates.push(manifestDisplayPath(entry.pathParts));
46
- break;
47
- case 'missing':
48
- restores.push(manifestDisplayPath(entry.pathParts));
49
- break;
50
- case 'upgrade':
51
- replacements.push(manifestDisplayPath(entry.pathParts));
52
- break;
53
- case 'moved':
54
- if (entry.cleanMove) {
55
- moves.push(displayEntry(entry));
56
- if (entry.previousPathParts) {
57
- managedPathsRemoved.push(manifestDisplayPath(entry.previousPathParts));
58
- }
59
- }
60
- else {
61
- if (entry.sourceModified && entry.previousPathParts) {
62
- conflicts.push(manifestDisplayPath(entry.previousPathParts));
63
- }
64
- if (entry.destinationOccupied && !entry.destinationMatches) {
65
- conflicts.push(manifestDisplayPath(entry.pathParts));
66
- }
67
- if (entry.previousPathParts) {
68
- managedPathsRemovedOnOverwrite.push(manifestDisplayPath(entry.previousPathParts));
69
- }
70
- }
71
- break;
72
- case 'conflict':
73
- conflicts.push(manifestDisplayPath(entry.pathParts));
74
- break;
75
- case 'orphan':
76
- orphansPreserved.push(manifestDisplayPath(entry.pathParts));
77
- break;
78
- case 'unchanged':
79
- if (entry.refreshHash) {
80
- recordedStateRefreshes.push(manifestDisplayPath(entry.pathParts));
81
- }
82
- break;
83
- }
84
- if (isActionable(entry) &&
85
- dependencyDefinitionLogicalNameSet.has(entry.logicalName)) {
86
- dependencyDefinitions.push(manifestDisplayPath(entry.pathParts));
87
- }
88
- }
89
- const frozenCreates = freezeSorted(creates);
90
- const frozenRestores = freezeSorted(restores);
91
- const frozenReplacements = freezeSorted(replacements);
92
- const frozenMoves = freezeSorted(moves);
93
- const frozenRefreshes = freezeSorted(recordedStateRefreshes);
94
- const frozenConflicts = freezeSorted(conflicts);
95
- const frozenManagedPaths = freezeSorted(managedPathsRemoved);
96
- const frozenManagedOverwritePaths = freezeSorted(managedPathsRemovedOnOverwrite);
97
- const frozenOrphans = freezeSorted(orphansPreserved);
98
- const frozenDependencyDefinitions = freezeSorted(dependencyDefinitions);
99
- const safeActionCount = frozenCreates.length +
100
- frozenRestores.length +
101
- frozenReplacements.length +
102
- frozenMoves.length +
103
- frozenRefreshes.length;
104
- const hasSafeActions = safeActionCount > 0;
105
- const hasActionableChanges = hasSafeActions || frozenConflicts.length > 0;
106
- return Object.freeze({
107
- creates: frozenCreates,
108
- restores: frozenRestores,
109
- replacements: frozenReplacements,
110
- moves: frozenMoves,
111
- recordedStateRefreshes: frozenRefreshes,
112
- conflicts: frozenConflicts,
113
- managedPathsRemoved: frozenManagedPaths,
114
- managedPathsRemovedOnOverwrite: frozenManagedOverwritePaths,
115
- orphansPreserved: frozenOrphans,
116
- dependencyDefinitions: frozenDependencyDefinitions,
117
- safeActionCount,
118
- localOrUserOwnedFilesAtRisk: frozenConflicts.length,
119
- manifestWillUpdate: hasActionableChanges,
120
- installsDependencies: false,
121
- deletesOrphans: false,
122
- retainsBackupAfterSuccess: false,
123
- hasSafeActions,
124
- hasActionableChanges
125
- });
126
- }
127
- //# sourceMappingURL=update-impact.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"update-impact.js","sourceRoot":"","sources":["../src/update-impact.ts"],"names":[],"mappings":"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"}