@topogram/cli 0.3.64 → 0.3.66
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/package.json +1 -1
- package/src/adoption/plan/index.js +716 -0
- package/src/adoption/plan.js +12 -703
- package/src/adoption/reporting.js +1 -1
- package/src/agent-brief.js +7 -21
- package/src/agent-ops/query-builders/auth.js +375 -0
- package/src/agent-ops/query-builders/change-risk/change-plan.js +123 -0
- package/src/agent-ops/query-builders/change-risk/import-plan.js +49 -0
- package/src/agent-ops/query-builders/change-risk/maintained.js +286 -0
- package/src/agent-ops/query-builders/change-risk/review-packets.js +123 -0
- package/src/agent-ops/query-builders/change-risk/risk.js +189 -0
- package/src/agent-ops/query-builders/change-risk.js +25 -0
- package/src/agent-ops/query-builders/common.js +149 -0
- package/src/agent-ops/query-builders/maintained-risk.js +539 -0
- package/src/agent-ops/query-builders/maintained-shared.js +120 -0
- package/src/agent-ops/query-builders/multi-agent.js +547 -0
- package/src/agent-ops/query-builders/projection-impacts.js +514 -0
- package/src/agent-ops/query-builders/work-packets.js +417 -0
- package/src/agent-ops/query-builders/workflow-context-shared.js +300 -0
- package/src/agent-ops/query-builders/workflow-context.js +398 -0
- package/src/agent-ops/query-builders/workflow-presets-core.js +677 -0
- package/src/agent-ops/query-builders/workflow-presets.js +341 -0
- package/src/agent-ops/query-builders.d.ts +26 -26
- package/src/agent-ops/query-builders.js +42 -5021
- package/src/archive/jsonl.js +2 -2
- package/src/archive/resolver-bridge.js +1 -1
- package/src/archive/unarchive.js +2 -1
- package/src/catalog/constants.js +10 -0
- package/src/catalog/copy.js +65 -0
- package/src/catalog/diagnostics.js +15 -0
- package/src/catalog/entries.js +42 -0
- package/src/catalog/files.js +67 -0
- package/src/catalog/provenance.js +123 -0
- package/src/catalog/source.js +150 -0
- package/src/catalog/validation.js +252 -0
- package/src/catalog.d.ts +2 -0
- package/src/catalog.js +18 -746
- package/src/cli/command-parsers/project.js +3 -0
- package/src/cli/command-parsers/shared.js +1 -1
- package/src/cli/commands/agent.js +2 -2
- package/src/cli/commands/catalog/check.js +31 -0
- package/src/cli/commands/catalog/copy.js +59 -0
- package/src/cli/commands/catalog/doctor.js +248 -0
- package/src/cli/commands/catalog/help.js +21 -0
- package/src/cli/commands/catalog/list.js +52 -0
- package/src/cli/commands/catalog/runner.js +92 -0
- package/src/cli/commands/catalog/shared.js +17 -0
- package/src/cli/commands/catalog/show.js +134 -0
- package/src/cli/commands/catalog.js +30 -615
- package/src/cli/commands/check.js +3 -3
- package/src/cli/commands/doctor.js +2 -9
- package/src/cli/commands/generator-policy/package-info.js +162 -0
- package/src/cli/commands/generator-policy/payloads.js +372 -0
- package/src/cli/commands/generator-policy/printers.js +159 -0
- package/src/cli/commands/generator-policy/runner.js +81 -0
- package/src/cli/commands/generator-policy/shared.js +39 -0
- package/src/cli/commands/generator-policy.js +15 -783
- package/src/cli/commands/import/adopt.js +170 -0
- package/src/cli/commands/import/check.js +91 -0
- package/src/cli/commands/import/diff.js +84 -0
- package/src/cli/commands/import/help.js +47 -0
- package/src/cli/commands/import/paths.js +269 -0
- package/src/cli/commands/import/plan.js +292 -0
- package/src/cli/commands/import/refresh.js +471 -0
- package/src/cli/commands/import/status-history.js +196 -0
- package/src/cli/commands/import/workspace.js +233 -0
- package/src/cli/commands/import.js +33 -1732
- package/src/cli/commands/migrate.js +153 -0
- package/src/cli/commands/package/constants.js +17 -0
- package/src/cli/commands/package/doctor.js +240 -0
- package/src/cli/commands/package/help.js +27 -0
- package/src/cli/commands/package/lockfile.js +135 -0
- package/src/cli/commands/package/npm.js +97 -0
- package/src/cli/commands/package/reporting.js +35 -0
- package/src/cli/commands/package/runner.js +33 -0
- package/src/cli/commands/package/shared.js +9 -0
- package/src/cli/commands/package/update-cli.js +252 -0
- package/src/cli/commands/package/versions.js +35 -0
- package/src/cli/commands/package.js +29 -813
- package/src/cli/commands/query/change-plan.js +68 -0
- package/src/cli/commands/query/definitions.js +202 -0
- package/src/cli/commands/query/import-adopt.js +121 -0
- package/src/cli/commands/query/runner/artifacts.js +102 -0
- package/src/cli/commands/query/runner/boundaries.js +211 -0
- package/src/cli/commands/query/runner/change.js +182 -0
- package/src/cli/commands/query/runner/import-adopt.js +111 -0
- package/src/cli/commands/query/runner/index.js +31 -0
- package/src/cli/commands/query/runner/output.js +12 -0
- package/src/cli/commands/query/runner/workflow.js +241 -0
- package/src/cli/commands/query/runner.js +3 -0
- package/src/cli/commands/query/workflow-context.js +5 -0
- package/src/cli/commands/query/workspace.js +270 -0
- package/src/cli/commands/query.js +9 -1300
- package/src/cli/commands/source.js +3 -12
- package/src/cli/commands/template/baseline.js +100 -0
- package/src/cli/commands/template/check.js +467 -0
- package/src/cli/commands/template/constants.js +8 -0
- package/src/cli/commands/template/diagnostics.js +26 -0
- package/src/cli/commands/template/help.js +28 -0
- package/src/cli/commands/template/lifecycle.js +404 -0
- package/src/cli/commands/template/list-show.js +287 -0
- package/src/cli/commands/template/policy.js +422 -0
- package/src/cli/commands/template/shared.js +127 -0
- package/src/cli/commands/template/updates.js +352 -0
- package/src/cli/commands/template-runner.js +6 -6
- package/src/cli/commands/template.js +41 -2143
- package/src/cli/commands/trust.js +1 -1
- package/src/cli/commands/workflow.js +6 -1
- package/src/cli/dispatcher.js +6 -1
- package/src/cli/help.js +15 -14
- package/src/cli/migration-guidance.js +1 -1
- package/src/cli/output-safety.js +2 -1
- package/src/cli/path-normalization.js +3 -13
- package/src/generator/api/contracts.js +497 -0
- package/src/generator/api/metadata.js +221 -0
- package/src/generator/api/openapi.js +559 -0
- package/src/generator/api/schema.js +124 -0
- package/src/generator/api/types.d.ts +98 -0
- package/src/generator/api.js +3 -1195
- package/src/generator/context/domain-page.js +1 -1
- package/src/generator/context/shared/domain-sdlc.js +282 -0
- package/src/generator/context/shared/maintained-boundary.js +665 -0
- package/src/generator/context/shared/metrics.js +85 -0
- package/src/generator/context/shared/primitives.js +64 -0
- package/src/generator/context/shared/relationships.js +453 -0
- package/src/generator/context/shared/summaries.js +263 -0
- package/src/generator/context/shared/types.d.ts +207 -0
- package/src/generator/context/shared.d.ts +42 -0
- package/src/generator/context/shared.js +80 -1390
- package/src/generator/context/slice/core.js +397 -0
- package/src/generator/context/slice/sdlc.js +417 -0
- package/src/generator/context/slice/ui-packets.js +183 -0
- package/src/generator/context/slice.js +2 -859
- package/src/generator/context/task-mode.js +2 -2
- package/src/generator/registry/index.js +507 -0
- package/src/generator/registry.js +18 -504
- package/src/generator/runtime/environment/index.js +666 -0
- package/src/generator/runtime/environment.js +4 -666
- package/src/generator/runtime/runtime-check/index.js +554 -0
- package/src/generator/runtime/runtime-check.js +4 -554
- package/src/generator/runtime/shared/index.js +572 -0
- package/src/generator/runtime/shared.js +19 -570
- package/src/generator/sdlc/doc-page.js +1 -1
- package/src/generator/shared.d.ts +2 -0
- package/src/generator/surfaces/databases/lifecycle-shared.js +1 -1
- package/src/generator/surfaces/native/swiftui-templates/README.generated.md +1 -1
- package/src/generator/surfaces/shared.d.ts +3 -0
- package/src/generator/widget-conformance/behavior-report.js +258 -0
- package/src/generator/widget-conformance/checks.js +371 -0
- package/src/generator/widget-conformance/projection-context.js +200 -0
- package/src/generator/widget-conformance/report.js +166 -0
- package/src/generator/widget-conformance/types.d.ts +121 -0
- package/src/generator/widget-conformance.js +3 -824
- package/src/import/core/context.d.ts +3 -0
- package/src/import/core/context.js +5 -7
- package/src/import/core/contracts.d.ts +1 -0
- package/src/import/core/registry.d.ts +4 -0
- package/src/import/core/runner/candidates.js +337 -0
- package/src/import/core/runner/options.js +22 -0
- package/src/import/core/runner/reports.js +51 -0
- package/src/import/core/runner/run.js +79 -0
- package/src/import/core/runner/tracks.js +150 -0
- package/src/import/core/runner/ui-drafts.js +393 -0
- package/src/import/core/runner.js +3 -698
- package/src/import/core/shared/api-routes.js +221 -0
- package/src/import/core/shared/candidates.js +97 -0
- package/src/import/core/shared/files.js +177 -0
- package/src/import/core/shared/next-app.js +389 -0
- package/src/import/core/shared/types.d.ts +51 -0
- package/src/import/core/shared/ui-routes.js +230 -0
- package/src/import/core/shared.js +60 -861
- package/src/new-project/constants.js +128 -0
- package/src/new-project/create.js +90 -0
- package/src/new-project/json.js +28 -0
- package/src/new-project/metadata.js +96 -0
- package/src/new-project/package-spec.js +161 -0
- package/src/new-project/project-files.js +351 -0
- package/src/new-project/template-policy.js +269 -0
- package/src/new-project/template-resolution.js +370 -0
- package/src/new-project/template-snapshots.js +442 -0
- package/src/new-project/template-updates.js +512 -0
- package/src/new-project/types.d.ts +83 -0
- package/src/new-project.js +6 -2277
- package/src/parser.d.ts +87 -1
- package/src/parser.js +118 -0
- package/src/policy/review-boundaries.d.ts +15 -0
- package/src/project-config/index.js +591 -0
- package/src/project-config.js +19 -561
- package/src/resolver/enrich/acceptance-criterion.js +2 -0
- package/src/resolver/enrich/bug.js +2 -0
- package/src/resolver/enrich/pitch.js +2 -0
- package/src/resolver/enrich/requirement.js +2 -0
- package/src/resolver/enrich/task.js +2 -0
- package/src/resolver/index.js +19 -2089
- package/src/resolver/normalize.js +384 -1
- package/src/resolver/plans.js +168 -0
- package/src/resolver/projections-api.js +494 -0
- package/src/resolver/projections-db.js +133 -0
- package/src/resolver/projections-ui.js +317 -0
- package/src/resolver/shapes.js +251 -0
- package/src/resolver/shared.js +278 -0
- package/src/resolver/widgets.js +132 -0
- package/src/sdlc/adopt.js +6 -5
- package/src/sdlc/paths.js +3 -5
- package/src/sdlc/scaffold.js +2 -1
- package/src/template-trust/constants.js +62 -0
- package/src/template-trust/content.js +258 -0
- package/src/template-trust/diff.js +92 -0
- package/src/template-trust/policy.js +61 -0
- package/src/template-trust/record.js +90 -0
- package/src/template-trust/status.js +182 -0
- package/src/template-trust.js +24 -687
- package/src/text-helpers.d.ts +1 -0
- package/src/topogram-types.d.ts +69 -0
- package/src/validator/common.js +488 -0
- package/src/validator/data-model.js +237 -0
- package/src/validator/docs.js +167 -0
- package/src/validator/expressions.js +146 -1
- package/src/validator/index.d.ts +23 -0
- package/src/validator/index.js +32 -3585
- package/src/validator/kinds.d.ts +41 -0
- package/src/validator/kinds.js +2 -0
- package/src/validator/model-helpers.js +46 -0
- package/src/validator/per-kind/acceptance-criterion.js +5 -0
- package/src/validator/per-kind/bug.js +6 -0
- package/src/validator/per-kind/domain.js +15 -2
- package/src/validator/per-kind/pitch.js +7 -0
- package/src/validator/per-kind/requirement.js +5 -0
- package/src/validator/per-kind/task.js +7 -0
- package/src/validator/per-kind/widget.js +14 -0
- package/src/validator/projections/api-http-async.js +410 -0
- package/src/validator/projections/api-http-authz.js +88 -0
- package/src/validator/projections/api-http-core.js +205 -0
- package/src/validator/projections/api-http-policies.js +339 -0
- package/src/validator/projections/api-http-responses.js +233 -0
- package/src/validator/projections/api-http.js +44 -0
- package/src/validator/projections/db.js +353 -0
- package/src/validator/projections/generator-defaults.js +45 -0
- package/src/validator/projections/helpers.js +87 -0
- package/src/validator/projections/ui-helpers.js +214 -0
- package/src/validator/projections/ui-navigation.js +344 -0
- package/src/validator/projections/ui-structure.js +364 -0
- package/src/validator/projections/ui-widgets.js +493 -0
- package/src/validator/projections/ui.js +46 -0
- package/src/validator/registry.js +48 -1
- package/src/validator/utils.d.ts +20 -0
- package/src/validator/utils.js +115 -12
- package/src/widget-behavior.d.ts +1 -0
- package/src/workflows/import-app/api/collect.js +221 -0
- package/src/workflows/import-app/api/openapi.js +257 -0
- package/src/workflows/import-app/api/routes.js +327 -0
- package/src/workflows/import-app/api/sources.js +22 -0
- package/src/workflows/import-app/api.js +2 -797
- package/src/workflows/reconcile/adoption-plan/build.js +212 -0
- package/src/workflows/reconcile/adoption-plan/dependencies.js +75 -0
- package/src/workflows/reconcile/adoption-plan/outputs.js +153 -0
- package/src/workflows/reconcile/adoption-plan/paths.js +58 -0
- package/src/workflows/reconcile/adoption-plan/projection-patches.js +177 -0
- package/src/workflows/reconcile/adoption-plan/reasons.js +107 -0
- package/src/workflows/reconcile/adoption-plan.js +30 -740
- package/src/workflows/reconcile/auth/closures.js +115 -0
- package/src/workflows/reconcile/auth/formatters.js +142 -0
- package/src/workflows/reconcile/auth/inference.js +330 -0
- package/src/workflows/reconcile/auth/roles.js +122 -0
- package/src/workflows/reconcile/auth.js +35 -690
- package/src/workflows/reconcile/bundle-core/index.js +600 -0
- package/src/workflows/reconcile/bundle-core.js +12 -598
- package/src/workflows/reconcile/candidate-model.js +18 -2
- package/src/workflows/reconcile/canonical-surface.js +1 -1
- package/src/workflows/reconcile/impacts/adoption-plan.js +196 -0
- package/src/workflows/reconcile/impacts/indexes.js +105 -0
- package/src/workflows/reconcile/impacts/patches.js +252 -0
- package/src/workflows/reconcile/impacts/reports.js +80 -0
- package/src/workflows/reconcile/impacts.js +14 -623
- package/src/workflows/reconcile/renderers.js +41 -6
- package/src/workflows/shared.js +5 -11
- package/src/workspace-docs.d.ts +29 -0
- package/src/workspace-paths.js +328 -0
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
|
|
6
|
+
import { stableStringify } from "../../../format.js";
|
|
7
|
+
import { loadProjectConfig } from "../../../project-config.js";
|
|
8
|
+
import {
|
|
9
|
+
applyTemplateUpdate,
|
|
10
|
+
applyTemplateUpdateFileAction,
|
|
11
|
+
buildTemplateUpdateCheck,
|
|
12
|
+
buildTemplateUpdatePlan,
|
|
13
|
+
buildTemplateUpdateStatus
|
|
14
|
+
} from "../../../new-project.js";
|
|
15
|
+
import { TEMPLATES_ROOT } from "./constants.js";
|
|
16
|
+
import { templateCheckDiagnostic } from "./diagnostics.js";
|
|
17
|
+
import { latestTemplateInfo, messageFromError, templateMetadataFromProjectConfig } from "./shared.js";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {any} plan
|
|
21
|
+
* @returns {void}
|
|
22
|
+
*/
|
|
23
|
+
export function printTemplateUpdatePlan(plan) {
|
|
24
|
+
const isApply = plan.mode === "apply";
|
|
25
|
+
const isCheck = plan.mode === "check";
|
|
26
|
+
const isStatus = plan.mode === "status";
|
|
27
|
+
const isFileAction = ["accept-current", "accept-candidate", "delete-current"].includes(plan.mode);
|
|
28
|
+
if (isApply) {
|
|
29
|
+
console.log(plan.ok ? "Template update apply: complete" : "Template update apply: refused");
|
|
30
|
+
} else if (isStatus) {
|
|
31
|
+
console.log(plan.ok ? "Template update status: aligned" : "Template update status: action needed");
|
|
32
|
+
} else if (isCheck) {
|
|
33
|
+
console.log(plan.ok ? "Template update check: aligned" : "Template update check: out of date");
|
|
34
|
+
} else if (isFileAction) {
|
|
35
|
+
console.log(plan.ok ? `Template update ${plan.mode}: complete` : `Template update ${plan.mode}: refused`);
|
|
36
|
+
} else {
|
|
37
|
+
console.log(plan.ok ? "Template update plan: ready for review" : "Template update plan: incompatible");
|
|
38
|
+
}
|
|
39
|
+
console.log(`Current: ${plan.current?.id || "unknown"}@${plan.current?.version || "unknown"}`);
|
|
40
|
+
console.log(`Candidate: ${plan.candidate?.id || "unknown"}@${plan.candidate?.version || "unknown"}`);
|
|
41
|
+
console.log(`Writes: ${plan.writes ? "applied" : "none"}`);
|
|
42
|
+
if (plan.reportPath) {
|
|
43
|
+
console.log(`Report: ${plan.reportPath}`);
|
|
44
|
+
}
|
|
45
|
+
console.log(`Added: ${plan.summary.added}`);
|
|
46
|
+
console.log(`Changed: ${plan.summary.changed}`);
|
|
47
|
+
console.log(`Current-only: ${plan.summary.currentOnly}`);
|
|
48
|
+
console.log(`Unchanged: ${plan.summary.unchanged}`);
|
|
49
|
+
if (isApply || isStatus || isFileAction) {
|
|
50
|
+
const appliedCount = (plan.applied || []).length;
|
|
51
|
+
const acceptedCount = (plan.accepted || []).length;
|
|
52
|
+
const deletedCount = (plan.deleted || []).length;
|
|
53
|
+
const skippedCount = (plan.skipped || []).length;
|
|
54
|
+
const conflictCount = (plan.conflicts || []).length;
|
|
55
|
+
if (isApply && appliedCount === 0 && skippedCount === 0 && conflictCount === 0 && plan.files.length === 0) {
|
|
56
|
+
console.log("No changes to apply.");
|
|
57
|
+
}
|
|
58
|
+
if (isStatus && plan.files.length === 0 && conflictCount === 0 && skippedCount === 0 && (plan.diagnostics || []).length === 0) {
|
|
59
|
+
console.log("No template update action needed.");
|
|
60
|
+
}
|
|
61
|
+
if (isApply && appliedCount > 0) {
|
|
62
|
+
console.log(`Applied ${appliedCount} file(s).`);
|
|
63
|
+
}
|
|
64
|
+
if (isFileAction && appliedCount > 0) {
|
|
65
|
+
console.log(`Accepted candidate for ${appliedCount} file(s).`);
|
|
66
|
+
}
|
|
67
|
+
if (acceptedCount > 0) {
|
|
68
|
+
console.log(`Accepted current baseline for ${acceptedCount} file(s).`);
|
|
69
|
+
}
|
|
70
|
+
if (deletedCount > 0) {
|
|
71
|
+
console.log(`Deleted ${deletedCount} current-only file(s).`);
|
|
72
|
+
}
|
|
73
|
+
if (skippedCount > 0) {
|
|
74
|
+
console.log(`Skipped ${skippedCount} current-only file(s).`);
|
|
75
|
+
}
|
|
76
|
+
if (conflictCount > 0) {
|
|
77
|
+
console.log(`Refused due to ${conflictCount} conflict(s).`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const diagnostics = Array.isArray(plan.diagnostics) ? plan.diagnostics : [];
|
|
81
|
+
for (const diagnostic of diagnostics) {
|
|
82
|
+
console.log(`[${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`);
|
|
83
|
+
if (diagnostic.path) {
|
|
84
|
+
console.log(` path: ${diagnostic.path}`);
|
|
85
|
+
}
|
|
86
|
+
if (diagnostic.suggestedFix) {
|
|
87
|
+
console.log(` fix: ${diagnostic.suggestedFix}`);
|
|
88
|
+
}
|
|
89
|
+
if (diagnostic.step) {
|
|
90
|
+
console.log(` step: ${diagnostic.step}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
for (const conflict of plan.conflicts || []) {
|
|
94
|
+
console.log(`Conflict: ${conflict.path}`);
|
|
95
|
+
console.log(` reason: ${conflict.reason}`);
|
|
96
|
+
}
|
|
97
|
+
for (const applied of plan.applied || []) {
|
|
98
|
+
console.log(`Applied: ${applied.path}`);
|
|
99
|
+
}
|
|
100
|
+
for (const skipped of plan.skipped || []) {
|
|
101
|
+
console.log(`Skipped: ${skipped.path}`);
|
|
102
|
+
console.log(` reason: ${skipped.reason}`);
|
|
103
|
+
}
|
|
104
|
+
for (const accepted of plan.accepted || []) {
|
|
105
|
+
console.log(`Accepted current: ${accepted.path}`);
|
|
106
|
+
}
|
|
107
|
+
for (const deleted of plan.deleted || []) {
|
|
108
|
+
console.log(`Deleted: ${deleted.path}`);
|
|
109
|
+
}
|
|
110
|
+
for (const file of plan.files) {
|
|
111
|
+
console.log("");
|
|
112
|
+
console.log(`${file.kind.toUpperCase()}: ${file.path}`);
|
|
113
|
+
if (file.current) {
|
|
114
|
+
console.log(` current sha256: ${file.current.sha256}`);
|
|
115
|
+
console.log(` current size: ${file.current.size}`);
|
|
116
|
+
}
|
|
117
|
+
if (file.candidate) {
|
|
118
|
+
console.log(` candidate sha256: ${file.candidate.sha256}`);
|
|
119
|
+
console.log(` candidate size: ${file.candidate.size}`);
|
|
120
|
+
}
|
|
121
|
+
if (file.binary) {
|
|
122
|
+
console.log(" diff: binary file");
|
|
123
|
+
} else if (file.diffOmitted && !file.unifiedDiff) {
|
|
124
|
+
console.log(" diff: hash-only");
|
|
125
|
+
}
|
|
126
|
+
if (file.unifiedDiff) {
|
|
127
|
+
console.log(file.unifiedDiff.trimEnd());
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (plan.files.length === 0) {
|
|
131
|
+
console.log("No template-owned file changes found.");
|
|
132
|
+
}
|
|
133
|
+
if (!isApply && !isCheck && !isStatus && !isFileAction) {
|
|
134
|
+
console.log("");
|
|
135
|
+
console.log("This command did not write files. Review the plan before applying template updates.");
|
|
136
|
+
} else if (isCheck || isStatus) {
|
|
137
|
+
console.log("");
|
|
138
|
+
console.log("This command did not write files.");
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* @param {any} status
|
|
144
|
+
* @returns {any}
|
|
145
|
+
*/
|
|
146
|
+
export function buildTemplateUpdateRecommendationPayload(status) {
|
|
147
|
+
/** @type {Array<{ action: string, command: string|null, reason: string, path: string|null }>} */
|
|
148
|
+
const recommendations = [];
|
|
149
|
+
/** @type {any[]} */
|
|
150
|
+
const diagnostics = Array.isArray(status.diagnostics)
|
|
151
|
+
? status.diagnostics.map((/** @type {any} */ diagnostic) => diagnostic.code === "template_update_available"
|
|
152
|
+
? { ...diagnostic, severity: "warning" }
|
|
153
|
+
: diagnostic)
|
|
154
|
+
: [];
|
|
155
|
+
const errorDiagnostics = diagnostics.filter((/** @type {any} */ diagnostic) => diagnostic.severity === "error");
|
|
156
|
+
const conflicts = Array.isArray(status.conflicts) ? status.conflicts : [];
|
|
157
|
+
const skipped = Array.isArray(status.skipped) ? status.skipped : [];
|
|
158
|
+
const files = Array.isArray(status.files) ? status.files : [];
|
|
159
|
+
const addedChanged = files.filter((/** @type {any} */ file) => file.kind === "added" || file.kind === "changed");
|
|
160
|
+
|
|
161
|
+
if (errorDiagnostics.length > 0) {
|
|
162
|
+
recommendations.push({
|
|
163
|
+
action: "resolve-errors",
|
|
164
|
+
command: "topogram template update --status",
|
|
165
|
+
reason: "Template policy, compatibility, baseline, or conflict errors must be resolved before applying candidate files.",
|
|
166
|
+
path: null
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
for (const conflict of conflicts) {
|
|
170
|
+
recommendations.push({
|
|
171
|
+
action: "review-conflict",
|
|
172
|
+
command: `topogram template update --accept-current ${conflict.path}`,
|
|
173
|
+
reason: "Local edits differ from the last trusted template-owned baseline. Accept current after review, or apply the candidate manually.",
|
|
174
|
+
path: conflict.path
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
if (addedChanged.length > 0 && conflicts.length === 0 && errorDiagnostics.length === 0) {
|
|
178
|
+
recommendations.push({
|
|
179
|
+
action: "apply-candidate",
|
|
180
|
+
command: "topogram template update --apply",
|
|
181
|
+
reason: `${addedChanged.length} added or changed candidate file(s) can be applied without local conflicts.`,
|
|
182
|
+
path: null
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
for (const item of skipped) {
|
|
186
|
+
recommendations.push({
|
|
187
|
+
action: "review-delete",
|
|
188
|
+
command: `topogram template update --delete-current ${item.path}`,
|
|
189
|
+
reason: "The candidate no longer owns this current file. Delete it only after review.",
|
|
190
|
+
path: item.path
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
if (files.length === 0 && errorDiagnostics.length === 0) {
|
|
194
|
+
recommendations.push({
|
|
195
|
+
action: "none",
|
|
196
|
+
command: null,
|
|
197
|
+
reason: "Current project files already match the candidate template.",
|
|
198
|
+
path: null
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
if (status.candidate?.id && status.candidate?.version && errorDiagnostics.length === 0) {
|
|
202
|
+
recommendations.push({
|
|
203
|
+
action: "pin-reviewed-version",
|
|
204
|
+
command: `topogram template policy pin ${status.candidate.id}@${status.candidate.version}`,
|
|
205
|
+
reason: "After reviewing or applying this candidate, pin the template version in project policy.",
|
|
206
|
+
path: null
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
...status,
|
|
211
|
+
ok: errorDiagnostics.length === 0,
|
|
212
|
+
mode: "recommend",
|
|
213
|
+
writes: false,
|
|
214
|
+
issues: errorDiagnostics.map((/** @type {any} */ diagnostic) => diagnostic.message),
|
|
215
|
+
diagnostics,
|
|
216
|
+
recommendations
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* @param {ReturnType<typeof buildTemplateUpdateRecommendationPayload>} payload
|
|
222
|
+
* @returns {void}
|
|
223
|
+
*/
|
|
224
|
+
export function printTemplateUpdateRecommendation(payload) {
|
|
225
|
+
console.log(payload.ok ? "Template update recommendation: ready" : "Template update recommendation: blocked");
|
|
226
|
+
console.log(`Current: ${payload.current?.id || "unknown"}@${payload.current?.version || "unknown"}`);
|
|
227
|
+
console.log(`Candidate: ${payload.candidate?.id || "unknown"}@${payload.candidate?.version || "unknown"}`);
|
|
228
|
+
console.log(`Added: ${payload.summary.added}`);
|
|
229
|
+
console.log(`Changed: ${payload.summary.changed}`);
|
|
230
|
+
console.log(`Current-only: ${payload.summary.currentOnly}`);
|
|
231
|
+
console.log(`Conflicts: ${payload.conflicts.length}`);
|
|
232
|
+
if (payload.reportPath) {
|
|
233
|
+
console.log(`Report: ${payload.reportPath}`);
|
|
234
|
+
}
|
|
235
|
+
for (const diagnostic of payload.diagnostics || []) {
|
|
236
|
+
console.log(`[${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`);
|
|
237
|
+
if (diagnostic.path) {
|
|
238
|
+
console.log(` path: ${diagnostic.path}`);
|
|
239
|
+
}
|
|
240
|
+
if (diagnostic.suggestedFix) {
|
|
241
|
+
console.log(` fix: ${diagnostic.suggestedFix}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
console.log("");
|
|
245
|
+
console.log("Recommended next steps:");
|
|
246
|
+
for (const recommendation of payload.recommendations) {
|
|
247
|
+
console.log(`- ${recommendation.reason}`);
|
|
248
|
+
if (recommendation.command) {
|
|
249
|
+
console.log(` ${recommendation.command}`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* @param {{ args: string[], inputPath: string, templateIndex: number, templateName: string|null|undefined, useLatestTemplate: boolean, outPath?: string|null }} options
|
|
256
|
+
* @returns {any}
|
|
257
|
+
*/
|
|
258
|
+
export function buildTemplateUpdateCliPayload(options) {
|
|
259
|
+
const { args, inputPath, templateIndex, templateName, useLatestTemplate, outPath = null } = options;
|
|
260
|
+
const applyUpdate = args.includes("--apply");
|
|
261
|
+
const checkUpdate = args.includes("--check");
|
|
262
|
+
const planUpdate = args.includes("--plan");
|
|
263
|
+
const statusUpdate = args.includes("--status");
|
|
264
|
+
const recommendUpdate = args.includes("--recommend");
|
|
265
|
+
const acceptCurrentIndex = args.indexOf("--accept-current");
|
|
266
|
+
const acceptCandidateIndex = args.indexOf("--accept-candidate");
|
|
267
|
+
const deleteCurrentIndex = args.indexOf("--delete-current");
|
|
268
|
+
const acceptCurrentUpdate = acceptCurrentIndex >= 0;
|
|
269
|
+
const acceptCandidateUpdate = acceptCandidateIndex >= 0;
|
|
270
|
+
const deleteCurrentUpdate = deleteCurrentIndex >= 0;
|
|
271
|
+
const fileAction = acceptCurrentUpdate ? "accept-current" : acceptCandidateUpdate ? "accept-candidate" : deleteCurrentUpdate ? "delete-current" : null;
|
|
272
|
+
const fileActionIndex = acceptCurrentUpdate ? acceptCurrentIndex : acceptCandidateUpdate ? acceptCandidateIndex : deleteCurrentUpdate ? deleteCurrentIndex : -1;
|
|
273
|
+
const fileActionPath = fileActionIndex >= 0 ? args[fileActionIndex + 1] : null;
|
|
274
|
+
const updateModeCount = [applyUpdate, checkUpdate, planUpdate, statusUpdate, recommendUpdate, acceptCurrentUpdate, acceptCandidateUpdate, deleteCurrentUpdate].filter(Boolean).length;
|
|
275
|
+
if (updateModeCount > 1) {
|
|
276
|
+
throw new Error("Choose one template update mode or file adoption action.");
|
|
277
|
+
}
|
|
278
|
+
if (updateModeCount === 0) {
|
|
279
|
+
throw new Error("Template update requires `--status`, `--recommend`, `--plan`, `--check`, `--apply`, `--accept-current <file>`, `--accept-candidate <file>`, or `--delete-current <file>`.");
|
|
280
|
+
}
|
|
281
|
+
if (fileAction && (!fileActionPath || fileActionPath.startsWith("-"))) {
|
|
282
|
+
throw new Error(`Template update ${fileAction} requires a relative file path.`);
|
|
283
|
+
}
|
|
284
|
+
const projectConfigInfo = loadProjectConfig(inputPath);
|
|
285
|
+
if (!projectConfigInfo) {
|
|
286
|
+
throw new Error("Cannot update template without topogram.project.json.");
|
|
287
|
+
}
|
|
288
|
+
if (!projectConfigInfo.config.template?.id && !projectConfigInfo.config.template?.sourceSpec) {
|
|
289
|
+
throw new Error("Cannot update template because this project is detached from template metadata.");
|
|
290
|
+
}
|
|
291
|
+
const requestedTemplateName = templateIndex >= 0
|
|
292
|
+
? templateName
|
|
293
|
+
: useLatestTemplate
|
|
294
|
+
? latestTemplateInfo(templateMetadataFromProjectConfig(projectConfigInfo.config)).candidateSpec
|
|
295
|
+
: null;
|
|
296
|
+
if (useLatestTemplate && !requestedTemplateName) {
|
|
297
|
+
throw new Error("Cannot use --latest because the current template is not package-backed.");
|
|
298
|
+
}
|
|
299
|
+
let update;
|
|
300
|
+
try {
|
|
301
|
+
const updateOptions = {
|
|
302
|
+
projectRoot: projectConfigInfo.configDir,
|
|
303
|
+
projectConfig: projectConfigInfo.config,
|
|
304
|
+
templateName: requestedTemplateName,
|
|
305
|
+
templatesRoot: TEMPLATES_ROOT
|
|
306
|
+
};
|
|
307
|
+
update = fileAction
|
|
308
|
+
? applyTemplateUpdateFileAction({ ...updateOptions, action: fileAction, filePath: fileActionPath || "" })
|
|
309
|
+
: recommendUpdate
|
|
310
|
+
? buildTemplateUpdateRecommendationPayload(buildTemplateUpdateStatus(updateOptions))
|
|
311
|
+
: (applyUpdate ? applyTemplateUpdate : checkUpdate ? buildTemplateUpdateCheck : statusUpdate ? buildTemplateUpdateStatus : buildTemplateUpdatePlan)(updateOptions);
|
|
312
|
+
} catch (error) {
|
|
313
|
+
const message = messageFromError(error);
|
|
314
|
+
update = {
|
|
315
|
+
ok: false,
|
|
316
|
+
mode: fileAction || (applyUpdate ? "apply" : checkUpdate ? "check" : statusUpdate ? "status" : recommendUpdate ? "recommend" : "plan"),
|
|
317
|
+
writes: false,
|
|
318
|
+
current: {
|
|
319
|
+
id: typeof projectConfigInfo.config.template?.id === "string" ? projectConfigInfo.config.template.id : null,
|
|
320
|
+
version: typeof projectConfigInfo.config.template?.version === "string" ? projectConfigInfo.config.template.version : null
|
|
321
|
+
},
|
|
322
|
+
candidate: null,
|
|
323
|
+
compatible: false,
|
|
324
|
+
issues: [message],
|
|
325
|
+
diagnostics: [templateCheckDiagnostic({
|
|
326
|
+
code: "template_resolve_failed",
|
|
327
|
+
message,
|
|
328
|
+
path: templateIndex >= 0 && typeof templateName === "string" && path.isAbsolute(templateName) ? templateName : null,
|
|
329
|
+
suggestedFix: "Check the template path or package spec, and verify private registry authentication if this is a package template.",
|
|
330
|
+
step: "resolve-candidate"
|
|
331
|
+
})],
|
|
332
|
+
summary: { added: 0, changed: 0, currentOnly: 0, unchanged: 0 },
|
|
333
|
+
files: [],
|
|
334
|
+
applied: [],
|
|
335
|
+
skipped: [],
|
|
336
|
+
conflicts: [],
|
|
337
|
+
recommendations: recommendUpdate ? [{
|
|
338
|
+
action: "resolve-errors",
|
|
339
|
+
command: "topogram template update --status",
|
|
340
|
+
reason: "Resolve the candidate template before choosing an update action.",
|
|
341
|
+
path: null
|
|
342
|
+
}] : undefined
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
if (outPath) {
|
|
346
|
+
const reportPath = path.resolve(outPath);
|
|
347
|
+
fs.mkdirSync(path.dirname(reportPath), { recursive: true });
|
|
348
|
+
fs.writeFileSync(reportPath, `${stableStringify(update)}\n`, "utf8");
|
|
349
|
+
update.reportPath = reportPath;
|
|
350
|
+
}
|
|
351
|
+
return update;
|
|
352
|
+
}
|
|
@@ -77,7 +77,7 @@ export function runTemplateCommand(context) {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
if (command === "status") {
|
|
80
|
-
const projectConfigInfo = loadProjectConfig(inputPath || "./
|
|
80
|
+
const projectConfigInfo = loadProjectConfig(inputPath || "./topo");
|
|
81
81
|
if (!projectConfigInfo) {
|
|
82
82
|
throw new Error("Cannot inspect template status without topogram.project.json.");
|
|
83
83
|
}
|
|
@@ -108,7 +108,7 @@ export function runTemplateCommand(context) {
|
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
if (command === "policy:init") {
|
|
111
|
-
const projectConfigInfo = loadProjectConfig(inputPath || "./
|
|
111
|
+
const projectConfigInfo = loadProjectConfig(inputPath || "./topo");
|
|
112
112
|
if (!projectConfigInfo) {
|
|
113
113
|
throw new Error("Cannot initialize template policy without topogram.project.json.");
|
|
114
114
|
}
|
|
@@ -131,7 +131,7 @@ export function runTemplateCommand(context) {
|
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
if (command === "policy:check") {
|
|
134
|
-
const payload = buildTemplatePolicyCheckPayload(inputPath || "./
|
|
134
|
+
const payload = buildTemplatePolicyCheckPayload(inputPath || "./topo");
|
|
135
135
|
if (json) {
|
|
136
136
|
console.log(stableStringify(payload));
|
|
137
137
|
} else {
|
|
@@ -141,7 +141,7 @@ export function runTemplateCommand(context) {
|
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
if (command === "policy:explain") {
|
|
144
|
-
const payload = buildTemplatePolicyExplainPayload(inputPath || "./
|
|
144
|
+
const payload = buildTemplatePolicyExplainPayload(inputPath || "./topo");
|
|
145
145
|
if (json) {
|
|
146
146
|
console.log(stableStringify(payload));
|
|
147
147
|
} else {
|
|
@@ -151,7 +151,7 @@ export function runTemplateCommand(context) {
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
if (command === "policy:pin") {
|
|
154
|
-
const payload = buildTemplatePolicyPinPayload(inputPath || "./
|
|
154
|
+
const payload = buildTemplatePolicyPinPayload(inputPath || "./topo", commandArgs.templatePolicyPinSpec);
|
|
155
155
|
if (json) {
|
|
156
156
|
console.log(stableStringify(payload));
|
|
157
157
|
} else {
|
|
@@ -178,7 +178,7 @@ export function runTemplateCommand(context) {
|
|
|
178
178
|
if (command === "update") {
|
|
179
179
|
const payload = buildTemplateUpdateCliPayload({
|
|
180
180
|
args,
|
|
181
|
-
inputPath: inputPath || "./
|
|
181
|
+
inputPath: inputPath || "./topo",
|
|
182
182
|
templateIndex: args.indexOf("--template"),
|
|
183
183
|
templateName,
|
|
184
184
|
useLatestTemplate: args.includes("--latest"),
|