@topogram/cli 0.3.77 → 0.3.79
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/CHANGELOG.md +20 -0
- package/package.json +2 -2
- package/src/agent-brief.js +29 -23
- package/src/agent-ops/query-builders/change-risk/{import-plan.js → extract-plan.js} +1 -1
- package/src/agent-ops/query-builders/change-risk/review-packets.js +5 -5
- package/src/agent-ops/query-builders/change-risk.js +1 -1
- package/src/agent-ops/query-builders/common.js +2 -2
- package/src/agent-ops/query-builders/multi-agent.js +1 -1
- package/src/agent-ops/query-builders/workflow-context-shared.js +4 -4
- package/src/catalog/provenance.js +1 -1
- package/src/cli/catalog-alias.d.ts +2 -0
- package/src/cli/catalog-alias.js +2 -2
- package/src/cli/command-parsers/core.js +9 -5
- package/src/cli/command-parsers/import.js +11 -17
- package/src/cli/command-parsers/project.js +0 -3
- package/src/cli/commands/catalog/copy.js +3 -3
- package/src/cli/commands/catalog/help.js +1 -2
- package/src/cli/commands/catalog/list.js +7 -4
- package/src/cli/commands/catalog/show.js +4 -4
- package/src/cli/commands/copy.js +356 -0
- package/src/cli/commands/doctor.js +1 -1
- package/src/cli/commands/import/adopt.js +9 -9
- package/src/cli/commands/import/check.js +15 -15
- package/src/cli/commands/import/diff.js +6 -6
- package/src/cli/commands/import/help.js +43 -34
- package/src/cli/commands/import/paths.js +3 -3
- package/src/cli/commands/import/plan.js +8 -8
- package/src/cli/commands/import/refresh.js +25 -24
- package/src/cli/commands/import/status-history.js +4 -4
- package/src/cli/commands/import/workspace.js +16 -16
- package/src/cli/commands/import-runner.js +6 -5
- package/src/cli/commands/import.js +4 -1
- package/src/cli/commands/init.js +67 -0
- package/src/cli/commands/query/{import-adopt.js → extract-adopt.js} +2 -2
- package/src/cli/commands/query/runner/change.js +2 -2
- package/src/cli/commands/query/runner/{import-adopt.js → extract-adopt.js} +9 -9
- package/src/cli/commands/query/runner/index.js +1 -1
- package/src/cli/commands/query/runner/workflow.js +7 -7
- package/src/cli/commands/query/workspace.js +4 -4
- package/src/cli/commands/release-status.js +2 -2
- package/src/cli/commands/source.js +2 -2
- package/src/cli/commands/template/check.js +2 -2
- package/src/cli/commands/template/list-show.js +4 -4
- package/src/cli/dispatcher.js +18 -3
- package/src/cli/help-dispatch.js +22 -8
- package/src/cli/help.js +68 -52
- package/src/cli/migration-guidance.js +9 -0
- package/src/generator/context/bundle.js +14 -7
- package/src/generator/context/diff.js +8 -1
- package/src/generator/context/digest.js +10 -1
- package/src/generator/context/shared/domain-sdlc.js +5 -1
- package/src/generator/context/shared/relationships.js +20 -5
- package/src/generator/context/shared/summaries.js +26 -0
- package/src/generator/context/shared.d.ts +1 -0
- package/src/generator/context/shared.js +1 -0
- package/src/generator/context/slice/core.js +9 -5
- package/src/generator/context/slice/sdlc.js +31 -2
- package/src/generator/context/task-mode.js +3 -3
- package/src/import/core/runner/reports.js +4 -4
- package/src/import/core/shared/files.js +21 -2
- package/src/import/core/shared.js +2 -1
- package/src/import/enrichers/django-rest.js +4 -4
- package/src/import/enrichers/rails-controllers.js +3 -3
- package/src/import/enrichers/rails-models.js +3 -3
- package/src/import/extractors/api/aspnet-core.js +5 -5
- package/src/import/extractors/api/django-routes.js +5 -5
- package/src/import/extractors/api/express.js +4 -4
- package/src/import/extractors/api/fastify.js +7 -7
- package/src/import/extractors/api/flutter-dio.js +4 -4
- package/src/import/extractors/api/generic-route-fallback.js +2 -2
- package/src/import/extractors/api/graphql-code-first.js +3 -3
- package/src/import/extractors/api/graphql-sdl.js +5 -5
- package/src/import/extractors/api/jaxrs.js +3 -3
- package/src/import/extractors/api/micronaut.js +3 -3
- package/src/import/extractors/api/openapi-code.js +4 -4
- package/src/import/extractors/api/openapi.js +3 -3
- package/src/import/extractors/api/rails-routes.js +3 -3
- package/src/import/extractors/api/react-native-repository.js +3 -3
- package/src/import/extractors/api/retrofit.js +3 -3
- package/src/import/extractors/api/spring-web.js +3 -3
- package/src/import/extractors/api/swift-webapi.js +3 -3
- package/src/import/extractors/api/trpc.js +4 -4
- package/src/import/extractors/cli/generic.js +3 -3
- package/src/import/extractors/db/django-models.js +4 -4
- package/src/import/extractors/db/dotnet-models.js +4 -4
- package/src/import/extractors/db/drizzle.js +9 -7
- package/src/import/extractors/db/ef-core.js +5 -5
- package/src/import/extractors/db/flutter-entities.js +3 -3
- package/src/import/extractors/db/jpa.js +3 -3
- package/src/import/extractors/db/liquibase.js +3 -3
- package/src/import/extractors/db/maintained-seams.js +4 -4
- package/src/import/extractors/db/mybatis-xml.js +4 -4
- package/src/import/extractors/db/prisma.js +3 -3
- package/src/import/extractors/db/rails-schema.js +3 -3
- package/src/import/extractors/db/react-native-entities.js +3 -3
- package/src/import/extractors/db/room.js +5 -5
- package/src/import/extractors/db/snapshot.js +3 -3
- package/src/import/extractors/db/sql.js +3 -3
- package/src/import/extractors/db/swiftdata.js +3 -3
- package/src/import/extractors/ui/android-compose.js +4 -4
- package/src/import/extractors/ui/backend-only.js +3 -3
- package/src/import/extractors/ui/blazor.js +3 -3
- package/src/import/extractors/ui/flutter-screens.js +3 -3
- package/src/import/extractors/ui/maui-xaml.js +4 -4
- package/src/import/extractors/ui/next-pages-router.js +3 -3
- package/src/import/extractors/ui/razor-pages.js +3 -3
- package/src/import/extractors/ui/react-native-screens.js +4 -4
- package/src/import/extractors/ui/swiftui.js +3 -3
- package/src/import/extractors/ui/uikit.js +3 -3
- package/src/import/provenance.js +16 -16
- package/src/init-project.js +215 -0
- package/src/new-project/constants.js +1 -1
- package/src/new-project/create.js +2 -2
- package/src/new-project/project-files.js +7 -7
- package/src/reconcile/journeys.js +8 -3
- package/src/record-blocks.js +125 -0
- package/src/resolver/index.js +3 -0
- package/src/resolver/journeys.js +74 -0
- package/src/resolver/normalize.js +25 -0
- package/src/sdlc/adopt.js +1 -1
- package/src/validator/common.js +34 -1
- package/src/validator/index.js +4 -0
- package/src/validator/kinds.d.ts +2 -0
- package/src/validator/kinds.js +34 -1
- package/src/validator/per-kind/journey.js +233 -0
- package/src/workflows/docs-generate.js +4 -1
- package/src/workflows/reconcile/bundle-core/index.js +4 -2
- package/src/workflows/reconcile/canonical-surface.js +4 -1
- package/src/cli/commands/new.js +0 -94
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
canonicalCandidateTerm,
|
|
3
3
|
dedupeCandidateRecords,
|
|
4
|
-
|
|
4
|
+
findPrimaryImportFiles,
|
|
5
5
|
idHintify,
|
|
6
6
|
makeCandidateRecord,
|
|
7
7
|
relativeTo,
|
|
@@ -151,8 +151,8 @@ export const roomExtractor = {
|
|
|
151
151
|
id: "db.room",
|
|
152
152
|
track: "db",
|
|
153
153
|
detect(context) {
|
|
154
|
-
const entityFiles =
|
|
155
|
-
const daoFiles =
|
|
154
|
+
const entityFiles = findPrimaryImportFiles(context.paths, (filePath) => /Entity\.kt$/i.test(filePath) || /\/entitiy\/.+\.kt$/i.test(filePath) || /\/entity\/.+\.kt$/i.test(filePath));
|
|
155
|
+
const daoFiles = findPrimaryImportFiles(context.paths, (filePath) => /Dao\.kt$/i.test(filePath));
|
|
156
156
|
const score = entityFiles.length > 0 && daoFiles.length > 0 ? 89 : 0;
|
|
157
157
|
return {
|
|
158
158
|
score,
|
|
@@ -160,8 +160,8 @@ export const roomExtractor = {
|
|
|
160
160
|
};
|
|
161
161
|
},
|
|
162
162
|
extract(context) {
|
|
163
|
-
const entityFiles =
|
|
164
|
-
const daoFiles =
|
|
163
|
+
const entityFiles = findPrimaryImportFiles(context.paths, (filePath) => /Entity\.kt$/i.test(filePath) || /\/entitiy\/.+\.kt$/i.test(filePath) || /\/entity\/.+\.kt$/i.test(filePath));
|
|
164
|
+
const daoFiles = findPrimaryImportFiles(context.paths, (filePath) => /Dao\.kt$/i.test(filePath));
|
|
165
165
|
const findings = [];
|
|
166
166
|
const candidates = { entities: [], enums: [], relations: [], indexes: [] };
|
|
167
167
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { findPrimaryImportFiles, makeCandidateRecord, relativeTo, slugify, titleCase, idHintify } from "../../core/shared.js";
|
|
2
2
|
|
|
3
3
|
function parseDbSchemaSnapshot(snapshot) {
|
|
4
4
|
return {
|
|
@@ -42,14 +42,14 @@ export const snapshotExtractor = {
|
|
|
42
42
|
id: "db.snapshot",
|
|
43
43
|
track: "db",
|
|
44
44
|
detect(context) {
|
|
45
|
-
const files =
|
|
45
|
+
const files = findPrimaryImportFiles(context.paths, (filePath) => filePath.endsWith(".db-schema-snapshot.json"));
|
|
46
46
|
return {
|
|
47
47
|
score: files.length > 0 ? 40 : 0,
|
|
48
48
|
reasons: files.length > 0 ? ["Found DB schema snapshot artifacts"] : []
|
|
49
49
|
};
|
|
50
50
|
},
|
|
51
51
|
extract(context) {
|
|
52
|
-
const snapshotFiles =
|
|
52
|
+
const snapshotFiles = findPrimaryImportFiles(context.paths, (filePath) => filePath.endsWith(".db-schema-snapshot.json"));
|
|
53
53
|
const findings = [];
|
|
54
54
|
const candidates = { entities: [], enums: [], relations: [], indexes: [] };
|
|
55
55
|
for (const filePath of snapshotFiles) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { canonicalCandidateTerm,
|
|
1
|
+
import { canonicalCandidateTerm, findPrimaryImportFiles, isPrimaryImportSource, makeCandidateRecord, relativeTo, selectPreferredImportFiles, slugify, titleCase, idHintify } from "../../core/shared.js";
|
|
2
2
|
import { inferSqlMaintainedDbSeams } from "./maintained-seams.js";
|
|
3
3
|
|
|
4
4
|
function parseTableConstraint(line, tableName) {
|
|
@@ -105,14 +105,14 @@ export const sqlExtractor = {
|
|
|
105
105
|
id: "db.sql",
|
|
106
106
|
track: "db",
|
|
107
107
|
detect(context) {
|
|
108
|
-
const files =
|
|
108
|
+
const files = findPrimaryImportFiles(context.paths, (filePath) => filePath.endsWith(".sql") && isPrimaryImportSource(context.paths, filePath));
|
|
109
109
|
return {
|
|
110
110
|
score: files.length > 0 ? 80 : 0,
|
|
111
111
|
reasons: files.length > 0 ? ["Found SQL schema or migration files"] : []
|
|
112
112
|
};
|
|
113
113
|
},
|
|
114
114
|
extract(context) {
|
|
115
|
-
const allSqlFiles =
|
|
115
|
+
const allSqlFiles = findPrimaryImportFiles(context.paths, (filePath) => filePath.endsWith(".sql") && isPrimaryImportSource(context.paths, filePath));
|
|
116
116
|
const schemaSqlFiles = allSqlFiles.filter((filePath) => !/migration/i.test(filePath) && !/\/src\/test\//i.test(filePath));
|
|
117
117
|
const migrationSqlFiles = allSqlFiles.filter((filePath) => /migration/i.test(filePath));
|
|
118
118
|
const sqlFiles =
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
canonicalCandidateTerm,
|
|
3
3
|
dedupeCandidateRecords,
|
|
4
|
-
|
|
4
|
+
findPrimaryImportFiles,
|
|
5
5
|
idHintify,
|
|
6
6
|
makeCandidateRecord,
|
|
7
7
|
relativeTo,
|
|
@@ -106,7 +106,7 @@ export const swiftDataExtractor = {
|
|
|
106
106
|
id: "db.swiftdata",
|
|
107
107
|
track: "db",
|
|
108
108
|
detect(context) {
|
|
109
|
-
const files =
|
|
109
|
+
const files = findPrimaryImportFiles(context.paths, (filePath) => /\.swift$/i.test(filePath))
|
|
110
110
|
.filter((filePath) => /@Model/.test(context.helpers.readTextIfExists(filePath) || ""));
|
|
111
111
|
return {
|
|
112
112
|
score: files.length > 0 ? 86 : 0,
|
|
@@ -114,7 +114,7 @@ export const swiftDataExtractor = {
|
|
|
114
114
|
};
|
|
115
115
|
},
|
|
116
116
|
extract(context) {
|
|
117
|
-
const files =
|
|
117
|
+
const files = findPrimaryImportFiles(context.paths, (filePath) => /\.swift$/i.test(filePath))
|
|
118
118
|
.filter((filePath) => /@Model/.test(context.helpers.readTextIfExists(filePath) || ""));
|
|
119
119
|
const findings = [];
|
|
120
120
|
const candidates = { entities: [], enums: [], relations: [], indexes: [] };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
canonicalCandidateTerm,
|
|
3
3
|
dedupeCandidateRecords,
|
|
4
|
-
|
|
4
|
+
findPrimaryImportFiles,
|
|
5
5
|
idHintify,
|
|
6
6
|
makeCandidateRecord,
|
|
7
7
|
relativeTo,
|
|
@@ -85,7 +85,7 @@ export const androidComposeUiExtractor = {
|
|
|
85
85
|
id: "ui.android-compose",
|
|
86
86
|
track: "ui",
|
|
87
87
|
detect(context) {
|
|
88
|
-
const composeFiles =
|
|
88
|
+
const composeFiles = findPrimaryImportFiles(context.paths, (filePath) => /\.kt$/i.test(filePath))
|
|
89
89
|
.filter((filePath) => /@Composable/.test(context.helpers.readTextIfExists(filePath) || ""));
|
|
90
90
|
const score = composeFiles.length > 0 ? 84 : 0;
|
|
91
91
|
return {
|
|
@@ -94,8 +94,8 @@ export const androidComposeUiExtractor = {
|
|
|
94
94
|
};
|
|
95
95
|
},
|
|
96
96
|
extract(context) {
|
|
97
|
-
const navFiles =
|
|
98
|
-
const composeFiles =
|
|
97
|
+
const navFiles = findPrimaryImportFiles(context.paths, (filePath) => /NavHost\.kt$/i.test(filePath) || /navigation\/.+\.kt$/i.test(filePath));
|
|
98
|
+
const composeFiles = findPrimaryImportFiles(context.paths, (filePath) => /\.kt$/i.test(filePath))
|
|
99
99
|
.filter((filePath) => /@Composable/.test(context.helpers.readTextIfExists(filePath) || ""));
|
|
100
100
|
const findings = [];
|
|
101
101
|
const candidates = { screens: [], routes: [], actions: [], stacks: [] };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { findPrimaryImportFiles, relativeTo } from "../../core/shared.js";
|
|
4
4
|
|
|
5
5
|
function readPackageJson(context) {
|
|
6
|
-
const packageFile =
|
|
6
|
+
const packageFile = findPrimaryImportFiles(context.paths, (filePath) => /package\.json$/i.test(filePath))[0];
|
|
7
7
|
if (!packageFile) return null;
|
|
8
8
|
try {
|
|
9
9
|
return {
|
|
@@ -24,7 +24,7 @@ function hasFrontendSignals(context) {
|
|
|
24
24
|
if (deps.react || deps.next || deps["@remix-run/react"] || deps["@sveltejs/kit"] || deps.svelte || deps.vue || deps.nuxt) {
|
|
25
25
|
return true;
|
|
26
26
|
}
|
|
27
|
-
const uiFiles =
|
|
27
|
+
const uiFiles = findPrimaryImportFiles(
|
|
28
28
|
context.paths,
|
|
29
29
|
(filePath) =>
|
|
30
30
|
/(app\/.+\/page\.(tsx|ts|jsx|js|mdx)|src\/App\.tsx|src\/routes\/.+\.(svelte|tsx|jsx)|pages\/.+\.(tsx|ts|jsx|js))$/i.test(filePath)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
canonicalCandidateTerm,
|
|
3
3
|
dedupeCandidateRecords,
|
|
4
|
-
|
|
4
|
+
findPrimaryImportFiles,
|
|
5
5
|
idHintify,
|
|
6
6
|
makeCandidateRecord,
|
|
7
7
|
relativeTo,
|
|
@@ -98,7 +98,7 @@ export const blazorUiExtractor = {
|
|
|
98
98
|
id: "ui.blazor",
|
|
99
99
|
track: "ui",
|
|
100
100
|
detect(context) {
|
|
101
|
-
const razorFiles =
|
|
101
|
+
const razorFiles = findPrimaryImportFiles(context.paths, (filePath) => /\.razor$/i.test(filePath))
|
|
102
102
|
.filter((filePath) => !shouldIgnoreFile(filePath));
|
|
103
103
|
const score = razorFiles.length > 0 ? 86 : 0;
|
|
104
104
|
return {
|
|
@@ -107,7 +107,7 @@ export const blazorUiExtractor = {
|
|
|
107
107
|
};
|
|
108
108
|
},
|
|
109
109
|
extract(context) {
|
|
110
|
-
const razorFiles =
|
|
110
|
+
const razorFiles = findPrimaryImportFiles(context.paths, (filePath) => /\.razor$/i.test(filePath))
|
|
111
111
|
.filter((filePath) => !shouldIgnoreFile(filePath));
|
|
112
112
|
const findings = [];
|
|
113
113
|
const candidates = { screens: [], routes: [], actions: [], stacks: [] };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
canonicalCandidateTerm,
|
|
3
3
|
dedupeCandidateRecords,
|
|
4
|
-
|
|
4
|
+
findPrimaryImportFiles,
|
|
5
5
|
idHintify,
|
|
6
6
|
makeCandidateRecord,
|
|
7
7
|
relativeTo,
|
|
@@ -110,7 +110,7 @@ export const flutterScreensUiExtractor = {
|
|
|
110
110
|
id: "ui.flutter-screens",
|
|
111
111
|
track: "ui",
|
|
112
112
|
detect(context) {
|
|
113
|
-
const files =
|
|
113
|
+
const files = findPrimaryImportFiles(
|
|
114
114
|
context.paths,
|
|
115
115
|
(filePath) => /\/lib\/features\/.+\/presentation\/screens\/.+_screen\.dart$/i.test(filePath)
|
|
116
116
|
);
|
|
@@ -121,7 +121,7 @@ export const flutterScreensUiExtractor = {
|
|
|
121
121
|
};
|
|
122
122
|
},
|
|
123
123
|
extract(context) {
|
|
124
|
-
const files =
|
|
124
|
+
const files = findPrimaryImportFiles(
|
|
125
125
|
context.paths,
|
|
126
126
|
(filePath) => /\/lib\/features\/.+\/presentation\/screens\/.+_screen\.dart$/i.test(filePath)
|
|
127
127
|
);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
canonicalCandidateTerm,
|
|
3
3
|
dedupeCandidateRecords,
|
|
4
|
-
|
|
4
|
+
findPrimaryImportFiles,
|
|
5
5
|
idHintify,
|
|
6
6
|
makeCandidateRecord,
|
|
7
7
|
relativeTo,
|
|
@@ -54,7 +54,7 @@ export const mauiXamlUiExtractor = {
|
|
|
54
54
|
id: "ui.maui-xaml",
|
|
55
55
|
track: "ui",
|
|
56
56
|
detect(context) {
|
|
57
|
-
const xamlFiles =
|
|
57
|
+
const xamlFiles = findPrimaryImportFiles(context.paths, (filePath) => /\.xaml$/i.test(filePath));
|
|
58
58
|
const score = xamlFiles.some((filePath) => /ContentPage|Shell/.test(context.helpers.readTextIfExists(filePath) || "")) ? 82 : 0;
|
|
59
59
|
return {
|
|
60
60
|
score,
|
|
@@ -62,8 +62,8 @@ export const mauiXamlUiExtractor = {
|
|
|
62
62
|
};
|
|
63
63
|
},
|
|
64
64
|
extract(context) {
|
|
65
|
-
const shellFiles =
|
|
66
|
-
const viewFiles =
|
|
65
|
+
const shellFiles = findPrimaryImportFiles(context.paths, (filePath) => /AppShell\.xaml$/i.test(filePath));
|
|
66
|
+
const viewFiles = findPrimaryImportFiles(context.paths, (filePath) => /\/Views\/.+\.xaml$/i.test(filePath));
|
|
67
67
|
const findings = [];
|
|
68
68
|
const candidates = { screens: [], routes: [], actions: [], stacks: [] };
|
|
69
69
|
const shellEntries = shellFiles.flatMap((filePath) => parseShellContent(context.helpers.readTextIfExists(filePath) || ""));
|
|
@@ -2,7 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
dedupeCandidateRecords,
|
|
5
|
-
|
|
5
|
+
findPrimaryImportFiles,
|
|
6
6
|
inferNonResourceUiFlow,
|
|
7
7
|
makeCandidateRecord,
|
|
8
8
|
proposedUiContractAdditionsForFlow,
|
|
@@ -61,7 +61,7 @@ export const nextPagesRouterUiExtractor = {
|
|
|
61
61
|
id: "ui.next-pages-router",
|
|
62
62
|
track: "ui",
|
|
63
63
|
detect(context) {
|
|
64
|
-
const pageFiles =
|
|
64
|
+
const pageFiles = findPrimaryImportFiles(context.paths, (filePath) => /src\/pages\/.+\.(tsx|ts|jsx|js|mdx)$/i.test(filePath))
|
|
65
65
|
.filter((filePath) => !/\/api\//.test(filePath) && !/\/_(app|document|error)\./.test(filePath) && !/\/404\./.test(filePath));
|
|
66
66
|
return {
|
|
67
67
|
score: pageFiles.length > 0 ? 85 : 0,
|
|
@@ -70,7 +70,7 @@ export const nextPagesRouterUiExtractor = {
|
|
|
70
70
|
},
|
|
71
71
|
extract(context) {
|
|
72
72
|
const pagesRoot = path.join(context.paths.workspaceRoot, "src", "pages");
|
|
73
|
-
const pageFiles =
|
|
73
|
+
const pageFiles = findPrimaryImportFiles(context.paths, (filePath) => /src\/pages\/.+\.(tsx|ts|jsx|js|mdx)$/i.test(filePath))
|
|
74
74
|
.filter((filePath) => !/\/api\//.test(filePath) && !/\/_(app|document|error)\./.test(filePath) && !/\/404\./.test(filePath));
|
|
75
75
|
const findings = [];
|
|
76
76
|
const candidates = { screens: [], routes: [], actions: [], flows: [], stacks: [] };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
canonicalCandidateTerm,
|
|
3
3
|
dedupeCandidateRecords,
|
|
4
|
-
|
|
4
|
+
findPrimaryImportFiles,
|
|
5
5
|
idHintify,
|
|
6
6
|
makeCandidateRecord,
|
|
7
7
|
relativeTo,
|
|
@@ -81,7 +81,7 @@ export const razorPagesUiExtractor = {
|
|
|
81
81
|
id: "ui.razor-pages",
|
|
82
82
|
track: "ui",
|
|
83
83
|
detect(context) {
|
|
84
|
-
const files =
|
|
84
|
+
const files = findPrimaryImportFiles(context.paths, (filePath) => /\.cshtml$/i.test(filePath))
|
|
85
85
|
.filter((filePath) => !shouldIgnoreFile(filePath));
|
|
86
86
|
const score = files.length > 0 ? 84 : 0;
|
|
87
87
|
return {
|
|
@@ -90,7 +90,7 @@ export const razorPagesUiExtractor = {
|
|
|
90
90
|
};
|
|
91
91
|
},
|
|
92
92
|
extract(context) {
|
|
93
|
-
const files =
|
|
93
|
+
const files = findPrimaryImportFiles(context.paths, (filePath) => /\.cshtml$/i.test(filePath))
|
|
94
94
|
.filter((filePath) => !shouldIgnoreFile(filePath));
|
|
95
95
|
const findings = [];
|
|
96
96
|
const candidates = { screens: [], routes: [], actions: [], stacks: [] };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
canonicalCandidateTerm,
|
|
3
3
|
dedupeCandidateRecords,
|
|
4
|
-
|
|
4
|
+
findPrimaryImportFiles,
|
|
5
5
|
idHintify,
|
|
6
6
|
makeCandidateRecord,
|
|
7
7
|
relativeTo,
|
|
@@ -119,7 +119,7 @@ export const reactNativeScreensExtractor = {
|
|
|
119
119
|
id: "ui.react-native-screens",
|
|
120
120
|
track: "ui",
|
|
121
121
|
detect(context) {
|
|
122
|
-
const files =
|
|
122
|
+
const files = findPrimaryImportFiles(
|
|
123
123
|
context.paths,
|
|
124
124
|
(filePath) => /\/src\/.+\/presentation\/screens\/.+Screen\.tsx$/i.test(filePath)
|
|
125
125
|
);
|
|
@@ -130,11 +130,11 @@ export const reactNativeScreensExtractor = {
|
|
|
130
130
|
};
|
|
131
131
|
},
|
|
132
132
|
extract(context) {
|
|
133
|
-
const screenFiles =
|
|
133
|
+
const screenFiles = findPrimaryImportFiles(
|
|
134
134
|
context.paths,
|
|
135
135
|
(filePath) => /\/src\/.+\/presentation\/screens\/.+Screen\.tsx$/i.test(filePath)
|
|
136
136
|
);
|
|
137
|
-
const navigatorFile =
|
|
137
|
+
const navigatorFile = findPrimaryImportFiles(
|
|
138
138
|
context.paths,
|
|
139
139
|
(filePath) => /\/src\/core\/presentation\/navigation\/RootNavigator\.tsx$/i.test(filePath)
|
|
140
140
|
)[0];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
canonicalCandidateTerm,
|
|
3
3
|
dedupeCandidateRecords,
|
|
4
|
-
|
|
4
|
+
findPrimaryImportFiles,
|
|
5
5
|
idHintify,
|
|
6
6
|
isPrimaryImportSource,
|
|
7
7
|
makeCandidateRecord,
|
|
@@ -118,7 +118,7 @@ export const swiftUiExtractor = {
|
|
|
118
118
|
id: "ui.swiftui",
|
|
119
119
|
track: "ui",
|
|
120
120
|
detect(context) {
|
|
121
|
-
const files =
|
|
121
|
+
const files = findPrimaryImportFiles(context.paths, (filePath) => /\.swift$/i.test(filePath) && isPrimaryImportSource(context.paths, filePath))
|
|
122
122
|
.filter((filePath) => /:\s*View\b/.test(context.helpers.readTextIfExists(filePath) || ""));
|
|
123
123
|
return {
|
|
124
124
|
score: files.length > 0 ? 84 : 0,
|
|
@@ -126,7 +126,7 @@ export const swiftUiExtractor = {
|
|
|
126
126
|
};
|
|
127
127
|
},
|
|
128
128
|
extract(context) {
|
|
129
|
-
const files =
|
|
129
|
+
const files = findPrimaryImportFiles(context.paths, (filePath) => /\.swift$/i.test(filePath) && isPrimaryImportSource(context.paths, filePath))
|
|
130
130
|
.filter((filePath) => /:\s*View\b/.test(context.helpers.readTextIfExists(filePath) || ""));
|
|
131
131
|
const findings = [];
|
|
132
132
|
const candidates = { screens: [], routes: [], actions: [], stacks: [] };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
canonicalCandidateTerm,
|
|
3
3
|
dedupeCandidateRecords,
|
|
4
|
-
|
|
4
|
+
findPrimaryImportFiles,
|
|
5
5
|
idHintify,
|
|
6
6
|
makeCandidateRecord,
|
|
7
7
|
relativeTo,
|
|
@@ -64,7 +64,7 @@ export const uiKitExtractor = {
|
|
|
64
64
|
id: "ui.uikit",
|
|
65
65
|
track: "ui",
|
|
66
66
|
detect(context) {
|
|
67
|
-
const controllerFiles =
|
|
67
|
+
const controllerFiles = findPrimaryImportFiles(context.paths, (filePath) => /\.swift$/i.test(filePath))
|
|
68
68
|
.filter((filePath) => !shouldIgnoreFile(filePath))
|
|
69
69
|
.filter((filePath) => /(UIViewController|UITableViewController|UICollectionViewController)/.test(context.helpers.readTextIfExists(filePath) || ""));
|
|
70
70
|
return {
|
|
@@ -73,7 +73,7 @@ export const uiKitExtractor = {
|
|
|
73
73
|
};
|
|
74
74
|
},
|
|
75
75
|
extract(context) {
|
|
76
|
-
const controllerFiles =
|
|
76
|
+
const controllerFiles = findPrimaryImportFiles(context.paths, (filePath) => /\.swift$/i.test(filePath))
|
|
77
77
|
.filter((filePath) => !shouldIgnoreFile(filePath))
|
|
78
78
|
.filter((filePath) => /(UIViewController|UITableViewController|UICollectionViewController)/.test(context.helpers.readTextIfExists(filePath) || ""));
|
|
79
79
|
const findings = [];
|
package/src/import/provenance.js
CHANGED
|
@@ -4,7 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
|
|
5
5
|
import { listFilesRecursive, relativeTo } from "./core/shared.js";
|
|
6
6
|
|
|
7
|
-
export const TOPOGRAM_IMPORT_FILE = ".topogram-
|
|
7
|
+
export const TOPOGRAM_IMPORT_FILE = ".topogram-extract.json";
|
|
8
8
|
|
|
9
9
|
function fileHash(filePath) {
|
|
10
10
|
const bytes = fs.readFileSync(filePath);
|
|
@@ -42,22 +42,22 @@ export function writeTopogramImportRecord(projectRoot, input) {
|
|
|
42
42
|
const timestamp = input.timestamp || new Date().toISOString();
|
|
43
43
|
const record = {
|
|
44
44
|
version: "0.1",
|
|
45
|
-
kind: "brownfield-
|
|
46
|
-
|
|
45
|
+
kind: "brownfield-extract",
|
|
46
|
+
extractedAt: input.importedAt || timestamp,
|
|
47
47
|
...(input.refreshedAt ? { refreshedAt: input.refreshedAt } : {}),
|
|
48
48
|
source: {
|
|
49
49
|
path: path.resolve(input.sourceRoot),
|
|
50
50
|
hashAlgorithm: "sha256",
|
|
51
51
|
ignoredRoots: (input.ignoredRoots || []).map((item) => path.resolve(item))
|
|
52
52
|
},
|
|
53
|
-
|
|
53
|
+
extract: {
|
|
54
54
|
tracks: input.tracks || [],
|
|
55
55
|
findingsCount: input.findingsCount || 0,
|
|
56
56
|
candidateCounts: input.candidateCounts || {}
|
|
57
57
|
},
|
|
58
58
|
ownership: {
|
|
59
|
-
|
|
60
|
-
note: "Topogram artifacts created by
|
|
59
|
+
extractedArtifacts: "project-owned",
|
|
60
|
+
note: "Topogram artifacts created by extraction are editable after extraction. Source hashes record the brownfield app evidence trusted at extraction time."
|
|
61
61
|
},
|
|
62
62
|
...(input.refresh ? { refresh: input.refresh } : {}),
|
|
63
63
|
files: input.files || []
|
|
@@ -79,11 +79,11 @@ export function buildTopogramImportStatus(projectRoot) {
|
|
|
79
79
|
source: null,
|
|
80
80
|
content: { changed: [], added: [], removed: [] },
|
|
81
81
|
diagnostics: [{
|
|
82
|
-
code: "
|
|
82
|
+
code: "topogram_extract_missing",
|
|
83
83
|
severity: "error",
|
|
84
|
-
message: `${TOPOGRAM_IMPORT_FILE} was not found. This workspace does not have brownfield
|
|
84
|
+
message: `${TOPOGRAM_IMPORT_FILE} was not found. This workspace does not have brownfield extraction provenance.`,
|
|
85
85
|
path: importPath,
|
|
86
|
-
suggestedFix: "Run `topogram
|
|
86
|
+
suggestedFix: "Run `topogram extract <app-path> --out <target>` to create an extracted Topogram workspace."
|
|
87
87
|
}],
|
|
88
88
|
errors: [`${TOPOGRAM_IMPORT_FILE} was not found.`]
|
|
89
89
|
};
|
|
@@ -92,7 +92,7 @@ export function buildTopogramImportStatus(projectRoot) {
|
|
|
92
92
|
const source = JSON.parse(fs.readFileSync(importPath, "utf8"));
|
|
93
93
|
const sourceRoot = path.resolve(source.source?.path || "");
|
|
94
94
|
if (!sourceRoot || !fs.existsSync(sourceRoot) || !fs.statSync(sourceRoot).isDirectory()) {
|
|
95
|
-
const message = `
|
|
95
|
+
const message = `Extracted source path was not found: ${source.source?.path || "unknown"}`;
|
|
96
96
|
return {
|
|
97
97
|
ok: false,
|
|
98
98
|
exists: true,
|
|
@@ -101,11 +101,11 @@ export function buildTopogramImportStatus(projectRoot) {
|
|
|
101
101
|
source,
|
|
102
102
|
content: { changed: [], added: [], removed: [] },
|
|
103
103
|
diagnostics: [{
|
|
104
|
-
|
|
104
|
+
code: "topogram_extract_source_missing",
|
|
105
105
|
severity: "error",
|
|
106
106
|
message,
|
|
107
107
|
path: source.source?.path || null,
|
|
108
|
-
suggestedFix: "Restore the
|
|
108
|
+
suggestedFix: "Restore the extracted source path or rerun extract from the current brownfield app location."
|
|
109
109
|
}],
|
|
110
110
|
errors: [message]
|
|
111
111
|
};
|
|
@@ -147,12 +147,12 @@ export function buildTopogramImportStatus(projectRoot) {
|
|
|
147
147
|
source,
|
|
148
148
|
content,
|
|
149
149
|
diagnostics: clean ? [] : [{
|
|
150
|
-
code: "
|
|
150
|
+
code: "topogram_extract_source_changed",
|
|
151
151
|
severity: "error",
|
|
152
|
-
message: "
|
|
152
|
+
message: "Extracted source files changed since they were trusted for this extraction.",
|
|
153
153
|
path: sourceRoot,
|
|
154
|
-
suggestedFix: "Review the source changes. If they should drive Topogram changes, rerun
|
|
154
|
+
suggestedFix: "Review the source changes. If they should drive Topogram changes, rerun extract or update the Topogram artifacts manually."
|
|
155
155
|
}],
|
|
156
|
-
errors: clean ? [] : ["
|
|
156
|
+
errors: clean ? [] : ["Extracted source files changed since extraction."]
|
|
157
157
|
};
|
|
158
158
|
}
|