@topogram/cli 0.3.65 → 0.3.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/package.json +1 -1
  2. package/src/adoption/plan/index.js +21 -8
  3. package/src/adoption/reporting.js +1 -1
  4. package/src/agent-brief.js +7 -21
  5. package/src/agent-ops/query-builders/change-risk/review-packets.js +2 -2
  6. package/src/agent-ops/query-builders/common.js +2 -2
  7. package/src/agent-ops/query-builders/multi-agent.js +1 -1
  8. package/src/agent-ops/query-builders/workflow-presets-core.js +3 -2
  9. package/src/archive/jsonl.js +2 -2
  10. package/src/archive/resolver-bridge.js +1 -1
  11. package/src/archive/unarchive.js +2 -1
  12. package/src/catalog/copy.js +11 -6
  13. package/src/catalog/provenance.js +2 -1
  14. package/src/cli/command-parsers/project.js +3 -0
  15. package/src/cli/command-parsers/shared.js +1 -1
  16. package/src/cli/commands/agent.js +2 -2
  17. package/src/cli/commands/check.js +3 -3
  18. package/src/cli/commands/doctor.js +2 -9
  19. package/src/cli/commands/generator-policy/runner.js +1 -1
  20. package/src/cli/commands/import/help.js +2 -2
  21. package/src/cli/commands/import/paths.js +3 -11
  22. package/src/cli/commands/import/plan.js +9 -1
  23. package/src/cli/commands/import/refresh.js +7 -6
  24. package/src/cli/commands/import/workspace.js +8 -5
  25. package/src/cli/commands/migrate.js +153 -0
  26. package/src/cli/commands/query/definitions.js +10 -10
  27. package/src/cli/commands/query/workspace.js +2 -6
  28. package/src/cli/commands/source.js +3 -12
  29. package/src/cli/commands/template/check.js +6 -5
  30. package/src/cli/commands/template-runner.js +6 -6
  31. package/src/cli/commands/trust.js +1 -1
  32. package/src/cli/commands/workflow.js +6 -1
  33. package/src/cli/dispatcher.js +6 -1
  34. package/src/cli/help.js +15 -14
  35. package/src/cli/migration-guidance.js +1 -1
  36. package/src/cli/output-safety.js +2 -1
  37. package/src/cli/path-normalization.js +3 -13
  38. package/src/generator/context/domain-page.js +1 -1
  39. package/src/generator/context/shared/maintained-boundary.js +2 -2
  40. package/src/generator/context/shared/metrics.js +2 -2
  41. package/src/generator/context/task-mode.js +2 -2
  42. package/src/generator/sdlc/doc-page.js +1 -1
  43. package/src/generator/surfaces/databases/lifecycle-shared.js +1 -1
  44. package/src/generator/surfaces/native/swiftui-templates/README.generated.md +1 -1
  45. package/src/import/core/context.js +5 -7
  46. package/src/import/core/runner/candidates.js +123 -3
  47. package/src/import/core/runner/reports.js +4 -3
  48. package/src/import/core/runner/ui-drafts.js +58 -2
  49. package/src/new-project/constants.js +1 -1
  50. package/src/new-project/create.js +9 -2
  51. package/src/new-project/project-files.js +16 -13
  52. package/src/new-project/template-resolution.js +6 -4
  53. package/src/new-project/template-snapshots.js +38 -8
  54. package/src/new-project/template-updates.js +1 -1
  55. package/src/project-config/index.js +27 -0
  56. package/src/sdlc/adopt.js +6 -5
  57. package/src/sdlc/paths.js +3 -5
  58. package/src/sdlc/scaffold.js +2 -1
  59. package/src/workflows/reconcile/adoption-plan/build.js +7 -3
  60. package/src/workflows/reconcile/adoption-plan/outputs.js +12 -2
  61. package/src/workflows/reconcile/adoption-plan/paths.js +1 -1
  62. package/src/workflows/reconcile/candidate-model.js +18 -2
  63. package/src/workflows/reconcile/impacts/adoption-plan.js +6 -2
  64. package/src/workflows/reconcile/impacts/indexes.js +5 -1
  65. package/src/workflows/reconcile/renderers.js +41 -6
  66. package/src/workflows/shared.js +5 -11
  67. package/src/workspace-paths.js +328 -0
@@ -0,0 +1,153 @@
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 {
8
+ DEFAULT_TOPO_FOLDER_NAME,
9
+ DEFAULT_WORKSPACE_PATH,
10
+ LEGACY_TOPOGRAM_FOLDER_NAME,
11
+ PROJECT_CONFIG_FILE
12
+ } from "../../workspace-paths.js";
13
+
14
+ /**
15
+ * @param {string|null|undefined} inputPath
16
+ * @returns {string}
17
+ */
18
+ function projectRootForMigration(inputPath) {
19
+ const absolute = path.resolve(inputPath || ".");
20
+ const base = path.basename(absolute);
21
+ if (base === DEFAULT_TOPO_FOLDER_NAME || base === LEGACY_TOPOGRAM_FOLDER_NAME) {
22
+ return path.dirname(absolute);
23
+ }
24
+ return absolute;
25
+ }
26
+
27
+ /**
28
+ * @param {string} projectRoot
29
+ * @returns {string[]}
30
+ */
31
+ function caseCollisionEntries(projectRoot) {
32
+ if (!fs.existsSync(projectRoot) || !fs.statSync(projectRoot).isDirectory()) {
33
+ return [];
34
+ }
35
+ return fs.readdirSync(projectRoot)
36
+ .filter((/** @type {string} */ entry) => entry.toLowerCase() === DEFAULT_TOPO_FOLDER_NAME && entry !== DEFAULT_TOPO_FOLDER_NAME);
37
+ }
38
+
39
+ /**
40
+ * @param {string} projectRoot
41
+ * @returns {{ write: boolean, path: string|null, before: any|null, after: any|null }}
42
+ */
43
+ function plannedProjectConfigUpdate(projectRoot) {
44
+ const configPath = path.join(projectRoot, PROJECT_CONFIG_FILE);
45
+ if (!fs.existsSync(configPath)) {
46
+ return { write: false, path: null, before: null, after: null };
47
+ }
48
+ const before = JSON.parse(fs.readFileSync(configPath, "utf8"));
49
+ const after = { ...before };
50
+ const currentWorkspace = before.workspace;
51
+ if (currentWorkspace == null || currentWorkspace === "./topogram" || currentWorkspace === "topogram") {
52
+ after.workspace = DEFAULT_WORKSPACE_PATH;
53
+ }
54
+ return {
55
+ write: JSON.stringify(before) !== JSON.stringify(after),
56
+ path: configPath,
57
+ before,
58
+ after
59
+ };
60
+ }
61
+
62
+ /**
63
+ * @param {string|null|undefined} inputPath
64
+ * @param {{ write?: boolean, json?: boolean }} [options]
65
+ * @returns {number}
66
+ */
67
+ export function runMigrateCommand(inputPath, options = {}) {
68
+ const projectRoot = projectRootForMigration(inputPath);
69
+ const legacyPath = path.join(projectRoot, LEGACY_TOPOGRAM_FOLDER_NAME);
70
+ const topoPath = path.join(projectRoot, DEFAULT_TOPO_FOLDER_NAME);
71
+ const write = Boolean(options.write);
72
+ /** @type {Array<Record<string, any>>} */
73
+ const diagnostics = [];
74
+ /** @type {Array<Record<string, any>>} */
75
+ const actions = [];
76
+
77
+ if (fs.existsSync(legacyPath) && fs.lstatSync(legacyPath).isSymbolicLink()) {
78
+ diagnostics.push({ severity: "error", message: `Refusing to migrate symlinked ${LEGACY_TOPOGRAM_FOLDER_NAME}/ at ${legacyPath}.` });
79
+ }
80
+ const collisions = caseCollisionEntries(projectRoot);
81
+ if (collisions.length > 0) {
82
+ diagnostics.push({ severity: "error", message: `Refusing to migrate because case-conflicting topo path(s) exist: ${collisions.join(", ")}.` });
83
+ }
84
+ if (fs.existsSync(legacyPath) && fs.existsSync(topoPath)) {
85
+ diagnostics.push({ severity: "error", message: `Refusing to migrate because both ${LEGACY_TOPOGRAM_FOLDER_NAME}/ and ${DEFAULT_TOPO_FOLDER_NAME}/ exist.` });
86
+ }
87
+ if (!fs.existsSync(legacyPath) && !fs.existsSync(topoPath)) {
88
+ diagnostics.push({ severity: "error", message: `No ${LEGACY_TOPOGRAM_FOLDER_NAME}/ or ${DEFAULT_TOPO_FOLDER_NAME}/ workspace folder found at ${projectRoot}.` });
89
+ }
90
+ if (fs.existsSync(topoPath) && fs.statSync(topoPath).isDirectory() && fs.readdirSync(topoPath).length > 0 && fs.existsSync(legacyPath)) {
91
+ diagnostics.push({ severity: "error", message: `Refusing to overwrite non-empty ${DEFAULT_TOPO_FOLDER_NAME}/ at ${topoPath}.` });
92
+ }
93
+
94
+ if (fs.existsSync(legacyPath) && diagnostics.length === 0) {
95
+ actions.push({
96
+ kind: "rename",
97
+ from: legacyPath,
98
+ to: topoPath
99
+ });
100
+ }
101
+ const configUpdate = plannedProjectConfigUpdate(projectRoot);
102
+ if (configUpdate.write) {
103
+ actions.push({
104
+ kind: "update_config",
105
+ path: configUpdate.path,
106
+ workspace: DEFAULT_WORKSPACE_PATH
107
+ });
108
+ }
109
+
110
+ const ok = diagnostics.filter((diagnostic) => diagnostic.severity === "error").length === 0;
111
+ if (ok && write) {
112
+ for (const action of actions) {
113
+ if (action.kind === "rename") {
114
+ fs.renameSync(action.from, action.to);
115
+ }
116
+ if (action.kind === "update_config" && configUpdate.path && configUpdate.after) {
117
+ fs.writeFileSync(configUpdate.path, `${JSON.stringify(configUpdate.after, null, 2)}\n`, "utf8");
118
+ }
119
+ }
120
+ }
121
+
122
+ const payload = {
123
+ ok,
124
+ dryRun: !write,
125
+ projectRoot,
126
+ legacyPath,
127
+ topoPath,
128
+ actions,
129
+ diagnostics,
130
+ errors: diagnostics.filter((diagnostic) => diagnostic.severity === "error").map((diagnostic) => diagnostic.message)
131
+ };
132
+ if (options.json) {
133
+ console.log(stableStringify(payload));
134
+ } else if (payload.ok) {
135
+ console.log(write ? "Workspace folder migration complete." : "Workspace folder migration dry run.");
136
+ if (actions.length === 0) {
137
+ console.log("No changes needed.");
138
+ }
139
+ for (const action of actions) {
140
+ if (action.kind === "rename") {
141
+ console.log(`Rename: ${action.from} -> ${action.to}`);
142
+ }
143
+ if (action.kind === "update_config") {
144
+ console.log(`Update ${action.path}: workspace ${DEFAULT_WORKSPACE_PATH}`);
145
+ }
146
+ }
147
+ } else {
148
+ for (const error of payload.errors) {
149
+ console.error(error);
150
+ }
151
+ }
152
+ return payload.ok ? 0 : 1;
153
+ }
@@ -40,7 +40,7 @@ export function queryDefinitions() {
40
40
  selectors: ["capability", "workflow", "projection", "widget", "entity", "journey", "domain"],
41
41
  args: ["[path]", "[selectors]", "[--json]"],
42
42
  output: "context_slice",
43
- example: "topogram query slice ./topogram --widget widget_data_grid"
43
+ example: "topogram query slice ./topo --widget widget_data_grid"
44
44
  },
45
45
  {
46
46
  name: "verification-targets",
@@ -49,7 +49,7 @@ export function queryDefinitions() {
49
49
  selectors: ["mode", "capability", "workflow", "projection", "widget", "entity", "journey", "from-topogram"],
50
50
  args: ["[path]", "[selectors]", "[--from-topogram <path>]", "[--json]"],
51
51
  output: "verification_targets",
52
- example: "topogram query verification-targets ./topogram --widget widget_data_grid"
52
+ example: "topogram query verification-targets ./topo --widget widget_data_grid"
53
53
  },
54
54
  {
55
55
  name: "widget-behavior",
@@ -58,7 +58,7 @@ export function queryDefinitions() {
58
58
  selectors: ["projection", "widget"],
59
59
  args: ["[path]", "[--projection <id>]", "[--widget <id>]", "[--json]"],
60
60
  output: "widget_behavior_report",
61
- example: "topogram query widget-behavior ./topogram --projection proj_web_surface --widget widget_data_grid --json"
61
+ example: "topogram query widget-behavior ./topo --projection proj_web_surface --widget widget_data_grid --json"
62
62
  },
63
63
  {
64
64
  name: "change-plan",
@@ -67,7 +67,7 @@ export function queryDefinitions() {
67
67
  selectors: ["mode", "capability", "workflow", "projection", "widget", "entity", "journey", "surface", "from-topogram"],
68
68
  args: ["[path]", "[selectors]", "[--from-topogram <path>]", "[--json]"],
69
69
  output: "change_plan_query",
70
- example: "topogram query change-plan ./topogram --widget widget_data_grid"
70
+ example: "topogram query change-plan ./topo --widget widget_data_grid"
71
71
  },
72
72
  {
73
73
  name: "review-packet",
@@ -76,7 +76,7 @@ export function queryDefinitions() {
76
76
  selectors: ["mode", "capability", "workflow", "projection", "widget", "entity", "journey", "surface", "from-topogram"],
77
77
  args: ["[path]", "[selectors]", "[--from-topogram <path>]", "[--json]"],
78
78
  output: "review_packet_query",
79
- example: "topogram query review-packet ./topogram --widget widget_data_grid"
79
+ example: "topogram query review-packet ./topo --widget widget_data_grid"
80
80
  },
81
81
  {
82
82
  name: "resolved-workflow-context",
@@ -85,7 +85,7 @@ export function queryDefinitions() {
85
85
  selectors: ["mode", "capability", "workflow", "projection", "widget", "entity", "journey", "surface", "provider", "preset", "from-topogram"],
86
86
  args: ["[path]", "[--mode <id>]", "[selectors]", "[--from-topogram <path>]", "[--json]"],
87
87
  output: "resolved_workflow_context_query",
88
- example: "topogram query resolved-workflow-context ./topogram --mode modeling --widget widget_data_grid --json"
88
+ example: "topogram query resolved-workflow-context ./topo --mode modeling --widget widget_data_grid --json"
89
89
  },
90
90
  {
91
91
  name: "single-agent-plan",
@@ -94,7 +94,7 @@ export function queryDefinitions() {
94
94
  selectors: ["mode", "capability", "workflow", "projection", "widget", "entity", "journey", "surface", "from-topogram"],
95
95
  args: ["[path]", "[--mode <id>]", "[selectors]", "[--from-topogram <path>]", "[--json]"],
96
96
  output: "single_agent_plan_query",
97
- example: "topogram query single-agent-plan ./topogram --mode modeling --widget widget_data_grid --json"
97
+ example: "topogram query single-agent-plan ./topo --mode modeling --widget widget_data_grid --json"
98
98
  },
99
99
  {
100
100
  name: "risk-summary",
@@ -103,7 +103,7 @@ export function queryDefinitions() {
103
103
  selectors: ["mode", "capability", "workflow", "projection", "widget", "entity", "journey", "surface", "from-topogram"],
104
104
  args: ["[path]", "[selectors]", "[--from-topogram <path>]", "[--json]"],
105
105
  output: "risk_summary_query",
106
- example: "topogram query risk-summary ./topogram --widget widget_data_grid"
106
+ example: "topogram query risk-summary ./topo --widget widget_data_grid"
107
107
  },
108
108
  {
109
109
  name: "proceed-decision",
@@ -112,7 +112,7 @@ export function queryDefinitions() {
112
112
  selectors: ["mode", "capability", "workflow", "projection", "widget", "entity", "journey", "surface", "from-topogram"],
113
113
  args: ["[path]", "[--mode <id>]", "[selectors]", "[--from-topogram <path>]", "[--json]"],
114
114
  output: "proceed_decision_query",
115
- example: "topogram query proceed-decision ./topogram --mode verification"
115
+ example: "topogram query proceed-decision ./topo --mode verification"
116
116
  },
117
117
  {
118
118
  name: "write-scope",
@@ -121,7 +121,7 @@ export function queryDefinitions() {
121
121
  selectors: ["mode", "capability", "workflow", "projection", "widget", "entity", "journey", "from-topogram"],
122
122
  args: ["[path]", "[selectors]", "[--from-topogram <path>]", "[--json]"],
123
123
  output: "write_scope_query",
124
- example: "topogram query write-scope ./topogram --widget widget_data_grid"
124
+ example: "topogram query write-scope ./topo --widget widget_data_grid"
125
125
  }
126
126
  ];
127
127
  }
@@ -6,6 +6,7 @@ import path from "node:path";
6
6
  import { generateWorkspace } from "../../../generator.js";
7
7
  import { formatValidationErrors } from "../../../validator.js";
8
8
  import { buildChangePlanPayload } from "../../../agent-ops/query-builders.js";
9
+ import { resolveTopoRoot } from "../../../workspace-paths.js";
9
10
 
10
11
  /**
11
12
  * @typedef {Record<string, any>} AnyRecord
@@ -16,12 +17,7 @@ import { buildChangePlanPayload } from "../../../agent-ops/query-builders.js";
16
17
  * @returns {string}
17
18
  */
18
19
  export function normalizeTopogramPath(inputPath) {
19
- const absolute = path.resolve(inputPath);
20
- if (path.basename(absolute) === "topogram") {
21
- return absolute;
22
- }
23
- const candidate = path.join(absolute, "topogram");
24
- return fs.existsSync(candidate) ? candidate : absolute;
20
+ return resolveTopoRoot(inputPath);
25
21
  }
26
22
 
27
23
  /**
@@ -1,6 +1,5 @@
1
1
  // @ts-check
2
2
 
3
- import fs from "node:fs";
4
3
  import path from "node:path";
5
4
 
6
5
  import { stableStringify } from "../../format.js";
@@ -18,6 +17,7 @@ import {
18
17
  localTemplatePackageStatus
19
18
  } from "./package.js";
20
19
  import { buildTemplateOwnedBaselineStatus } from "./template.js";
20
+ import { resolveTopoRoot, resolveWorkspaceContext } from "../../workspace-paths.js";
21
21
 
22
22
  /**
23
23
  * @typedef {Record<string, any>} AnyRecord
@@ -43,12 +43,7 @@ export function printSourceHelp() {
43
43
  * @returns {string}
44
44
  */
45
45
  function normalizeTopogramPath(inputPath) {
46
- const absolute = path.resolve(inputPath);
47
- if (path.basename(absolute) === "topogram") {
48
- return absolute;
49
- }
50
- const candidate = path.join(absolute, "topogram");
51
- return fs.existsSync(candidate) ? candidate : absolute;
46
+ return resolveTopoRoot(inputPath);
52
47
  }
53
48
 
54
49
  /**
@@ -56,11 +51,7 @@ function normalizeTopogramPath(inputPath) {
56
51
  * @returns {string}
57
52
  */
58
53
  export function normalizeProjectRoot(inputPath) {
59
- const absolute = path.resolve(inputPath);
60
- if (path.basename(absolute) === "topogram") {
61
- return path.dirname(absolute);
62
- }
63
- return absolute;
54
+ return resolveWorkspaceContext(inputPath).projectRoot;
64
55
  }
65
56
 
66
57
  /**
@@ -11,6 +11,7 @@ import {
11
11
  validateProjectConfig,
12
12
  validateProjectOutputOwnership
13
13
  } from "../../../project-config.js";
14
+ import { resolveTopoRoot } from "../../../workspace-paths.js";
14
15
  import {
15
16
  buildTemplateUpdatePlan,
16
17
  createNewProject,
@@ -91,12 +92,12 @@ function diagnosticForTemplateCreateFailure(message, templateSpec, step) {
91
92
  step
92
93
  });
93
94
  }
94
- if (message.includes("is missing topogram/")) {
95
+ if (message.includes("is missing topo/") || message.includes("is missing topogram/")) {
95
96
  return templateCheckDiagnostic({
96
97
  code: "template_topogram_missing",
97
98
  message,
98
- path: localTemplatePath(templateSpec, "topogram"),
99
- suggestedFix: "Add a topogram/ directory with the reusable Topogram source files.",
99
+ path: localTemplatePath(templateSpec, "topo"),
100
+ suggestedFix: "Add a topo/ directory with the reusable Topogram source files.",
100
101
  step
101
102
  });
102
103
  }
@@ -105,7 +106,7 @@ function diagnosticForTemplateCreateFailure(message, templateSpec, step) {
105
106
  code: "template_project_config_missing",
106
107
  message,
107
108
  path: localTemplatePath(templateSpec, "topogram.project.json"),
108
- suggestedFix: "Add topogram.project.json beside topogram/ with outputs and topology.runtimes.",
109
+ suggestedFix: "Add topogram.project.json beside topo/ with outputs and topology.runtimes.",
109
110
  step
110
111
  });
111
112
  }
@@ -320,7 +321,7 @@ export function buildTemplateCheckPayload(templateSpec) {
320
321
  template: projectConfigInfo.config.template?.id || null
321
322
  }));
322
323
 
323
- const ast = parsePath(path.join(projectRoot, "topogram"));
324
+ const ast = parsePath(resolveTopoRoot(projectRoot));
324
325
  const resolved = resolveWorkspace(ast);
325
326
  const projectValidation = combineProjectValidationResults(
326
327
  validateProjectConfig(projectConfigInfo.config, resolved.ok ? resolved.graph : null, { configDir: projectConfigInfo.configDir }),
@@ -77,7 +77,7 @@ export function runTemplateCommand(context) {
77
77
  }
78
78
 
79
79
  if (command === "status") {
80
- const projectConfigInfo = loadProjectConfig(inputPath || "./topogram");
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 || "./topogram");
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 || "./topogram");
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 || "./topogram");
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 || "./topogram", commandArgs.templatePolicyPinSpec);
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 || "./topogram",
181
+ inputPath: inputPath || "./topo",
182
182
  templateIndex: args.indexOf("--template"),
183
183
  templateName,
184
184
  useLatestTemplate: args.includes("--latest"),
@@ -205,7 +205,7 @@ export function runTrustDiffCommand(inputPath, options = {}) {
205
205
  * @returns {number}
206
206
  */
207
207
  export function runTrustCommand(context) {
208
- const inputPath = context.inputPath || "./topogram";
208
+ const inputPath = context.inputPath || "./topo";
209
209
  if (context.commandArgs.trustCommand === "template") {
210
210
  return runTrustTemplateCommand(inputPath, { force: Boolean(context.commandArgs.force) });
211
211
  }
@@ -6,6 +6,7 @@ import path from "node:path";
6
6
  import { stableStringify } from "../../format.js";
7
7
  import { parsePath } from "../../parser.js";
8
8
  import { formatValidationErrors, validateWorkspace } from "../../validator.js";
9
+ import { resolveTopoRoot } from "../../workspace-paths.js";
9
10
  import { runWorkflow } from "../../workflows.js";
10
11
 
11
12
  /**
@@ -13,7 +14,11 @@ import { runWorkflow } from "../../workflows.js";
13
14
  * @returns {number}
14
15
  */
15
16
  export function runValidateCommand(inputPath) {
16
- const ast = parsePath(inputPath || ".");
17
+ const requestedPath = inputPath || ".";
18
+ const targetPath = fs.existsSync(requestedPath) && fs.statSync(requestedPath).isFile()
19
+ ? requestedPath
20
+ : resolveTopoRoot(requestedPath);
21
+ const ast = parsePath(targetPath);
17
22
  const result = validateWorkspace(ast);
18
23
  if (!result.ok) {
19
24
  console.error(formatValidationErrors(result));
@@ -10,6 +10,7 @@ import { runGenerateAppCommand } from "./commands/generate.js";
10
10
  import { runGeneratorCommand } from "./commands/generator.js";
11
11
  import { runGeneratorPolicyCommand } from "./commands/generator-policy.js";
12
12
  import { runImportCommand } from "./commands/import-runner.js";
13
+ import { runMigrateCommand } from "./commands/migrate.js";
13
14
  import { runNewProjectCommand } from "./commands/new.js";
14
15
  import { runPackageCommand } from "./commands/package.js";
15
16
  import { runParseCommand, runResolveCommand } from "./commands/inspect.js";
@@ -145,7 +146,7 @@ export async function runCliDispatch(context) {
145
146
  return 1;
146
147
  }
147
148
 
148
- if ((shouldCheck || shouldWidgetCheck || shouldWidgetBehavior || shouldAgentBrief || shouldValidate || commandArgs?.generatorPolicyCommand || commandArgs?.trustCommand || generateTarget === "app-bundle") && inputPath) {
149
+ if ((shouldCheck || shouldWidgetCheck || shouldWidgetBehavior || shouldAgentBrief || shouldValidate || commandArgs?.generatorPolicyCommand || commandArgs?.trustCommand || commandArgs?.queryName || commandArgs?.workflowPresetCommand || generateTarget) && inputPath) {
149
150
  inputPath = normalizeTopogramPath(inputPath);
150
151
  }
151
152
  const effectiveInputPath = commandInputPath(inputPath);
@@ -241,6 +242,10 @@ export async function runCliDispatch(context) {
241
242
  return runPackageCommand({ commandArgs, inputPath, json: emitJson });
242
243
  }
243
244
 
245
+ if (commandArgs?.migrateCommand) {
246
+ return runMigrateCommand(inputPath, { write: shouldWrite, json: emitJson });
247
+ }
248
+
244
249
  if (commandArgs?.importCommand) {
245
250
  return runImportCommand({
246
251
  commandArgs,
package/src/cli/help.js CHANGED
@@ -28,6 +28,7 @@ export function printUsage(options = {}) {
28
28
  console.log(" or: topogram catalog doctor [--json] [--catalog <path-or-source>]");
29
29
  console.log(" or: topogram catalog check <path-or-url> [--json]");
30
30
  console.log(" or: topogram catalog copy <id> <target> [--version <version>] [--json] [--catalog <path-or-source>]");
31
+ console.log(" or: topogram migrate workspace-folder [path] [--dry-run|--write] [--json]");
31
32
  console.log(" or: topogram package update-cli <version|--latest> [--json]");
32
33
  console.log(" or: topogram import <app-path> --out <target> [--from <track[,track]>] [--json]");
33
34
  console.log(" or: topogram import refresh [path] [--from <app-path>] [--dry-run] [--json]");
@@ -79,9 +80,9 @@ export function printUsage(options = {}) {
79
80
  console.log(" topogram agent brief --json");
80
81
  console.log(" topogram query list");
81
82
  console.log(" topogram query show widget-behavior");
82
- console.log(" topogram query widget-behavior ./topogram --projection proj_web_surface --json");
83
+ console.log(" topogram query widget-behavior ./topo --projection proj_web_surface --json");
83
84
  console.log(" topogram emit ui-widget-contract --widget widget_data_grid --json");
84
- console.log(" topogram emit widget-conformance-report ./topogram --projection proj_web_surface --json");
85
+ console.log(" topogram emit widget-conformance-report ./topo --projection proj_web_surface --json");
85
86
  console.log(" topogram generator list");
86
87
  console.log(" topogram generator show @topogram/generator-react-web");
87
88
  console.log(" topogram generator check ./generator-package");
@@ -136,7 +137,7 @@ export function printUsage(options = {}) {
136
137
  console.log(" topogram template update --check");
137
138
  console.log(" topogram template update --apply");
138
139
  console.log("");
139
- console.log("Defaults: check/generate use ./topogram, and generate writes ./app.");
140
+ console.log("Defaults: check/generate use ./topo, and generate writes ./app.");
140
141
  console.log("Default starter: hello-web from the catalog. Run `topogram template list` for catalog aliases.");
141
142
  console.log("Generated app commands are emitted into the output package.json.");
142
143
  console.log("Run `topogram help <command>` for command-specific help.");
@@ -231,13 +232,13 @@ export function printGenerateHelp() {
231
232
  console.log("Usage: topogram generate [path] [--out <path>]");
232
233
  console.log(" or: topogram generate app [path] [--out <path>]");
233
234
  console.log("");
234
- console.log("Defaults: path is ./topogram and app generation writes ./app.");
235
+ console.log("Defaults: path is ./topo and app generation writes ./app.");
235
236
  console.log("Use `topogram emit <target>` for contracts, reports, snapshots, migration plans, and other artifacts.");
236
237
  console.log("");
237
238
  console.log("Examples:");
238
239
  console.log(" topogram generate");
239
- console.log(" topogram generate ./topogram --out ./app");
240
- console.log(" topogram generate app ./topogram --out ./app");
240
+ console.log(" topogram generate ./topo --out ./app");
241
+ console.log(" topogram generate app ./topo --out ./app");
241
242
  }
242
243
 
243
244
  /**
@@ -249,7 +250,7 @@ export function printEmitHelp() {
249
250
  console.log("");
250
251
  console.log("Emits named contracts, reports, snapshots, migration plans, and other artifacts.");
251
252
  console.log("");
252
- console.log("Defaults: path is ./topogram. Emit prints to stdout unless --write is passed. --write writes ./artifacts unless --out-dir is supplied.");
253
+ console.log("Defaults: path is ./topo. Emit prints to stdout unless --write is passed. --write writes ./artifacts unless --out-dir is supplied.");
253
254
  console.log("");
254
255
  console.log("Common artifact targets:");
255
256
  console.log(" ui-widget-contract");
@@ -268,10 +269,10 @@ export function printEmitHelp() {
268
269
  console.log("");
269
270
  console.log("Examples:");
270
271
  console.log(" topogram emit ui-widget-contract --widget widget_data_grid --json");
271
- console.log(" topogram emit widget-conformance-report ./topogram --projection proj_web_surface --json");
272
- console.log(" topogram emit widget-behavior-report ./topogram --projection proj_web_surface --json");
273
- console.log(" topogram emit db-schema-snapshot ./topogram --projection proj_db_postgres --json");
274
- console.log(" topogram emit sql-migration ./topogram --projection proj_db_postgres --from-snapshot ./state/current.json");
272
+ console.log(" topogram emit widget-conformance-report ./topo --projection proj_web_surface --json");
273
+ console.log(" topogram emit widget-behavior-report ./topo --projection proj_web_surface --json");
274
+ console.log(" topogram emit db-schema-snapshot ./topo --projection proj_db_postgres --json");
275
+ console.log(" topogram emit sql-migration ./topo --projection proj_db_postgres --from-snapshot ./state/current.json");
275
276
  console.log(" topogram emit ui-widget-contract --write --out-dir ./contracts");
276
277
  }
277
278
 
@@ -284,13 +285,13 @@ export function printWidgetHelp() {
284
285
  console.log("");
285
286
  console.log("Checks projection widget_bindings usage against reusable widget contracts and behavior realizations.");
286
287
  console.log("");
287
- console.log("Defaults: path is ./topogram.");
288
+ console.log("Defaults: path is ./topo.");
288
289
  console.log("");
289
290
  console.log("Examples:");
290
291
  console.log(" topogram widget check");
291
292
  console.log(" topogram widget check --projection proj_web_surface");
292
- console.log(" topogram widget check ./topogram --widget widget_data_grid --json");
293
+ console.log(" topogram widget check ./topo --widget widget_data_grid --json");
293
294
  console.log(" topogram widget behavior");
294
295
  console.log(" topogram widget behavior --projection proj_web_surface");
295
- console.log(" topogram widget behavior ./topogram --widget widget_data_grid --json");
296
+ console.log(" topogram widget behavior ./topo --widget widget_data_grid --json");
296
297
  }
@@ -17,7 +17,7 @@ const RENAMED_GENERATE_TARGETS = new Map([
17
17
  * @param {string} [fallback]
18
18
  * @returns {string}
19
19
  */
20
- function commandPath(args, index, fallback = "./topogram") {
20
+ function commandPath(args, index, fallback = "./topo") {
21
21
  const value = args[index];
22
22
  return value && !value.startsWith("-") ? value : fallback;
23
23
  }
@@ -5,6 +5,7 @@ import os from "node:os";
5
5
  import path from "node:path";
6
6
 
7
7
  import { outputOwnershipForPath } from "../project-config.js";
8
+ import { DEFAULT_TOPO_FOLDER_NAME } from "../workspace-paths.js";
8
9
 
9
10
  export const GENERATED_OUTPUT_SENTINEL = ".topogram-generated.json";
10
11
 
@@ -103,5 +104,5 @@ export function topogramInputPathForGeneration(inputPath) {
103
104
  if (isSameOrInside(REPO_ROOT, absolute)) {
104
105
  return `./${path.relative(REPO_ROOT, absolute).replace(/\\/g, "/")}`;
105
106
  }
106
- return path.basename(absolute) === "topogram" ? "./topogram" : ".";
107
+ return path.basename(absolute) === DEFAULT_TOPO_FOLDER_NAME ? `./${DEFAULT_TOPO_FOLDER_NAME}` : ".";
107
108
  }
@@ -1,19 +1,13 @@
1
1
  // @ts-check
2
2
 
3
- import fs from "node:fs";
4
- import path from "node:path";
3
+ import { resolveTopoRoot, resolveWorkspaceContext } from "../workspace-paths.js";
5
4
 
6
5
  /**
7
6
  * @param {string} inputPath
8
7
  * @returns {string}
9
8
  */
10
9
  export function normalizeTopogramPath(inputPath) {
11
- const absolute = path.resolve(inputPath);
12
- if (path.basename(absolute) === "topogram") {
13
- return absolute;
14
- }
15
- const candidate = path.join(absolute, "topogram");
16
- return fs.existsSync(candidate) ? candidate : absolute;
10
+ return resolveTopoRoot(inputPath);
17
11
  }
18
12
 
19
13
  /**
@@ -21,9 +15,5 @@ export function normalizeTopogramPath(inputPath) {
21
15
  * @returns {string}
22
16
  */
23
17
  export function normalizeProjectRoot(inputPath) {
24
- const absolute = path.resolve(inputPath);
25
- if (path.basename(absolute) === "topogram") {
26
- return path.dirname(absolute);
27
- }
28
- return absolute;
18
+ return resolveWorkspaceContext(inputPath).projectRoot;
29
19
  }
@@ -118,7 +118,7 @@ export function generateDomainPage(graph, options = {}) {
118
118
  version: 1,
119
119
  focus: { kind: "domain", id: domain.id },
120
120
  output: {
121
- path: `topogram/docs-generated/domains/${domain.id}.md`,
121
+ path: `topo/docs-generated/domains/${domain.id}.md`,
122
122
  contents: lines.join("\n") + "\n"
123
123
  },
124
124
  summary
@@ -1,5 +1,6 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
+ import { resolveWorkspaceContext } from "../../../workspace-paths.js";
3
4
 
4
5
  import { parseDocFile } from "../../../workspace-docs.js";
5
6
  import {
@@ -49,8 +50,7 @@ export function relativePathFromGraph(graph, targetPath) {
49
50
  * @returns {any}
50
51
  */
51
52
  function workspaceRootFromGraph(graph) {
52
- const root = path.resolve(graph.root);
53
- return path.basename(root) === "topogram" ? path.dirname(root) : root;
53
+ return resolveWorkspaceContext(graph.root).projectRoot;
54
54
  }
55
55
 
56
56
  /**
@@ -34,7 +34,7 @@ export function percentOf(part, whole) {
34
34
  */
35
35
  export function buildDefaultWriteScope() {
36
36
  return {
37
- safe_to_edit: ["topogram/**", "candidates/**"],
37
+ safe_to_edit: ["topo/**", "candidates/**"],
38
38
  generator_owned: ["artifacts/**", "apps/**"],
39
39
  human_owned_review_required: ["examples/maintained/proof-app/**"],
40
40
  out_of_bounds: [".git/**", "node_modules/**"]
@@ -54,7 +54,7 @@ export function buildMaintainedWriteScope(graph, maintainedFiles = []) {
54
54
  ...maintainedFiles,
55
55
  "examples/maintained/proof-app/**"
56
56
  ]),
57
- out_of_bounds: ["topogram/**"]
57
+ out_of_bounds: ["topo/**"]
58
58
  };
59
59
  }
60
60