@ductape/cli 0.2.23 → 0.3.0

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 (101) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +7 -0
  3. package/dist/commands/migrate-codebase.d.ts +176 -0
  4. package/dist/commands/migrate-codebase.js +753 -0
  5. package/dist/commands/migration-artifact.d.ts +32 -0
  6. package/dist/commands/migration-artifact.js +48 -0
  7. package/dist/commands/migration-assurance.d.ts +10 -0
  8. package/dist/commands/migration-assurance.js +120 -0
  9. package/dist/commands/migration-database.d.ts +21 -0
  10. package/dist/commands/migration-database.js +162 -0
  11. package/dist/commands/migration-e2e.d.ts +68 -0
  12. package/dist/commands/migration-e2e.js +189 -0
  13. package/dist/commands/migration-environments.d.ts +20 -0
  14. package/dist/commands/migration-environments.js +58 -0
  15. package/dist/commands/migration-generated.d.ts +68 -0
  16. package/dist/commands/migration-generated.js +217 -0
  17. package/dist/commands/migration-portfolio.d.ts +88 -0
  18. package/dist/commands/migration-portfolio.js +223 -0
  19. package/dist/commands/migration-products.d.ts +23 -0
  20. package/dist/commands/migration-products.js +88 -0
  21. package/dist/commands/migration-review.d.ts +248 -0
  22. package/dist/commands/migration-review.js +624 -0
  23. package/dist/commands/migration-secrets.d.ts +24 -0
  24. package/dist/commands/migration-secrets.js +93 -0
  25. package/dist/commands/migration-slice.d.ts +132 -0
  26. package/dist/commands/migration-slice.js +266 -0
  27. package/dist/commands/migration-verification.d.ts +12 -0
  28. package/dist/commands/migration-verification.js +194 -0
  29. package/dist/commands/products.d.ts +1 -0
  30. package/dist/commands/products.js +33 -1
  31. package/dist/commands/secrets.d.ts +8 -0
  32. package/dist/commands/secrets.js +44 -0
  33. package/dist/index.js +354 -2
  34. package/dist/lib/migration-artifact.d.ts +13 -0
  35. package/dist/lib/migration-artifact.js +103 -0
  36. package/package.json +8 -1
  37. package/API_PARITY.md +0 -58
  38. package/DB_MIGRATE_PLAN.md +0 -223
  39. package/ductape.example.ts +0 -18
  40. package/src/commands/apply.ts +0 -153
  41. package/src/commands/apps-import.ts +0 -43
  42. package/src/commands/apps.ts +0 -92
  43. package/src/commands/cloud.ts +0 -68
  44. package/src/commands/completion.ts +0 -119
  45. package/src/commands/db-migrate.ts +0 -209
  46. package/src/commands/db-schema.ts +0 -429
  47. package/src/commands/db.ts +0 -63
  48. package/src/commands/generate.ts +0 -74
  49. package/src/commands/graph.ts +0 -51
  50. package/src/commands/init.ts +0 -39
  51. package/src/commands/install.ts +0 -76
  52. package/src/commands/link.ts +0 -84
  53. package/src/commands/login.ts +0 -145
  54. package/src/commands/logout.ts +0 -7
  55. package/src/commands/platform.ts +0 -123
  56. package/src/commands/products.ts +0 -228
  57. package/src/commands/profiles.ts +0 -23
  58. package/src/commands/resources.ts +0 -213
  59. package/src/commands/secrets.ts +0 -46
  60. package/src/commands/unlink.ts +0 -15
  61. package/src/commands/whoami.ts +0 -27
  62. package/src/commands/workspaces.ts +0 -98
  63. package/src/index.ts +0 -523
  64. package/src/lib/api-client.ts +0 -88
  65. package/src/lib/app-import.ts +0 -82
  66. package/src/lib/apply-loaders.ts +0 -30
  67. package/src/lib/config.ts +0 -230
  68. package/src/lib/context-store.ts +0 -77
  69. package/src/lib/db-methods.ts +0 -56
  70. package/src/lib/db-types.ts +0 -104
  71. package/src/lib/encryption.ts +0 -12
  72. package/src/lib/forms/enums.ts +0 -52
  73. package/src/lib/forms/index.ts +0 -8
  74. package/src/lib/forms/prompt.ts +0 -209
  75. package/src/lib/forms/schemas.ts +0 -288
  76. package/src/lib/forms/types.ts +0 -27
  77. package/src/lib/http.ts +0 -76
  78. package/src/lib/integrations.ts +0 -110
  79. package/src/lib/interactive-opts.ts +0 -13
  80. package/src/lib/migration-files.ts +0 -58
  81. package/src/lib/output.ts +0 -39
  82. package/src/lib/platform-api.ts +0 -209
  83. package/src/lib/proxy/context.ts +0 -94
  84. package/src/lib/proxy/db-proxy.ts +0 -40
  85. package/src/lib/proxy/graph-proxy.ts +0 -64
  86. package/src/lib/proxy/sdk-proxy.ts +0 -58
  87. package/src/lib/read-body.ts +0 -57
  88. package/src/lib/resources.ts +0 -160
  89. package/src/lib/schema-loader.ts +0 -152
  90. package/src/lib/snippets.ts +0 -165
  91. package/src/lib/templates.ts +0 -157
  92. package/src/lib/workspace-context.ts +0 -43
  93. package/src/lib/workspaces.ts +0 -283
  94. package/test/apply-loaders.test.ts +0 -40
  95. package/test/encryption.test.ts +0 -20
  96. package/test/forms.test.ts +0 -25
  97. package/test/http.test.ts +0 -15
  98. package/test/platform-api.test.ts +0 -42
  99. package/test/resources.test.ts +0 -23
  100. package/test/workspace-resolve.test.ts +0 -29
  101. package/tsconfig.json +0 -15
@@ -0,0 +1,23 @@
1
+ export declare function initializeProductMap(opts: {
2
+ analysis: string;
3
+ definition: string;
4
+ output: string;
5
+ }): {
6
+ path: string;
7
+ };
8
+ export declare function validateProductMap(file: string): {
9
+ artifact: string;
10
+ ready: boolean;
11
+ blockers: string[];
12
+ };
13
+ export declare function runMigrationProductsInit(opts: {
14
+ analysis: string;
15
+ definition: string;
16
+ output: string;
17
+ json?: boolean;
18
+ }): void;
19
+ export declare function runMigrationProductsValidate(opts: {
20
+ file: string;
21
+ strict?: boolean;
22
+ json?: boolean;
23
+ }): void;
@@ -0,0 +1,88 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { printJson } from '../lib/output.js';
4
+ import { readMigrationJson, writeMigrationJson } from '../lib/migration-artifact.js';
5
+ function read(file) {
6
+ return readMigrationJson(file);
7
+ }
8
+ export function initializeProductMap(opts) {
9
+ const analysisPath = path.resolve(opts.analysis);
10
+ const definition = read(opts.definition);
11
+ if (!Array.isArray(definition.mappings) || !Array.isArray(definition.assets) ||
12
+ !Array.isArray(definition.promotions)) {
13
+ throw new Error('Definition requires mappings, assets, and promotions arrays.');
14
+ }
15
+ const artifact = {
16
+ version: 1,
17
+ artifact_kind: 'ductape_service_product_map',
18
+ analysis: analysisPath,
19
+ ...definition,
20
+ };
21
+ const output = path.resolve(opts.output);
22
+ if (fs.existsSync(output))
23
+ throw new Error(`Service-to-product map already exists: ${output}`);
24
+ fs.mkdirSync(path.dirname(output), { recursive: true });
25
+ writeMigrationJson(output, artifact, { createOnly: true });
26
+ return { path: output };
27
+ }
28
+ export function validateProductMap(file) {
29
+ const resolved = path.resolve(file);
30
+ const artifact = read(resolved);
31
+ if (artifact.artifact_kind !== 'ductape_service_product_map')
32
+ throw new Error('Invalid service-to-product map.');
33
+ const analysis = read(artifact.analysis);
34
+ const blockers = [];
35
+ const assignment = new Map();
36
+ for (const mapping of artifact.mappings) {
37
+ if (!mapping.service || !mapping.product_tag || !mapping.environments.length || !mapping.evidence) {
38
+ blockers.push(`mapping ${mapping.service || '<unknown>'}: service, product, environments, and evidence are required`);
39
+ }
40
+ for (const manifest of mapping.manifests) {
41
+ assignment.set(manifest, [...(assignment.get(manifest) ?? []), mapping.service]);
42
+ }
43
+ }
44
+ for (const unit of analysis.workspace_units ?? []) {
45
+ const owners = assignment.get(unit.manifest) ?? [];
46
+ if (owners.length === 0)
47
+ blockers.push(`workspace unit is unmapped: ${unit.manifest}`);
48
+ if (owners.length > 1)
49
+ blockers.push(`workspace unit has multiple service owners: ${unit.manifest}`);
50
+ }
51
+ for (const manifest of assignment.keys()) {
52
+ if (!(analysis.workspace_units ?? []).some((unit) => unit.manifest === manifest)) {
53
+ blockers.push(`mapping references unknown workspace unit: ${manifest}`);
54
+ }
55
+ }
56
+ for (const asset of artifact.assets) {
57
+ if (!asset.kind || !asset.tag || !asset.product_tag || !asset.inventory_evidence) {
58
+ blockers.push(`asset ${asset.tag || '<unknown>'}: identity and inventory evidence are required`);
59
+ }
60
+ for (const environment of asset.required_environments) {
61
+ if (!asset.configured_environments.includes(environment)) {
62
+ blockers.push(`asset ${asset.kind}:${asset.tag} missing environment configuration: ${environment}`);
63
+ }
64
+ }
65
+ }
66
+ for (const promotion of artifact.promotions) {
67
+ if (!promotion.product_tag || !promotion.from || !promotion.to ||
68
+ !promotion.entry_conditions.length || !promotion.validation.length || !promotion.rollback.length) {
69
+ blockers.push(`promotion ${promotion.from || '?'} -> ${promotion.to || '?'} is incomplete`);
70
+ }
71
+ }
72
+ const mappedProducts = new Set(artifact.mappings.map((mapping) => mapping.product_tag));
73
+ for (const product of mappedProducts) {
74
+ if (!artifact.promotions.some((promotion) => promotion.product_tag === product)) {
75
+ blockers.push(`product has no promotion plan: ${product}`);
76
+ }
77
+ }
78
+ return { artifact: resolved, ready: blockers.length === 0, blockers };
79
+ }
80
+ export function runMigrationProductsInit(opts) {
81
+ printJson(initializeProductMap(opts), Boolean(opts.json));
82
+ }
83
+ export function runMigrationProductsValidate(opts) {
84
+ const result = validateProductMap(opts.file);
85
+ printJson(result, Boolean(opts.json));
86
+ if (opts.strict && !result.ready)
87
+ throw new Error('Service-to-product mapping is not ready.');
88
+ }
@@ -0,0 +1,248 @@
1
+ type ReviewStatus = 'pending' | 'reviewed' | 'excluded';
2
+ type ParityStatus = 'pending' | 'verified' | 'not_applicable';
3
+ type ReferenceKind = 'import' | 'caller' | 'callee' | 'implements' | 'event' | 'test' | 'config' | 'schema';
4
+ interface ParityEvidence {
5
+ status: ParityStatus;
6
+ evidence: string[];
7
+ reason?: string;
8
+ }
9
+ interface ReviewEntry {
10
+ file: string;
11
+ status: ReviewStatus;
12
+ safety: 'names_only' | 'normal';
13
+ baseline_checksum: string | null;
14
+ reviewed_checksum: string | null;
15
+ purpose: string;
16
+ dependencies: string[];
17
+ follow_up_files: string[];
18
+ references: Array<{
19
+ kind: ReferenceKind;
20
+ target: string;
21
+ external: boolean;
22
+ evidence: string;
23
+ }>;
24
+ interfaces: string[];
25
+ findings: Array<{
26
+ kind: string;
27
+ evidence: string;
28
+ location: {
29
+ start_line: number;
30
+ end_line: number;
31
+ };
32
+ symbol: {
33
+ kind: 'module' | 'class' | 'interface' | 'function' | 'method' | 'field' | 'route' | 'event' | 'schema' | 'other';
34
+ name: string;
35
+ qualified_name?: string;
36
+ };
37
+ classification: 'observed' | 'inferred' | 'proposed' | 'confirmed';
38
+ confidence: 'low' | 'medium' | 'high';
39
+ requires_followup: string[];
40
+ }>;
41
+ exclusion_reason?: string;
42
+ exclusion?: {
43
+ classification: 'generated' | 'vendor' | 'build' | 'snapshot' | 'other';
44
+ reason: string;
45
+ owner?: string;
46
+ generator?: string;
47
+ regeneration_test?: string;
48
+ };
49
+ interface_parity: ParityEvidence;
50
+ functional_parity: ParityEvidence;
51
+ operational_parity: ParityEvidence;
52
+ }
53
+ interface ReviewLedger {
54
+ version: 1;
55
+ artifact_kind: 'ai_migration_review_ledger';
56
+ source: string;
57
+ created_at: string;
58
+ revision: number;
59
+ events: Array<{
60
+ revision: number;
61
+ timestamp: string;
62
+ actor: string;
63
+ tool: '@ductape/cli';
64
+ tool_version: string;
65
+ operation: string;
66
+ state_hash: string;
67
+ previous_hash: string | null;
68
+ hash: string;
69
+ }>;
70
+ entries: ReviewEntry[];
71
+ }
72
+ interface LedgerSignature {
73
+ version: 1;
74
+ artifact_kind: 'ductape_review_ledger_signature';
75
+ ledger: string;
76
+ ledger_checksum: string;
77
+ key_id: string;
78
+ algorithm: 'Ed25519';
79
+ signed_at: string;
80
+ signature: string;
81
+ }
82
+ export declare function initializeReviewLedger(analysisPath: string, ledgerPath?: string): {
83
+ ledger: ReviewLedger;
84
+ path: string;
85
+ };
86
+ export declare function validateReviewLedger(ledgerPath: string): {
87
+ ledger: string;
88
+ source: string;
89
+ ready: boolean;
90
+ coverage: {
91
+ total: number;
92
+ reviewed: number;
93
+ excluded: number;
94
+ pending: number;
95
+ percent: number;
96
+ };
97
+ blockers: {
98
+ pending: string[];
99
+ stale: string[];
100
+ invalid_exclusions: string[];
101
+ invalid_generated_exclusions: string[];
102
+ missing_follow_ups: {
103
+ file: string;
104
+ follow_up: string;
105
+ }[];
106
+ uncovered_references: {
107
+ file: string;
108
+ kind: ReferenceKind;
109
+ target: string;
110
+ }[];
111
+ missing_finding_provenance: {
112
+ file: string;
113
+ finding: number;
114
+ }[];
115
+ missing_symbol_provenance: {
116
+ file: string;
117
+ finding: number;
118
+ }[];
119
+ probable_moves: {
120
+ from: string;
121
+ candidates: string[];
122
+ }[];
123
+ invalidated_dependents: string[];
124
+ audit_errors: string[];
125
+ missing_context: string[];
126
+ incomplete_parity: {
127
+ file: string;
128
+ concern: string;
129
+ }[];
130
+ };
131
+ };
132
+ export declare function snapshotReviewedFile(ledgerPath: string, file: string): ReviewEntry;
133
+ export declare function recordReviewContext(ledgerPath: string, file: string, dataPath: string): ReviewEntry;
134
+ export declare function addFollowUpFile(ledgerPath: string, fromFile: string, followUpFile: string): ReviewEntry;
135
+ export declare function excludeReviewFile(ledgerPath: string, file: string, exclusion: NonNullable<ReviewEntry['exclusion']>): ReviewEntry;
136
+ export declare function setParityEvidence(ledgerPath: string, file: string, concern: 'interface' | 'functional' | 'operational', status: Exclude<ParityStatus, 'pending'>, evidence?: string, reason?: string): ReviewEntry;
137
+ export declare function reopenReviewFile(ledgerPath: string, file: string): ReviewEntry;
138
+ export declare function moveReviewedFile(ledgerPath: string, from: string, to: string): ReviewEntry;
139
+ export declare function signReviewLedger(opts: {
140
+ ledger: string;
141
+ privateKey: string;
142
+ keyId: string;
143
+ output?: string;
144
+ }): {
145
+ path: string;
146
+ signature: LedgerSignature;
147
+ };
148
+ export declare function verifyReviewLedgerSignature(opts: {
149
+ ledger: string;
150
+ signature: string;
151
+ publicKey: string;
152
+ }): {
153
+ ledger: string;
154
+ key_id: string;
155
+ valid: boolean;
156
+ };
157
+ export declare function mergeReviewLedgers(opts: {
158
+ base: string;
159
+ current: string;
160
+ incoming: string;
161
+ output: string;
162
+ }): {
163
+ merged: boolean;
164
+ conflicts: string[];
165
+ output: null;
166
+ } | {
167
+ merged: boolean;
168
+ conflicts: never[];
169
+ output: string;
170
+ };
171
+ export declare function runMigrationReviewInit(opts: {
172
+ analysis: string;
173
+ output?: string;
174
+ json?: boolean;
175
+ }): void;
176
+ export declare function runMigrationReviewValidate(opts: {
177
+ ledger: string;
178
+ strict?: boolean;
179
+ json?: boolean;
180
+ }): void;
181
+ export declare function runMigrationReviewSnapshot(opts: {
182
+ ledger: string;
183
+ file: string;
184
+ json?: boolean;
185
+ }): void;
186
+ export declare function runMigrationReviewRecord(opts: {
187
+ ledger: string;
188
+ file: string;
189
+ data: string;
190
+ json?: boolean;
191
+ }): void;
192
+ export declare function runMigrationReviewFollowUp(opts: {
193
+ ledger: string;
194
+ file: string;
195
+ followUp: string;
196
+ json?: boolean;
197
+ }): void;
198
+ export declare function runMigrationReviewExclude(opts: {
199
+ ledger: string;
200
+ file: string;
201
+ classification: NonNullable<ReviewEntry['exclusion']>['classification'];
202
+ reason: string;
203
+ owner?: string;
204
+ generator?: string;
205
+ regenerationTest?: string;
206
+ json?: boolean;
207
+ }): void;
208
+ export declare function runMigrationReviewParity(opts: {
209
+ ledger: string;
210
+ file: string;
211
+ concern: 'interface' | 'functional' | 'operational';
212
+ status: 'verified' | 'not_applicable';
213
+ evidence?: string;
214
+ reason?: string;
215
+ json?: boolean;
216
+ }): void;
217
+ export declare function runMigrationReviewReopen(opts: {
218
+ ledger: string;
219
+ file: string;
220
+ json?: boolean;
221
+ }): void;
222
+ export declare function runMigrationReviewMove(opts: {
223
+ ledger: string;
224
+ from: string;
225
+ to: string;
226
+ json?: boolean;
227
+ }): void;
228
+ export declare function runMigrationReviewSign(opts: {
229
+ ledger: string;
230
+ privateKey: string;
231
+ keyId: string;
232
+ output?: string;
233
+ json?: boolean;
234
+ }): void;
235
+ export declare function runMigrationReviewVerifySignature(opts: {
236
+ ledger: string;
237
+ signature: string;
238
+ publicKey: string;
239
+ json?: boolean;
240
+ }): void;
241
+ export declare function runMigrationReviewMerge(opts: {
242
+ base: string;
243
+ current: string;
244
+ incoming: string;
245
+ output: string;
246
+ json?: boolean;
247
+ }): void;
248
+ export {};