@topogram/cli 0.3.63 → 0.3.65
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 +703 -0
- package/src/adoption/plan.d.ts +6 -0
- package/src/adoption/plan.js +12 -703
- package/src/adoption/reporting.d.ts +10 -0
- package/src/adoption/review-groups.d.ts +6 -0
- package/src/agent-brief.d.ts +3 -0
- package/src/agent-brief.js +495 -0
- 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 +676 -0
- package/src/agent-ops/query-builders/workflow-presets.js +341 -0
- package/src/agent-ops/query-builders.d.ts +26 -0
- package/src/agent-ops/query-builders.js +42 -5021
- package/src/archive/archive.d.ts +2 -0
- package/src/archive/compact.d.ts +1 -0
- package/src/archive/unarchive.d.ts +1 -0
- package/src/catalog/constants.js +10 -0
- package/src/catalog/copy.js +60 -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 +122 -0
- package/src/catalog/source.js +150 -0
- package/src/catalog/validation.js +252 -0
- package/src/catalog.d.ts +12 -0
- package/src/catalog.js +18 -750
- package/src/cli/catalog-alias.d.ts +1 -0
- package/src/cli/command-parser.js +38 -0
- package/src/cli/command-parsers/core.js +102 -0
- package/src/cli/command-parsers/generator.js +39 -0
- package/src/cli/command-parsers/import.js +44 -0
- package/src/cli/command-parsers/legacy-workflow.js +21 -0
- package/src/cli/command-parsers/project.js +47 -0
- package/src/cli/command-parsers/sdlc.js +47 -0
- package/src/cli/command-parsers/shared.js +51 -0
- package/src/cli/command-parsers/template.js +48 -0
- package/src/cli/commands/agent.js +47 -0
- 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 +32 -0
- package/src/cli/commands/check.js +268 -0
- package/src/cli/commands/doctor.js +268 -0
- package/src/cli/commands/emit.js +149 -0
- package/src/cli/commands/generate.js +96 -0
- 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 +17 -0
- package/src/cli/commands/generator.js +443 -0
- 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 +277 -0
- package/src/cli/commands/import/plan.js +284 -0
- package/src/cli/commands/import/refresh.js +470 -0
- package/src/cli/commands/import/status-history.js +196 -0
- package/src/cli/commands/import/workspace.js +230 -0
- package/src/cli/commands/import-runner.js +157 -0
- package/src/cli/commands/import.js +35 -0
- package/src/cli/commands/inspect.js +55 -0
- package/src/cli/commands/new.js +94 -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 +31 -0
- 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 +274 -0
- package/src/cli/commands/query.js +11 -0
- package/src/cli/commands/release-rollout.js +257 -0
- package/src/cli/commands/release-shared.js +528 -0
- package/src/cli/commands/release-status.js +429 -0
- package/src/cli/commands/release.js +107 -0
- package/src/cli/commands/sdlc.js +168 -0
- package/src/cli/commands/setup.js +76 -0
- package/src/cli/commands/source.js +291 -0
- package/src/cli/commands/template/baseline.js +100 -0
- package/src/cli/commands/template/check.js +466 -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 +198 -0
- package/src/cli/commands/template.js +43 -0
- package/src/cli/commands/trust.js +219 -0
- package/src/cli/commands/version.js +40 -0
- package/src/cli/commands/widget.js +168 -0
- package/src/cli/commands/workflow.js +63 -0
- package/src/cli/dispatcher.js +392 -0
- package/src/cli/help-dispatch.js +188 -0
- package/src/cli/help.js +296 -0
- package/src/cli/migration-guidance.js +59 -0
- package/src/cli/options.js +96 -0
- package/src/cli/output-safety.js +107 -0
- package/src/cli/path-normalization.js +29 -0
- package/src/cli.js +47 -11711
- package/src/example-implementation.d.ts +2 -0
- package/src/format.d.ts +1 -0
- 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/check.d.ts +1 -0
- package/src/generator/context/bundle.d.ts +1 -0
- 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 +44 -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/native/parity-bundle.js +2 -1
- 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/shared.d.ts +2 -0
- package/src/generator/surfaces/shared.d.ts +3 -0
- package/src/generator/surfaces/web/html-escape.js +22 -0
- package/src/generator/surfaces/web/react.js +10 -8
- package/src/generator/surfaces/web/sveltekit.js +7 -5
- package/src/generator/surfaces/web/vanilla.js +8 -4
- 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/generator.d.ts +2 -0
- package/src/github-client.js +520 -0
- package/src/import/core/context.d.ts +3 -0
- 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 +217 -0
- package/src/import/core/runner/options.js +22 -0
- package/src/import/core/runner/reports.js +50 -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 +337 -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 +67 -910
- package/src/import/extractors/api/flutter-dio.js +4 -8
- package/src/import/extractors/api/react-native-repository.js +4 -8
- package/src/import/index.d.ts +4 -0
- package/src/import/provenance.d.ts +4 -0
- package/src/new-project/constants.js +128 -0
- package/src/new-project/create.js +83 -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 +348 -0
- package/src/new-project/template-policy.js +269 -0
- package/src/new-project/template-resolution.js +368 -0
- package/src/new-project/template-snapshots.js +430 -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 -2188
- package/src/npm-safety.js +79 -0
- package/src/parser.d.ts +87 -0
- package/src/parser.js +118 -0
- package/src/path-helpers.d.ts +1 -0
- package/src/path-helpers.js +20 -0
- package/src/policy/review-boundaries.d.ts +15 -0
- package/src/project-config/index.js +564 -0
- package/src/project-config.js +19 -560
- package/src/reconcile/docs.d.ts +8 -0
- package/src/reconcile/journeys.d.ts +1 -0
- 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/resolver.d.ts +1 -0
- package/src/runtime-support.js +29 -0
- package/src/sdlc/adopt.d.ts +1 -0
- package/src/sdlc/check.d.ts +1 -0
- package/src/sdlc/explain.d.ts +1 -0
- package/src/sdlc/release.d.ts +1 -0
- package/src/sdlc/scaffold.d.ts +1 -0
- package/src/sdlc/transition.d.ts +1 -0
- 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 +7 -0
- package/src/text-helpers.js +245 -0
- package/src/topogram-config.js +306 -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/validator.d.ts +2 -0
- package/src/widget-behavior.d.ts +1 -0
- package/src/workflows/adoption/index.js +26 -0
- package/src/workflows/docs-generate.js +262 -0
- package/src/workflows/docs-scan.js +703 -0
- package/src/workflows/docs.js +15 -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 +4 -0
- package/src/workflows/import-app/db.js +538 -0
- package/src/workflows/import-app/index.js +30 -0
- package/src/workflows/import-app/shared.js +218 -0
- package/src/workflows/import-app/ui.js +443 -0
- package/src/workflows/import-app/workflow.js +159 -0
- package/src/workflows/reconcile/adoption-plan/build.js +208 -0
- package/src/workflows/reconcile/adoption-plan/dependencies.js +75 -0
- package/src/workflows/reconcile/adoption-plan/outputs.js +143 -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 +32 -0
- 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 +37 -0
- package/src/workflows/reconcile/bundle-core/index.js +600 -0
- package/src/workflows/reconcile/bundle-core.js +14 -0
- package/src/workflows/reconcile/bundle-shared.js +75 -0
- package/src/workflows/reconcile/candidate-model.js +477 -0
- package/src/workflows/reconcile/canonical-surface.js +264 -0
- package/src/workflows/reconcile/gap-report.js +333 -0
- package/src/workflows/reconcile/ids.js +6 -0
- package/src/workflows/reconcile/impacts/adoption-plan.js +192 -0
- package/src/workflows/reconcile/impacts/indexes.js +101 -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 +16 -0
- package/src/workflows/reconcile/index.js +7 -0
- package/src/workflows/reconcile/renderers.js +461 -0
- package/src/workflows/reconcile/summary.js +90 -0
- package/src/workflows/reconcile/workflow.js +309 -0
- package/src/workflows/shared.js +189 -0
- package/src/workflows/types.d.ts +93 -0
- package/src/workflows.d.ts +1 -0
- package/src/workflows.js +10 -7652
- package/src/workspace-docs.d.ts +29 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { parsePath } from "../../../parser.js";
|
|
4
|
+
import {
|
|
5
|
+
loadProjectConfig,
|
|
6
|
+
validateProjectConfig,
|
|
7
|
+
validateProjectOutputOwnership
|
|
8
|
+
} from "../../../project-config.js";
|
|
9
|
+
import { resolveWorkspace } from "../../../resolver.js";
|
|
10
|
+
import { validateProjectImplementationTrust } from "../../../template-trust.js";
|
|
11
|
+
import { buildTopogramImportStatus } from "../../../import/provenance.js";
|
|
12
|
+
import {
|
|
13
|
+
checkSummaryPayload,
|
|
14
|
+
combineProjectValidationResults,
|
|
15
|
+
normalizeProjectRoot
|
|
16
|
+
} from "./paths.js";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @typedef {Record<string, any>} AnyRecord
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param {string} inputPath
|
|
24
|
+
* @returns {ReturnType<typeof checkSummaryPayload>}
|
|
25
|
+
*/
|
|
26
|
+
export function buildTopogramCheckPayloadForPath(inputPath) {
|
|
27
|
+
const ast = parsePath(inputPath);
|
|
28
|
+
const resolved = resolveWorkspace(ast);
|
|
29
|
+
const explicitProjectConfig = loadProjectConfig(inputPath);
|
|
30
|
+
const projectValidation = explicitProjectConfig
|
|
31
|
+
? combineProjectValidationResults(
|
|
32
|
+
validateProjectConfig(explicitProjectConfig.config, resolved.ok ? resolved.graph : null, { configDir: explicitProjectConfig.configDir }),
|
|
33
|
+
validateProjectOutputOwnership(explicitProjectConfig),
|
|
34
|
+
validateProjectImplementationTrust(explicitProjectConfig)
|
|
35
|
+
)
|
|
36
|
+
: { ok: false, errors: [{ message: "Missing topogram.project.json or compatible topogram.implementation.json", loc: null }] };
|
|
37
|
+
return checkSummaryPayload({ inputPath, ast, resolved, projectConfigInfo: explicitProjectConfig, projectValidation });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @param {string} projectRoot
|
|
42
|
+
* @returns {{ ok: boolean, projectRoot: string, import: ReturnType<typeof buildTopogramImportStatus>, topogram: ReturnType<typeof buildTopogramCheckPayloadForPath>, errors: any[] }}
|
|
43
|
+
*/
|
|
44
|
+
export function buildBrownfieldImportCheckPayload(projectRoot) {
|
|
45
|
+
const resolvedRoot = normalizeProjectRoot(projectRoot);
|
|
46
|
+
const importStatus = buildTopogramImportStatus(resolvedRoot);
|
|
47
|
+
const topogramCheck = buildTopogramCheckPayloadForPath(resolvedRoot);
|
|
48
|
+
return {
|
|
49
|
+
ok: importStatus.ok && topogramCheck.ok,
|
|
50
|
+
projectRoot: resolvedRoot,
|
|
51
|
+
import: importStatus,
|
|
52
|
+
topogram: topogramCheck,
|
|
53
|
+
errors: [
|
|
54
|
+
...(importStatus.errors || []).map((/** @type {string} */ message) => ({ source: "import", message })),
|
|
55
|
+
...(topogramCheck.errors || [])
|
|
56
|
+
]
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @param {ReturnType<typeof buildBrownfieldImportCheckPayload>} payload
|
|
62
|
+
* @returns {void}
|
|
63
|
+
*/
|
|
64
|
+
export function printBrownfieldImportCheck(payload) {
|
|
65
|
+
console.log(`Topogram import check: ${payload.import.status}`);
|
|
66
|
+
console.log(`Project: ${payload.projectRoot}`);
|
|
67
|
+
if (payload.import.source?.source?.path) {
|
|
68
|
+
console.log(`Imported source: ${payload.import.source.source.path}`);
|
|
69
|
+
}
|
|
70
|
+
console.log(`Provenance: ${payload.import.path}`);
|
|
71
|
+
if (payload.import.source?.files) {
|
|
72
|
+
console.log(`Trusted source files: ${payload.import.source.files.length}`);
|
|
73
|
+
}
|
|
74
|
+
if (payload.import.status === "changed") {
|
|
75
|
+
console.log(`Changed source files: ${payload.import.content.changed.length}`);
|
|
76
|
+
console.log(`Added source files: ${payload.import.content.added.length}`);
|
|
77
|
+
console.log(`Removed source files: ${payload.import.content.removed.length}`);
|
|
78
|
+
}
|
|
79
|
+
console.log(`Topogram check: ${payload.topogram.ok ? "passed" : "failed"}`);
|
|
80
|
+
console.log("Imported Topogram artifacts are project-owned; import check compares only the brownfield source hashes trusted at import time plus normal Topogram validity.");
|
|
81
|
+
for (const diagnostic of payload.import.diagnostics || []) {
|
|
82
|
+
const label = diagnostic.severity === "warning" ? "Warning" : "Error";
|
|
83
|
+
console.log(`${label}: ${diagnostic.message}`);
|
|
84
|
+
if (diagnostic.suggestedFix) {
|
|
85
|
+
console.log(`Fix: ${diagnostic.suggestedFix}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
for (const error of payload.topogram.errors || []) {
|
|
89
|
+
console.log(`Error: ${error.message}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { importProjectCommandPath } from "./paths.js";
|
|
4
|
+
import { buildBrownfieldImportRefreshAnalysis } from "./refresh.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {Record<string, any>} AnyRecord
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {string} inputPath
|
|
12
|
+
* @param {{ sourcePath?: string|null }} [options]
|
|
13
|
+
* @returns {AnyRecord}
|
|
14
|
+
*/
|
|
15
|
+
export function buildBrownfieldImportDiffPayload(inputPath, options = {}) {
|
|
16
|
+
const analysis = buildBrownfieldImportRefreshAnalysis(inputPath, options);
|
|
17
|
+
return {
|
|
18
|
+
ok: true,
|
|
19
|
+
projectRoot: analysis.projectRoot,
|
|
20
|
+
topogramRoot: analysis.topogramRoot,
|
|
21
|
+
sourcePath: analysis.sourcePath,
|
|
22
|
+
provenancePath: analysis.provenancePath,
|
|
23
|
+
importStatus: analysis.previousImportStatus,
|
|
24
|
+
sourceDiff: analysis.sourceDiff,
|
|
25
|
+
tracks: analysis.tracks,
|
|
26
|
+
sourceFiles: analysis.sourceFiles,
|
|
27
|
+
candidateCounts: analysis.candidateCounts,
|
|
28
|
+
candidateCountDeltas: analysis.candidateCountDeltas,
|
|
29
|
+
adoptionPlanDeltas: analysis.adoptionPlanDeltas,
|
|
30
|
+
receiptVerification: analysis.receiptVerification,
|
|
31
|
+
plannedFiles: analysis.plannedFiles,
|
|
32
|
+
nextCommands: [
|
|
33
|
+
`topogram import refresh ${importProjectCommandPath(analysis.projectRoot)} --dry-run`,
|
|
34
|
+
`topogram import refresh ${importProjectCommandPath(analysis.projectRoot)}`,
|
|
35
|
+
`topogram import plan ${importProjectCommandPath(analysis.projectRoot)}`
|
|
36
|
+
]
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @param {ReturnType<typeof buildBrownfieldImportDiffPayload>} payload
|
|
42
|
+
* @returns {void}
|
|
43
|
+
*/
|
|
44
|
+
export function printBrownfieldImportDiff(payload) {
|
|
45
|
+
console.log(`Import diff for ${payload.projectRoot}`);
|
|
46
|
+
console.log(`Source: ${payload.sourcePath}`);
|
|
47
|
+
console.log(`Source status: ${payload.importStatus}`);
|
|
48
|
+
console.log(`Source diff: changed=${payload.sourceDiff.counts.changed}, added=${payload.sourceDiff.counts.added}, removed=${payload.sourceDiff.counts.removed}`);
|
|
49
|
+
for (const filePath of [...payload.sourceDiff.changed, ...payload.sourceDiff.added, ...payload.sourceDiff.removed].slice(0, 12)) {
|
|
50
|
+
const status = payload.sourceDiff.changed.includes(filePath)
|
|
51
|
+
? "changed"
|
|
52
|
+
: payload.sourceDiff.added.includes(filePath)
|
|
53
|
+
? "added"
|
|
54
|
+
: "removed";
|
|
55
|
+
console.log(`- ${filePath}: ${status}`);
|
|
56
|
+
}
|
|
57
|
+
console.log("");
|
|
58
|
+
console.log("Candidate count changes:");
|
|
59
|
+
const candidateChanges = payload.candidateCountDeltas.changed || [];
|
|
60
|
+
if (candidateChanges.length === 0) {
|
|
61
|
+
console.log("- None");
|
|
62
|
+
} else {
|
|
63
|
+
for (const item of candidateChanges) {
|
|
64
|
+
const sign = item.delta > 0 ? "+" : "";
|
|
65
|
+
console.log(`- ${item.key}: ${item.previous} -> ${item.next} (${sign}${item.delta})`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
console.log("");
|
|
69
|
+
console.log(`Adoption plan changes: added=${payload.adoptionPlanDeltas.added.length}, removed=${payload.adoptionPlanDeltas.removed.length}, changed=${payload.adoptionPlanDeltas.changed.length}`);
|
|
70
|
+
for (const item of payload.adoptionPlanDeltas.added.slice(0, 8)) {
|
|
71
|
+
console.log(`- added ${item.bundle}/${item.kind}/${item.item}`);
|
|
72
|
+
}
|
|
73
|
+
for (const item of payload.adoptionPlanDeltas.removed.slice(0, 8)) {
|
|
74
|
+
console.log(`- removed ${item.bundle}/${item.kind}/${item.item}`);
|
|
75
|
+
}
|
|
76
|
+
console.log(`Receipt verification: ${payload.receiptVerification.status}`);
|
|
77
|
+
const receiptSummary = payload.receiptVerification.summary;
|
|
78
|
+
console.log(`Adopted file audit: changed=${receiptSummary.changedFileCount}, removed=${receiptSummary.removedFileCount}, unverifiable=${receiptSummary.unverifiableFileCount}`);
|
|
79
|
+
console.log("");
|
|
80
|
+
console.log("Next steps:");
|
|
81
|
+
for (const command of payload.nextCommands) {
|
|
82
|
+
console.log(` ${command}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { TOPOGRAM_IMPORT_FILE } from "../../../import/provenance.js";
|
|
4
|
+
import { TOPOGRAM_IMPORT_ADOPTIONS_FILE } from "./paths.js";
|
|
5
|
+
|
|
6
|
+
export function printImportHelp() {
|
|
7
|
+
console.log("Usage: topogram import <app-path> --out <target> [--from <track[,track]>] [--json]");
|
|
8
|
+
console.log(" or: topogram import refresh [path] [--from <app-path>] [--dry-run] [--json]");
|
|
9
|
+
console.log(" or: topogram import diff [path] [--json]");
|
|
10
|
+
console.log(" or: topogram import check [path] [--json]");
|
|
11
|
+
console.log(" or: topogram import plan [path] [--json]");
|
|
12
|
+
console.log(" or: topogram import adopt --list [path] [--json]");
|
|
13
|
+
console.log(" or: topogram import adopt <selector> [path] [--dry-run|--write] [--force --reason <text>] [--json]");
|
|
14
|
+
console.log(" or: topogram import status [path] [--json]");
|
|
15
|
+
console.log(" or: topogram import history [path] [--verify] [--json]");
|
|
16
|
+
console.log("");
|
|
17
|
+
console.log("Creates an editable Topogram workspace from a brownfield app without modifying the app.");
|
|
18
|
+
console.log("");
|
|
19
|
+
console.log("Behavior:");
|
|
20
|
+
console.log(" - writes raw import candidates under topogram/candidates/app");
|
|
21
|
+
console.log(" - writes reconcile proposal bundles under topogram/candidates/reconcile");
|
|
22
|
+
console.log(" - writes topogram.project.json with maintained ownership and no generated stack binding");
|
|
23
|
+
console.log(` - writes ${TOPOGRAM_IMPORT_FILE} with source file hashes from import time`);
|
|
24
|
+
console.log(" - imported Topogram artifacts are project-owned after creation");
|
|
25
|
+
console.log(" - refresh rewrites only candidate/reconcile artifacts and source provenance");
|
|
26
|
+
console.log(" - adoption previews never write canonical Topogram files unless --write is passed");
|
|
27
|
+
console.log(" - adoption writes refuse dirty brownfield source provenance unless --force is passed");
|
|
28
|
+
console.log(` - adoption writes append audit receipts to ${TOPOGRAM_IMPORT_ADOPTIONS_FILE}`);
|
|
29
|
+
console.log(" - forced adoption writes require --reason <text>");
|
|
30
|
+
console.log("");
|
|
31
|
+
console.log("Examples:");
|
|
32
|
+
console.log(" topogram import ./existing-app --out ./imported-topogram");
|
|
33
|
+
console.log(" topogram import ./existing-app --out ./imported-topogram --from db,api,ui");
|
|
34
|
+
console.log(" topogram import diff ./imported-topogram");
|
|
35
|
+
console.log(" topogram import refresh ./imported-topogram --from ./existing-app --dry-run");
|
|
36
|
+
console.log(" topogram import refresh ./imported-topogram --from ./existing-app");
|
|
37
|
+
console.log(" topogram import check ./imported-topogram");
|
|
38
|
+
console.log(" topogram import plan ./imported-topogram");
|
|
39
|
+
console.log(" topogram import adopt --list ./imported-topogram");
|
|
40
|
+
console.log(" topogram import adopt bundle:task ./imported-topogram --dry-run");
|
|
41
|
+
console.log(" topogram import adopt bundle:task ./imported-topogram --write");
|
|
42
|
+
console.log(" topogram import adopt bundle:task ./imported-topogram --write --force --reason \"Reviewed source drift\"");
|
|
43
|
+
console.log(" topogram import status ./imported-topogram");
|
|
44
|
+
console.log(" topogram import history ./imported-topogram");
|
|
45
|
+
console.log(" topogram import history ./imported-topogram --verify");
|
|
46
|
+
console.log(" topogram import check --json");
|
|
47
|
+
}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import crypto from "node:crypto";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
|
|
7
|
+
import { stableStringify } from "../../../format.js";
|
|
8
|
+
import { TOPOGRAM_IMPORT_FILE } from "../../../import/provenance.js";
|
|
9
|
+
import { shellCommandArg } from "../catalog.js";
|
|
10
|
+
|
|
11
|
+
export const TOPOGRAM_IMPORT_ADOPTIONS_FILE = ".topogram-import-adoptions.jsonl";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @typedef {Record<string, any>} AnyRecord
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {string} inputPath
|
|
19
|
+
* @returns {string}
|
|
20
|
+
*/
|
|
21
|
+
export function normalizeTopogramPath(inputPath) {
|
|
22
|
+
const absolute = path.resolve(inputPath);
|
|
23
|
+
if (path.basename(absolute) === "topogram") {
|
|
24
|
+
return absolute;
|
|
25
|
+
}
|
|
26
|
+
const candidate = path.join(absolute, "topogram");
|
|
27
|
+
return fs.existsSync(candidate) ? candidate : absolute;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @param {string} inputPath
|
|
32
|
+
* @returns {string}
|
|
33
|
+
*/
|
|
34
|
+
export function normalizeProjectRoot(inputPath) {
|
|
35
|
+
const absolute = path.resolve(inputPath);
|
|
36
|
+
if (path.basename(absolute) === "topogram") {
|
|
37
|
+
return path.dirname(absolute);
|
|
38
|
+
}
|
|
39
|
+
return absolute;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @param {...{ ok: boolean, errors?: any[] }|null|undefined} results
|
|
44
|
+
* @returns {{ ok: boolean, errors: any[] }}
|
|
45
|
+
*/
|
|
46
|
+
export function combineProjectValidationResults(...results) {
|
|
47
|
+
const errors = [];
|
|
48
|
+
for (const result of results) {
|
|
49
|
+
errors.push(...(result?.errors || []));
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
ok: errors.length === 0,
|
|
53
|
+
errors
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @param {AnyRecord} component
|
|
59
|
+
* @returns {{ uses_api: string|null, uses_database: string|null }}
|
|
60
|
+
*/
|
|
61
|
+
export function topologyComponentReferences(component) {
|
|
62
|
+
return {
|
|
63
|
+
uses_api: component.uses_api || null,
|
|
64
|
+
uses_database: component.uses_database || null
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @param {AnyRecord} component
|
|
70
|
+
* @returns {any}
|
|
71
|
+
*/
|
|
72
|
+
export function topologyComponentPort(component) {
|
|
73
|
+
return Object.prototype.hasOwnProperty.call(component, "port") ? component.port : null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @param {AnyRecord|null|undefined} config
|
|
78
|
+
* @returns {{ outputs: any[], runtimes: any[], edges: any[] }}
|
|
79
|
+
*/
|
|
80
|
+
export function summarizeProjectTopology(config) {
|
|
81
|
+
const outputs = Object.entries(config?.outputs || {})
|
|
82
|
+
.map(([name, output]) => ({
|
|
83
|
+
name,
|
|
84
|
+
path: output?.path || null,
|
|
85
|
+
ownership: output?.ownership || null
|
|
86
|
+
}))
|
|
87
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
88
|
+
const runtimes = (config?.topology?.runtimes || [])
|
|
89
|
+
.map((/** @type {AnyRecord} */ component) => ({
|
|
90
|
+
id: component.id,
|
|
91
|
+
kind: component.kind,
|
|
92
|
+
projection: component.projection,
|
|
93
|
+
generator: {
|
|
94
|
+
id: component.generator?.id || null,
|
|
95
|
+
version: component.generator?.version || null
|
|
96
|
+
},
|
|
97
|
+
port: topologyComponentPort(component),
|
|
98
|
+
references: topologyComponentReferences(component)
|
|
99
|
+
}))
|
|
100
|
+
.sort((/** @type {AnyRecord} */ left, /** @type {AnyRecord} */ right) => left.id.localeCompare(right.id));
|
|
101
|
+
const edges = runtimes.flatMap((/** @type {AnyRecord} */ component) => {
|
|
102
|
+
const references = [];
|
|
103
|
+
if (component.references.uses_api) {
|
|
104
|
+
references.push({
|
|
105
|
+
from: component.id,
|
|
106
|
+
to: component.references.uses_api,
|
|
107
|
+
type: "calls_api"
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
if (component.references.uses_database) {
|
|
111
|
+
references.push({
|
|
112
|
+
from: component.id,
|
|
113
|
+
to: component.references.uses_database,
|
|
114
|
+
type: "uses_database"
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return references;
|
|
118
|
+
}).sort((/** @type {AnyRecord} */ left, /** @type {AnyRecord} */ right) => `${left.from}:${left.type}:${left.to}`.localeCompare(`${right.from}:${right.type}:${right.to}`));
|
|
119
|
+
return {
|
|
120
|
+
outputs,
|
|
121
|
+
runtimes,
|
|
122
|
+
edges
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @param {AnyRecord|null|undefined} topology
|
|
128
|
+
* @returns {AnyRecord|null}
|
|
129
|
+
*/
|
|
130
|
+
export function publicProjectTopology(topology) {
|
|
131
|
+
if (!topology || typeof topology !== "object") {
|
|
132
|
+
return topology || null;
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
...Object.fromEntries(Object.entries(topology).filter(([key]) => key !== "components")),
|
|
136
|
+
runtimes: topology.runtimes || []
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* @param {{ inputPath: string, ast: AnyRecord, resolved: AnyRecord, projectConfigInfo: AnyRecord|null, projectValidation: { ok: boolean, errors: any[] } }} input
|
|
142
|
+
* @returns {AnyRecord}
|
|
143
|
+
*/
|
|
144
|
+
export function checkSummaryPayload({ inputPath, ast, resolved, projectConfigInfo, projectValidation }) {
|
|
145
|
+
const statementCount = ast.files.flatMap((/** @type {{ statements: any[] }} */ file) => file.statements).length;
|
|
146
|
+
const projectInfo = projectConfigInfo || {
|
|
147
|
+
configPath: null,
|
|
148
|
+
compatibility: false,
|
|
149
|
+
config: { topology: null }
|
|
150
|
+
};
|
|
151
|
+
const resolvedTopology = summarizeProjectTopology(projectInfo.config);
|
|
152
|
+
return {
|
|
153
|
+
ok: resolved.ok && projectValidation.ok,
|
|
154
|
+
inputPath,
|
|
155
|
+
topogram: {
|
|
156
|
+
files: ast.files.length,
|
|
157
|
+
statements: statementCount,
|
|
158
|
+
valid: resolved.ok
|
|
159
|
+
},
|
|
160
|
+
project: {
|
|
161
|
+
configPath: projectInfo.configPath,
|
|
162
|
+
compatibility: Boolean(projectInfo.compatibility),
|
|
163
|
+
valid: projectValidation.ok,
|
|
164
|
+
topology: publicProjectTopology(projectInfo.config.topology),
|
|
165
|
+
resolvedTopology
|
|
166
|
+
},
|
|
167
|
+
errors: [
|
|
168
|
+
...(resolved.ok ? [] : resolved.validation.errors.map((/** @type {AnyRecord} */ error) => ({
|
|
169
|
+
source: "topogram",
|
|
170
|
+
message: error.message,
|
|
171
|
+
loc: error.loc
|
|
172
|
+
}))),
|
|
173
|
+
...projectValidation.errors.map((error) => ({
|
|
174
|
+
source: "project",
|
|
175
|
+
message: error.message,
|
|
176
|
+
loc: error.loc
|
|
177
|
+
}))
|
|
178
|
+
]
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* @param {string} filePath
|
|
184
|
+
* @returns {{ sha256: string, size: number }}
|
|
185
|
+
*/
|
|
186
|
+
export function projectFileHash(filePath) {
|
|
187
|
+
const bytes = fs.readFileSync(filePath);
|
|
188
|
+
return {
|
|
189
|
+
sha256: crypto.createHash("sha256").update(bytes).digest("hex"),
|
|
190
|
+
size: bytes.length
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* @param {string} filePath
|
|
196
|
+
* @returns {AnyRecord|null}
|
|
197
|
+
*/
|
|
198
|
+
export function readJsonIfExists(filePath) {
|
|
199
|
+
if (!fs.existsSync(filePath)) {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* @param {string} projectRoot
|
|
207
|
+
* @returns {string}
|
|
208
|
+
*/
|
|
209
|
+
export function importAdoptionsPath(projectRoot) {
|
|
210
|
+
return path.join(normalizeProjectRoot(projectRoot), TOPOGRAM_IMPORT_ADOPTIONS_FILE);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* @param {string} projectRoot
|
|
215
|
+
* @returns {AnyRecord[]}
|
|
216
|
+
*/
|
|
217
|
+
export function readImportAdoptionReceipts(projectRoot) {
|
|
218
|
+
const historyPath = importAdoptionsPath(projectRoot);
|
|
219
|
+
if (!fs.existsSync(historyPath)) {
|
|
220
|
+
return [];
|
|
221
|
+
}
|
|
222
|
+
return fs.readFileSync(historyPath, "utf8")
|
|
223
|
+
.split(/\r?\n/)
|
|
224
|
+
.map((/** @type {string} */ line) => line.trim())
|
|
225
|
+
.filter(Boolean)
|
|
226
|
+
.map((/** @type {string} */ line, /** @type {number} */ index) => {
|
|
227
|
+
try {
|
|
228
|
+
return JSON.parse(line);
|
|
229
|
+
} catch (error) {
|
|
230
|
+
throw new Error(`Invalid import adoption receipt JSON at ${historyPath}:${index + 1}.`);
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* @param {string} projectRoot
|
|
237
|
+
* @param {AnyRecord} receipt
|
|
238
|
+
* @returns {string}
|
|
239
|
+
*/
|
|
240
|
+
export function appendImportAdoptionReceipt(projectRoot, receipt) {
|
|
241
|
+
const historyPath = importAdoptionsPath(projectRoot);
|
|
242
|
+
fs.appendFileSync(historyPath, `${JSON.stringify(receipt)}\n`, "utf8");
|
|
243
|
+
return historyPath;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* @param {AnyRecord[]} items
|
|
248
|
+
* @param {string} fieldName
|
|
249
|
+
* @returns {Record<string, number>}
|
|
250
|
+
*/
|
|
251
|
+
export function countByField(items, fieldName) {
|
|
252
|
+
/** @type {Record<string, number>} */
|
|
253
|
+
const counts = {};
|
|
254
|
+
for (const item of items || []) {
|
|
255
|
+
const key = item?.[fieldName] || "unknown";
|
|
256
|
+
counts[key] = (counts[key] || 0) + 1;
|
|
257
|
+
}
|
|
258
|
+
return Object.fromEntries(Object.entries(counts).sort(([left], [right]) => left.localeCompare(right)));
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* @param {string} projectRoot
|
|
263
|
+
* @returns {string}
|
|
264
|
+
*/
|
|
265
|
+
export function importProjectCommandPath(projectRoot) {
|
|
266
|
+
return shellCommandArg(path.relative(process.cwd(), projectRoot) || ".");
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* @param {string} projectRoot
|
|
271
|
+
* @param {string} selector
|
|
272
|
+
* @param {boolean} [write]
|
|
273
|
+
* @returns {string}
|
|
274
|
+
*/
|
|
275
|
+
export function importAdoptCommand(projectRoot, selector, write = false) {
|
|
276
|
+
return `topogram import adopt ${selector} ${importProjectCommandPath(projectRoot)} ${write ? "--write" : "--dry-run"}`;
|
|
277
|
+
}
|