@topogram/cli 0.3.78 → 0.3.80
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-parser.js +2 -0
- package/src/cli/command-parsers/core.js +9 -5
- package/src/cli/command-parsers/extractor.js +40 -0
- 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/extractor.js +451 -0
- 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 +45 -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 +24 -18
- package/src/cli/commands/import-runner.js +10 -7
- 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 +32 -3
- package/src/cli/help-dispatch.js +33 -8
- package/src/cli/help.js +79 -52
- package/src/cli/migration-guidance.js +9 -0
- package/src/cli/options.js +17 -0
- package/src/extractor/check.js +155 -0
- package/src/extractor/packages.js +295 -0
- package/src/extractor/registry.js +196 -0
- package/src/extractor-policy.js +249 -0
- package/src/generator/check.js +24 -87
- 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/generator/registry/index.js +16 -75
- package/src/generator-policy.js +9 -57
- package/src/import/core/registry.d.ts +3 -0
- package/src/import/core/registry.js +82 -8
- package/src/import/core/runner/reports.js +4 -4
- package/src/import/core/runner/run.js +2 -0
- package/src/import/core/runner/tracks.js +66 -4
- package/src/import/provenance.js +18 -17
- 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/package-adapters/adapter.js +64 -0
- package/src/package-adapters/file-map.js +30 -0
- package/src/package-adapters/index.js +27 -0
- package/src/package-adapters/manifest.js +108 -0
- package/src/package-adapters/policy.js +81 -0
- package/src/package-adapters/spec.js +51 -0
- 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
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
- No changes yet.
|
|
6
|
+
|
|
7
|
+
## 0.3.79 - 2026-05-12
|
|
8
|
+
|
|
9
|
+
- Add graph-native `journey` statements with ordered `step` and `alternate`
|
|
10
|
+
record blocks, resolver/query support, and canonical dogfood journey records.
|
|
11
|
+
- Add `topogram init` as the primary command for starting an empty maintained
|
|
12
|
+
Topogram workspace, including optional SDLC policy initialization.
|
|
13
|
+
- Replace the public creation/extraction vocabulary with `copy`, `extract`, and
|
|
14
|
+
top-level `adopt`: `topogram copy <source> <target>` copies templates or pure
|
|
15
|
+
Topogram packages, `topogram extract` reads brownfield apps into reviewable
|
|
16
|
+
candidates, and `topogram adopt` promotes selected candidates.
|
|
17
|
+
- Rename public extraction provenance and guidance to extract/adopt terms,
|
|
18
|
+
including generated starter docs, agent brief output, package smoke scripts,
|
|
19
|
+
and dogfood CLI surface records.
|
|
20
|
+
- Keep `generate` scoped to app/runtime output and `emit` scoped to contracts,
|
|
21
|
+
reports, snapshots, and plans.
|
|
22
|
+
|
|
23
|
+
## 0.3.78 - 2026-05-12
|
|
24
|
+
|
|
5
25
|
- Install package-backed generator dependencies during `topogram template check`
|
|
6
26
|
before starter validation.
|
|
7
27
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@topogram/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.80",
|
|
4
4
|
"description": "Topogram CLI for checking Topogram workspaces and generating app bundles.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"access": "public"
|
|
28
28
|
},
|
|
29
29
|
"scripts": {
|
|
30
|
-
"
|
|
30
|
+
"copy": "node ./src/cli.js copy",
|
|
31
31
|
"check": "npm test",
|
|
32
32
|
"fixture:check": "node ./src/cli.js check ./tests/fixtures/workspaces/app-basic",
|
|
33
33
|
"fixture:check:json": "node ./src/cli.js check ./tests/fixtures/workspaces/app-basic --json",
|
package/src/agent-brief.js
CHANGED
|
@@ -155,11 +155,17 @@ function readImportSummary(projectRoot) {
|
|
|
155
155
|
path: TOPOGRAM_IMPORT_FILE,
|
|
156
156
|
workspaceRoot: resolveTopoRoot(projectRoot),
|
|
157
157
|
source: typeof record?.source?.path === "string" ? record.source.path : null,
|
|
158
|
-
tracks: Array.isArray(record?.import?.tracks) ? record.import.tracks.map(String) : [],
|
|
159
|
-
candidateCounts: record?.
|
|
158
|
+
tracks: Array.isArray(record?.extract?.tracks) ? record.extract.tracks.map(String) : Array.isArray(record?.import?.tracks) ? record.import.tracks.map(String) : [],
|
|
159
|
+
candidateCounts: record?.extract?.candidateCounts && typeof record.extract.candidateCounts === "object"
|
|
160
|
+
? record.extract.candidateCounts
|
|
161
|
+
: record?.import?.candidateCounts && typeof record.import.candidateCounts === "object"
|
|
160
162
|
? record.import.candidateCounts
|
|
161
163
|
: {},
|
|
162
|
-
ownership: typeof record?.ownership?.
|
|
164
|
+
ownership: typeof record?.ownership?.extractedArtifacts === "string"
|
|
165
|
+
? record.ownership.extractedArtifacts
|
|
166
|
+
: typeof record?.ownership?.importedArtifacts === "string"
|
|
167
|
+
? record.ownership.importedArtifacts
|
|
168
|
+
: null
|
|
163
169
|
};
|
|
164
170
|
} catch (error) {
|
|
165
171
|
return {
|
|
@@ -241,16 +247,16 @@ function buildWorkflows(config, hasImportRecord) {
|
|
|
241
247
|
}
|
|
242
248
|
if (hasImportRecord) {
|
|
243
249
|
workflows.push({
|
|
244
|
-
id: "brownfield-
|
|
245
|
-
title: "Brownfield
|
|
250
|
+
id: "brownfield-extract",
|
|
251
|
+
title: "Brownfield extract/adopt loop",
|
|
246
252
|
commands: [
|
|
247
|
-
"topogram
|
|
248
|
-
"topogram
|
|
249
|
-
"topogram
|
|
250
|
-
"topogram
|
|
251
|
-
"topogram
|
|
253
|
+
"topogram extract check . --json",
|
|
254
|
+
"topogram extract plan . --json",
|
|
255
|
+
"topogram adopt --list . --json",
|
|
256
|
+
"topogram extract status . --json",
|
|
257
|
+
"topogram extract history . --verify --json"
|
|
252
258
|
],
|
|
253
|
-
rule: "
|
|
259
|
+
rule: "Extracted Topogram files are editable after adoption; JSON automation should read workspaceRoot for the project-owned workspace path."
|
|
254
260
|
});
|
|
255
261
|
}
|
|
256
262
|
return workflows;
|
|
@@ -284,7 +290,7 @@ function buildWarnings(projectRoot, config, trust, importSummary, generatorPolic
|
|
|
284
290
|
warnings.push("Generated-owned outputs are replaceable by Topogram; do not make lasting edits under generated output paths.");
|
|
285
291
|
}
|
|
286
292
|
if (importSummary) {
|
|
287
|
-
warnings.push(`${TOPOGRAM_IMPORT_FILE} is present. Treat
|
|
293
|
+
warnings.push(`${TOPOGRAM_IMPORT_FILE} is present. Treat extracted Topogram artifacts as project-owned after adoption; hashes are extraction evidence.`);
|
|
288
294
|
}
|
|
289
295
|
if (!fs.existsSync(path.join(projectRoot, "AGENTS.md"))) {
|
|
290
296
|
warnings.push("AGENTS.md is missing. Use this command as the current agent guidance source.");
|
|
@@ -365,7 +371,7 @@ export function buildAgentBrief(inputPath, workspaceAst) {
|
|
|
365
371
|
readItem(projectRoot, "topogram.template-policy.json", "Template trust/update policy for attached templates.", false),
|
|
366
372
|
readItem(projectRoot, GENERATOR_POLICY_FILE, "Package-backed generator policy and allowed scopes.", false),
|
|
367
373
|
readItem(projectRoot, TEMPLATE_TRUST_FILE, "Executable implementation trust record, if the template copied implementation code.", Boolean(config.implementation)),
|
|
368
|
-
readItem(projectRoot, TOPOGRAM_IMPORT_FILE, "Brownfield
|
|
374
|
+
readItem(projectRoot, TOPOGRAM_IMPORT_FILE, "Brownfield extraction provenance and source evidence, if this came from extract.", Boolean(importSummary)),
|
|
369
375
|
readItem(projectRoot, topogramReadPath, "Canonical Topogram graph source. Use focused query packets for implementation work.", true)
|
|
370
376
|
];
|
|
371
377
|
|
|
@@ -389,11 +395,11 @@ export function buildAgentBrief(inputPath, workspaceAst) {
|
|
|
389
395
|
commandItem("npm run generate", "Write generated-owned runtime/app outputs after validation.", "write"),
|
|
390
396
|
commandItem("npm run verify", "Run generated output verification.", "verify"),
|
|
391
397
|
...(importSummary ? [
|
|
392
|
-
commandItem("topogram
|
|
393
|
-
commandItem("topogram
|
|
394
|
-
commandItem("topogram
|
|
395
|
-
commandItem("topogram
|
|
396
|
-
commandItem("topogram
|
|
398
|
+
commandItem("topogram extract check . --json", "Validate extracted workspace provenance and read workspaceRoot.", "extract"),
|
|
399
|
+
commandItem("topogram extract plan . --json", "Review extraction adoption plan and workspaceRoot.", "extract"),
|
|
400
|
+
commandItem("topogram adopt --list . --json", "List reviewable adoption selectors.", "adopt"),
|
|
401
|
+
commandItem("topogram extract status . --json", "Check extraction/adoption status.", "extract"),
|
|
402
|
+
commandItem("topogram extract history . --verify --json", "Verify adoption history evidence.", "extract")
|
|
397
403
|
] : [])
|
|
398
404
|
];
|
|
399
405
|
|
|
@@ -464,7 +470,7 @@ export function buildAgentBrief(inputPath, workspaceAst) {
|
|
|
464
470
|
issues: trust.issues || []
|
|
465
471
|
},
|
|
466
472
|
generator_policy: generatorPolicy,
|
|
467
|
-
|
|
473
|
+
extract: importSummary,
|
|
468
474
|
warnings: []
|
|
469
475
|
};
|
|
470
476
|
payload.warnings = buildWarnings(projectRoot, config, payload.trust, importSummary, generatorPolicy, sdlcPolicy);
|
|
@@ -520,11 +526,11 @@ export function formatAgentBrief(brief) {
|
|
|
520
526
|
for (const workflow of brief.workflows || []) {
|
|
521
527
|
lines.push(` - ${workflow.title}: ${workflow.rule}`);
|
|
522
528
|
}
|
|
523
|
-
if (brief.
|
|
529
|
+
if (brief.extract?.workspaceRoot) {
|
|
524
530
|
lines.push("");
|
|
525
|
-
lines.push("
|
|
526
|
-
lines.push(` - Workspace root: ${brief.
|
|
527
|
-
lines.push(" - JSON
|
|
531
|
+
lines.push("Extract:");
|
|
532
|
+
lines.push(` - Workspace root: ${brief.extract.workspaceRoot}`);
|
|
533
|
+
lines.push(" - JSON extract commands expose workspaceRoot; prefer it over compatibility fields.");
|
|
528
534
|
}
|
|
529
535
|
lines.push("");
|
|
530
536
|
lines.push("Verification gates:");
|
|
@@ -7,7 +7,7 @@ export function buildImportPlanPayload(adoptionPlan, taskModeArtifact, maintaine
|
|
|
7
7
|
const importNextAction = buildImportPlanNextAction(taskModeArtifact.next_action || null, workflowPresetState);
|
|
8
8
|
const presetGuidanceSummary = buildPresetGuidanceSummary(workflowPresetState, null);
|
|
9
9
|
return {
|
|
10
|
-
type: "
|
|
10
|
+
type: "extract_plan_query",
|
|
11
11
|
summary: taskModeArtifact.summary || null,
|
|
12
12
|
adoption_state_vocabulary: adoptionPlan.adoption_state_vocabulary || [],
|
|
13
13
|
next_action: importNextAction,
|
|
@@ -13,7 +13,7 @@ import { buildPresetGuidanceSummary } from "./risk.js";
|
|
|
13
13
|
export function buildCanonicalWritesPayloadForImportPlan(proposalSurfaces = []) {
|
|
14
14
|
return {
|
|
15
15
|
type: "canonical_writes_query",
|
|
16
|
-
source: "
|
|
16
|
+
source: "extract-plan",
|
|
17
17
|
canonical_writes: proposalSurfaces
|
|
18
18
|
.filter((surface) => surface.canonical_rel_path)
|
|
19
19
|
.map((surface) => ({
|
|
@@ -40,7 +40,7 @@ export function buildReviewPacketPayloadForImportPlan({ importPlan, risk }) {
|
|
|
40
40
|
const presetGuidanceSummary = buildPresetGuidanceSummary(importPlan.workflow_presets || null, null);
|
|
41
41
|
return {
|
|
42
42
|
type: "review_packet_query",
|
|
43
|
-
source: "
|
|
43
|
+
source: "extract-plan",
|
|
44
44
|
summary: importPlan.summary || null,
|
|
45
45
|
risk_summary: {
|
|
46
46
|
overall_risk: risk.overall_risk,
|
|
@@ -49,7 +49,7 @@ export function buildReviewPacketPayloadForImportPlan({ importPlan, risk }) {
|
|
|
49
49
|
maintained_risk: importPlan.maintained_risk || null
|
|
50
50
|
},
|
|
51
51
|
next_action: importPlan.next_action || null,
|
|
52
|
-
recommended_query_family: recommendedQueryFamilyForAction(importPlan.next_action, "
|
|
52
|
+
recommended_query_family: recommendedQueryFamilyForAction(importPlan.next_action, "extract-adopt"),
|
|
53
53
|
canonical_writes: (importPlan.proposal_surfaces || [])
|
|
54
54
|
.filter((surface) => surface.canonical_rel_path)
|
|
55
55
|
.map((surface) => ({
|
|
@@ -64,9 +64,9 @@ export function buildReviewPacketPayloadForImportPlan({ importPlan, risk }) {
|
|
|
64
64
|
maintained_risk: importPlan.maintained_risk || null,
|
|
65
65
|
maintained_seam_review_summary: importPlan.maintained_seam_review_summary || null,
|
|
66
66
|
operator_loop: buildOperatorLoopSummary({
|
|
67
|
-
mode: "
|
|
67
|
+
mode: "extract-adopt",
|
|
68
68
|
nextAction: importPlan.next_action || null,
|
|
69
|
-
primaryArtifacts: ["
|
|
69
|
+
primaryArtifacts: ["extract-plan", "adoption-plan.agent.json"],
|
|
70
70
|
verificationTargets: importPlan.verification_targets || null,
|
|
71
71
|
currentSurface: "review-packet"
|
|
72
72
|
}),
|
|
@@ -35,7 +35,7 @@ export function stableSortedStrings(values) {
|
|
|
35
35
|
export const CANONICAL_TASK_MODES = new Set([
|
|
36
36
|
"modeling",
|
|
37
37
|
"maintained-app-edit",
|
|
38
|
-
"
|
|
38
|
+
"extract-adopt",
|
|
39
39
|
"diff-review",
|
|
40
40
|
"verification"
|
|
41
41
|
]);
|
|
@@ -59,7 +59,7 @@ export const PROVIDER_PRESET_MANUAL_DECISION_CATEGORIES = new Set([
|
|
|
59
59
|
export const WORKFLOW_QUERY_FAMILIES_BY_MODE = {
|
|
60
60
|
modeling: ["change-plan", "write-scope", "verification-targets", "risk-summary"],
|
|
61
61
|
"maintained-app-edit": ["maintained-boundary", "maintained-conformance", "seam-check", "change-plan"],
|
|
62
|
-
"
|
|
62
|
+
"extract-adopt": ["extract-plan", "risk-summary", "proceed-decision", "review-packet"],
|
|
63
63
|
"diff-review": ["change-plan", "risk-summary", "review-packet"],
|
|
64
64
|
verification: ["verification-targets", "proceed-decision", "risk-summary"]
|
|
65
65
|
};
|
|
@@ -518,7 +518,7 @@ export function buildMultiAgentPlanPayload({
|
|
|
518
518
|
return {
|
|
519
519
|
type: "multi_agent_plan",
|
|
520
520
|
workspace: workspace || null,
|
|
521
|
-
mode: "
|
|
521
|
+
mode: "extract-adopt",
|
|
522
522
|
source_single_agent_plan: singleAgentPlan,
|
|
523
523
|
summary: buildMultiAgentSummary(lanes, parallelWorkstreams, overlapRules, handoffPackets),
|
|
524
524
|
coordination_strategy: {
|
|
@@ -11,7 +11,7 @@ export function outputIdsForWorkflowContext(taskModeArtifact, maintainedBoundary
|
|
|
11
11
|
|
|
12
12
|
export function integrationCategoriesForWorkflowContext(taskModeArtifact, importPlan = null) {
|
|
13
13
|
const categories = [];
|
|
14
|
-
if (taskModeArtifact?.mode === "
|
|
14
|
+
if (taskModeArtifact?.mode === "extract-adopt") categories.push("provider_adoption");
|
|
15
15
|
if (taskModeArtifact?.mode === "maintained-app-edit") categories.push("maintained_app");
|
|
16
16
|
if ((taskModeArtifact?.verification_targets?.maintained_app_checks || []).length > 0) categories.push("maintained_boundary");
|
|
17
17
|
if ((importPlan?.requires_human_review || []).length > 0) categories.push("human_review");
|
|
@@ -43,7 +43,7 @@ export function recommendedQueryFamilyForAction(nextAction, mode = null) {
|
|
|
43
43
|
case "customize_workflow_preset":
|
|
44
44
|
case "refresh_workflow_preset_customization":
|
|
45
45
|
case "import_declared_workflow_preset":
|
|
46
|
-
return "
|
|
46
|
+
return "extract-plan";
|
|
47
47
|
case "review_diff_impact":
|
|
48
48
|
case "inspect_projection":
|
|
49
49
|
case "inspect_diff":
|
|
@@ -61,7 +61,7 @@ export function recommendedQueryFamilyForAction(nextAction, mode = null) {
|
|
|
61
61
|
break;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
if (mode === "
|
|
64
|
+
if (mode === "extract-adopt") return "extract-plan";
|
|
65
65
|
if (mode === "maintained-app-edit") return "maintained-boundary";
|
|
66
66
|
if (mode === "verification") return "verification-targets";
|
|
67
67
|
return "change-plan";
|
|
@@ -268,7 +268,7 @@ export function buildGenericSequence(taskModeArtifact, {
|
|
|
268
268
|
|
|
269
269
|
export function buildRecommendedSequence(taskModeArtifact, importPlan = null) {
|
|
270
270
|
const mode = taskModeArtifact?.mode || null;
|
|
271
|
-
if (mode === "
|
|
271
|
+
if (mode === "extract-adopt") {
|
|
272
272
|
return buildImportAdoptSequence(taskModeArtifact, importPlan);
|
|
273
273
|
}
|
|
274
274
|
if (mode === "maintained-app-edit") {
|
|
@@ -56,7 +56,7 @@ export function buildTopogramSourceStatus(projectRoot) {
|
|
|
56
56
|
severity: "warning",
|
|
57
57
|
message: `${TOPOGRAM_SOURCE_FILE} was not found. This project may not have been copied from a catalog topogram entry.`,
|
|
58
58
|
path: sourcePath,
|
|
59
|
-
suggestedFix: "Run `topogram
|
|
59
|
+
suggestedFix: "Run `topogram copy <id> <target>` to create a project with source provenance."
|
|
60
60
|
}],
|
|
61
61
|
errors: []
|
|
62
62
|
};
|
|
@@ -1 +1,3 @@
|
|
|
1
1
|
export function resolveCatalogTemplateAlias(templateName: string, catalogSource?: string | null): any;
|
|
2
|
+
export function formatCatalogTemplateAliasError(templateName: string, catalogSource: string | null, error: unknown, options?: { suggestions?: string[] }): string;
|
|
3
|
+
export function suggestCatalogTemplateIds(catalog: any, templateName: string): string[];
|
package/src/cli/catalog-alias.js
CHANGED
|
@@ -93,7 +93,7 @@ export function formatCatalogTemplateAliasError(templateName, catalogSource, err
|
|
|
93
93
|
return [
|
|
94
94
|
`Catalog template alias '${templateName}' could not be resolved from '${sourceLabel}'.`,
|
|
95
95
|
reason,
|
|
96
|
-
templateName === "hello-web" ? "The default starter 'hello-web' is catalog-backed. Enable catalog access, or
|
|
96
|
+
templateName === "hello-web" ? "The default starter 'hello-web' is catalog-backed. Enable catalog access, or use `topogram copy <source> <target>` with a local path or full package spec." : null,
|
|
97
97
|
suggestions.length > 0 ? `Suggested templates: ${suggestions.join(", ")}.` : null,
|
|
98
98
|
catalogDisabled ? "Unset TOPOGRAM_CATALOG_SOURCE=none, pass --catalog <source>, or use an explicit local path/package spec." : null,
|
|
99
99
|
"Run `topogram template list` to see available templates, or `topogram catalog show <id>` to inspect a catalog alias.",
|
|
@@ -108,7 +108,7 @@ export function formatCatalogTemplateAliasError(templateName, catalogSource, err
|
|
|
108
108
|
* @param {string} templateName
|
|
109
109
|
* @returns {string[]}
|
|
110
110
|
*/
|
|
111
|
-
function suggestCatalogTemplateIds(catalog, templateName) {
|
|
111
|
+
export function suggestCatalogTemplateIds(catalog, templateName) {
|
|
112
112
|
const queryTokens = tokenizeSuggestionText(templateName);
|
|
113
113
|
const templates = (catalog.entries || []).filter((entry) => entry.kind === "template");
|
|
114
114
|
return templates
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
3
|
import { parseCoreCommandArgs } from "./command-parsers/core.js";
|
|
4
|
+
import { parseExtractorCommandArgs } from "./command-parsers/extractor.js";
|
|
4
5
|
import { parseGeneratorCommandArgs } from "./command-parsers/generator.js";
|
|
5
6
|
import { parseImportCommandArgs } from "./command-parsers/import.js";
|
|
6
7
|
import { parseLegacyWorkflowCommandArgs } from "./command-parsers/legacy-workflow.js";
|
|
@@ -10,6 +11,7 @@ import { parseTemplateCommandArgs } from "./command-parsers/template.js";
|
|
|
10
11
|
|
|
11
12
|
const COMMAND_PARSERS = [
|
|
12
13
|
parseCoreCommandArgs,
|
|
14
|
+
parseExtractorCommandArgs,
|
|
13
15
|
parseGeneratorCommandArgs,
|
|
14
16
|
parseTemplateCommandArgs,
|
|
15
17
|
parseProjectCommandArgs,
|
|
@@ -18,7 +18,7 @@ const QUERY_NAMES = new Set([
|
|
|
18
18
|
"verification-targets",
|
|
19
19
|
"widget-behavior",
|
|
20
20
|
"change-plan",
|
|
21
|
-
"
|
|
21
|
+
"extract-plan",
|
|
22
22
|
"risk-summary",
|
|
23
23
|
"canonical-writes",
|
|
24
24
|
"proceed-decision",
|
|
@@ -42,10 +42,14 @@ const QUERY_NAMES = new Set([
|
|
|
42
42
|
* @returns {import("./shared.js").SplitCommandArgs|null}
|
|
43
43
|
*/
|
|
44
44
|
export function parseCoreCommandArgs(args) {
|
|
45
|
-
if (args[0] === "
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
if (args[0] === "copy") {
|
|
46
|
+
if (args.includes("--list")) {
|
|
47
|
+
return { copyCommand: "list", inputPath: null };
|
|
48
|
+
}
|
|
49
|
+
return { copyCommand: "copy", copySource: args[1], inputPath: args[2] };
|
|
50
|
+
}
|
|
51
|
+
if (args[0] === "init") {
|
|
52
|
+
return { initProject: true, inputPath: commandPath(args, 1, ".") };
|
|
49
53
|
}
|
|
50
54
|
if (args[0] === "generate" && args[1] === "app") {
|
|
51
55
|
return { generateTarget: "app-bundle", write: true, inputPath: commandPath(args, 2), defaultOutDir: "./app" };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { commandPath } from "./shared.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {string[]} args
|
|
7
|
+
* @returns {import("./shared.js").SplitCommandArgs|null}
|
|
8
|
+
*/
|
|
9
|
+
export function parseExtractorCommandArgs(args) {
|
|
10
|
+
if (args[0] === "extractor" && args[1] === "list") {
|
|
11
|
+
return { extractorCommand: "list", inputPath: null };
|
|
12
|
+
}
|
|
13
|
+
if (args[0] === "extractor" && args[1] === "show") {
|
|
14
|
+
return { extractorCommand: "show", inputPath: args[2] };
|
|
15
|
+
}
|
|
16
|
+
if (args[0] === "extractor" && args[1] === "check") {
|
|
17
|
+
return { extractorCommand: "check", inputPath: args[2] };
|
|
18
|
+
}
|
|
19
|
+
if (args[0] === "extractor" && args[1] === "policy" && args[2] === "init") {
|
|
20
|
+
return { extractorPolicyCommand: "init", inputPath: commandPath(args, 3, ".") };
|
|
21
|
+
}
|
|
22
|
+
if (args[0] === "extractor" && args[1] === "policy" && args[2] === "status") {
|
|
23
|
+
return { extractorPolicyCommand: "status", inputPath: commandPath(args, 3, ".") };
|
|
24
|
+
}
|
|
25
|
+
if (args[0] === "extractor" && args[1] === "policy" && args[2] === "check") {
|
|
26
|
+
return { extractorPolicyCommand: "check", inputPath: commandPath(args, 3, ".") };
|
|
27
|
+
}
|
|
28
|
+
if (args[0] === "extractor" && args[1] === "policy" && args[2] === "explain") {
|
|
29
|
+
return { extractorPolicyCommand: "explain", inputPath: commandPath(args, 3, ".") };
|
|
30
|
+
}
|
|
31
|
+
if (args[0] === "extractor" && args[1] === "policy" && args[2] === "pin") {
|
|
32
|
+
return {
|
|
33
|
+
extractorPolicyCommand: "pin",
|
|
34
|
+
extractorPolicyPinSpec: args[3] && !args[3].startsWith("-") ? args[3] : null,
|
|
35
|
+
inputPath: commandPath(args, 4, ".")
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
@@ -7,37 +7,31 @@ import { commandOperandFrom, commandPath } from "./shared.js";
|
|
|
7
7
|
* @returns {import("./shared.js").SplitCommandArgs|null}
|
|
8
8
|
*/
|
|
9
9
|
export function parseImportCommandArgs(args) {
|
|
10
|
-
if (args[0] === "
|
|
11
|
-
return { workflowName: "import-app", inputPath: args[2] };
|
|
12
|
-
}
|
|
13
|
-
if (args[0] === "import" && args[1] === "docs") {
|
|
14
|
-
return { workflowName: "scan-docs", inputPath: args[2] };
|
|
15
|
-
}
|
|
16
|
-
if (args[0] === "import" && args[1] === "diff") {
|
|
10
|
+
if (args[0] === "extract" && args[1] === "diff") {
|
|
17
11
|
return { importCommand: "diff", inputPath: commandOperandFrom(args, 2, ".") };
|
|
18
12
|
}
|
|
19
|
-
if (args[0] === "
|
|
13
|
+
if (args[0] === "extract" && args[1] === "refresh") {
|
|
20
14
|
return { importCommand: "refresh", inputPath: commandOperandFrom(args, 2, ".") };
|
|
21
15
|
}
|
|
22
|
-
if (args[0] === "
|
|
16
|
+
if (args[0] === "extract" && args[1] === "check") {
|
|
23
17
|
return { importCommand: "check", inputPath: commandPath(args, 2, ".") };
|
|
24
18
|
}
|
|
25
|
-
if (args[0] === "
|
|
19
|
+
if (args[0] === "extract" && args[1] === "plan") {
|
|
26
20
|
return { importCommand: "plan", inputPath: commandPath(args, 2, ".") };
|
|
27
21
|
}
|
|
28
|
-
if (args[0] === "
|
|
29
|
-
return { importCommand: "adopt-list", inputPath: commandPath(args,
|
|
22
|
+
if (args[0] === "adopt" && (args[1] === "--list" || args[1] === "list")) {
|
|
23
|
+
return { importCommand: "adopt-list", inputPath: commandPath(args, 2, ".") };
|
|
30
24
|
}
|
|
31
|
-
if (args[0] === "
|
|
32
|
-
return { importCommand: "adopt", importAdoptSelector: args[
|
|
25
|
+
if (args[0] === "adopt") {
|
|
26
|
+
return { importCommand: "adopt", importAdoptSelector: args[1], inputPath: commandPath(args, 2, ".") };
|
|
33
27
|
}
|
|
34
|
-
if (args[0] === "
|
|
28
|
+
if (args[0] === "extract" && args[1] === "status") {
|
|
35
29
|
return { importCommand: "status", inputPath: commandPath(args, 2, ".") };
|
|
36
30
|
}
|
|
37
|
-
if (args[0] === "
|
|
31
|
+
if (args[0] === "extract" && args[1] === "history") {
|
|
38
32
|
return { importCommand: "history", verify: args.includes("--verify"), inputPath: commandOperandFrom(args, 2, ".") };
|
|
39
33
|
}
|
|
40
|
-
if (args[0] === "
|
|
34
|
+
if (args[0] === "extract" && args[1] && !args[1].startsWith("-")) {
|
|
41
35
|
return { importCommand: "workspace", inputPath: args[1] };
|
|
42
36
|
}
|
|
43
37
|
return null;
|
|
@@ -37,9 +37,6 @@ export function parseProjectCommandArgs(args) {
|
|
|
37
37
|
if (args[0] === "catalog" && args[1] === "check") {
|
|
38
38
|
return { catalogCommand: "check", inputPath: args[2] };
|
|
39
39
|
}
|
|
40
|
-
if (args[0] === "catalog" && args[1] === "copy") {
|
|
41
|
-
return { catalogCommand: "copy", catalogId: args[2], inputPath: args[3] };
|
|
42
|
-
}
|
|
43
40
|
if (args[0] === "package" && args[1] === "update-cli") {
|
|
44
41
|
return { packageCommand: "update-cli", inputPath: args.includes("--latest") ? "latest" : args[2] };
|
|
45
42
|
}
|
|
@@ -18,10 +18,10 @@ import { shellCommandArg } from "./shared.js";
|
|
|
18
18
|
*/
|
|
19
19
|
export function buildCatalogCopyPayload(id, targetPath, options) {
|
|
20
20
|
if (!id || id.startsWith("-")) {
|
|
21
|
-
throw new Error("topogram
|
|
21
|
+
throw new Error("topogram copy requires <source>.");
|
|
22
22
|
}
|
|
23
23
|
if (!targetPath || targetPath.startsWith("-")) {
|
|
24
|
-
throw new Error("topogram
|
|
24
|
+
throw new Error("topogram copy requires <target>.");
|
|
25
25
|
}
|
|
26
26
|
const loaded = loadCatalog(options.source || null);
|
|
27
27
|
const entry = findCatalogEntry(loaded.catalog, id, "topogram");
|
|
@@ -49,7 +49,7 @@ export function printCatalogCopy(payload) {
|
|
|
49
49
|
console.log(`Package: ${payload.packageSpec}`);
|
|
50
50
|
console.log(`Source provenance: ${payload.provenancePath}`);
|
|
51
51
|
console.log(`Files: ${payload.files.length}`);
|
|
52
|
-
console.log(`${TOPOGRAM_SOURCE_FILE} records
|
|
52
|
+
console.log(`${TOPOGRAM_SOURCE_FILE} records copy provenance only. Local edits are allowed.`);
|
|
53
53
|
console.log("");
|
|
54
54
|
console.log("Next steps:");
|
|
55
55
|
console.log(` cd ${shellCommandArg(path.relative(process.cwd(), payload.targetPath) || ".")}`);
|
|
@@ -8,7 +8,6 @@ export function printCatalogHelp() {
|
|
|
8
8
|
console.log(" or: topogram catalog show <id> [--json] [--catalog <path-or-source>]");
|
|
9
9
|
console.log(" or: topogram catalog doctor [--json] [--catalog <path-or-source>]");
|
|
10
10
|
console.log(" or: topogram catalog check <path-or-url> [--json]");
|
|
11
|
-
console.log(" or: topogram catalog copy <id> <target> [--version <version>] [--json] [--catalog <path-or-source>]");
|
|
12
11
|
console.log("");
|
|
13
12
|
console.log("Catalog commands inspect the shared Topogram index. The catalog is an index; templates and topograms resolve to versioned packages.");
|
|
14
13
|
console.log("");
|
|
@@ -17,5 +16,5 @@ export function printCatalogHelp() {
|
|
|
17
16
|
console.log(" topogram catalog show hello-web");
|
|
18
17
|
console.log(" topogram catalog doctor");
|
|
19
18
|
console.log(" topogram catalog check topograms.catalog.json");
|
|
20
|
-
console.log(" topogram
|
|
19
|
+
console.log(" topogram copy hello ./hello-topogram");
|
|
21
20
|
}
|
|
@@ -8,7 +8,7 @@ import { shellCommandArg } from "./shared.js";
|
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* @param {string|null} source
|
|
11
|
-
* @returns {{ ok: boolean, source: string, catalog: any, entries: any[], diagnostics: any[], errors: string[] }}
|
|
11
|
+
* @returns {{ ok: boolean, source: string, catalog: any, entries: any[], templates: any[], topograms: any[], diagnostics: any[], errors: string[] }}
|
|
12
12
|
*/
|
|
13
13
|
export function buildCatalogListPayload(source) {
|
|
14
14
|
const loaded = loadCatalog(source || null);
|
|
@@ -16,10 +16,13 @@ export function buildCatalogListPayload(source) {
|
|
|
16
16
|
ok: true,
|
|
17
17
|
source: loaded.source,
|
|
18
18
|
catalog: {
|
|
19
|
+
loaded: true,
|
|
19
20
|
version: loaded.catalog.version,
|
|
20
21
|
entries: loaded.catalog.entries.length
|
|
21
22
|
},
|
|
22
23
|
entries: loaded.catalog.entries,
|
|
24
|
+
templates: loaded.catalog.entries.filter((/** @type {any} */ entry) => entry.kind === "template"),
|
|
25
|
+
topograms: loaded.catalog.entries.filter((/** @type {any} */ entry) => entry.kind === "topogram"),
|
|
23
26
|
diagnostics: loaded.diagnostics,
|
|
24
27
|
errors: []
|
|
25
28
|
};
|
|
@@ -31,7 +34,7 @@ export function buildCatalogListPayload(source) {
|
|
|
31
34
|
*/
|
|
32
35
|
export function printCatalogList(payload) {
|
|
33
36
|
console.log("Catalog entries:");
|
|
34
|
-
console.log("Template entries create starters with `topogram
|
|
37
|
+
console.log("Template entries create starters with `topogram copy`; topogram entries copy editable Topogram source.");
|
|
35
38
|
console.log(`Catalog: ${payload.source}`);
|
|
36
39
|
console.log(`Version: ${payload.catalog.version}`);
|
|
37
40
|
const catalogOption = payload.source === catalogSourceOrDefault(null)
|
|
@@ -44,9 +47,9 @@ export function printCatalogList(payload) {
|
|
|
44
47
|
console.log(` Trust scope: ${entry.trust.scope}`);
|
|
45
48
|
console.log(` Executable implementation: ${entry.trust.includesExecutableImplementation ? "yes" : "no"}`);
|
|
46
49
|
if (entry.kind === "template") {
|
|
47
|
-
console.log(`
|
|
50
|
+
console.log(` Copy: topogram copy ${shellCommandArg(entry.id)} ./my-app${catalogOption}`);
|
|
48
51
|
} else {
|
|
49
|
-
console.log(` Copy: topogram
|
|
52
|
+
console.log(` Copy: topogram copy ${shellCommandArg(entry.id)} ./${entry.id}-topogram${catalogOption}`);
|
|
50
53
|
}
|
|
51
54
|
}
|
|
52
55
|
}
|
|
@@ -63,7 +63,7 @@ export function catalogShowCommands(entry, source) {
|
|
|
63
63
|
if (entry.kind === "template") {
|
|
64
64
|
const target = "./my-app";
|
|
65
65
|
return {
|
|
66
|
-
primary: `topogram
|
|
66
|
+
primary: `topogram copy ${shellCommandArg(entry.id)} ${target}${catalogOption}`,
|
|
67
67
|
followUp: [
|
|
68
68
|
`cd ${target}`,
|
|
69
69
|
"npm install",
|
|
@@ -74,7 +74,7 @@ export function catalogShowCommands(entry, source) {
|
|
|
74
74
|
}
|
|
75
75
|
const target = `./${entry.id}-topogram`;
|
|
76
76
|
return {
|
|
77
|
-
primary: `topogram
|
|
77
|
+
primary: `topogram copy ${shellCommandArg(entry.id)} ${target}${catalogOption}`,
|
|
78
78
|
followUp: [
|
|
79
79
|
`cd ${target}`,
|
|
80
80
|
"topogram source status --local",
|
|
@@ -102,9 +102,9 @@ export function printCatalogShow(payload) {
|
|
|
102
102
|
console.log(`Catalog entry: ${entry.id}`);
|
|
103
103
|
console.log(`Kind: ${entry.kind}`);
|
|
104
104
|
if (entry.kind === "template") {
|
|
105
|
-
console.log("Action: creates a starter app workspace with `topogram
|
|
105
|
+
console.log("Action: creates a starter app workspace with `topogram copy`.");
|
|
106
106
|
} else {
|
|
107
|
-
console.log("Action: copies editable Topogram source with `topogram
|
|
107
|
+
console.log("Action: copies editable Topogram source with `topogram copy`.");
|
|
108
108
|
console.log("Executable implementation: no (topogram entries cannot include implementation/ in v1).");
|
|
109
109
|
}
|
|
110
110
|
console.log(`Catalog: ${payload.source}`);
|