@objectstack/cli 4.0.4 → 4.1.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 (269) hide show
  1. package/README.md +44 -25
  2. package/dist/commands/build.d.ts +5 -0
  3. package/dist/commands/build.d.ts.map +1 -0
  4. package/dist/commands/build.js +6 -0
  5. package/dist/commands/build.js.map +1 -0
  6. package/dist/commands/cloud/login.d.ts +16 -0
  7. package/dist/commands/cloud/login.d.ts.map +1 -0
  8. package/dist/commands/cloud/login.js +166 -0
  9. package/dist/commands/cloud/login.js.map +1 -0
  10. package/dist/commands/cloud/logout.d.ts +15 -0
  11. package/dist/commands/cloud/logout.d.ts.map +1 -0
  12. package/dist/commands/cloud/logout.js +51 -0
  13. package/dist/commands/cloud/logout.js.map +1 -0
  14. package/dist/commands/cloud/whoami.d.ts +15 -0
  15. package/dist/commands/cloud/whoami.d.ts.map +1 -0
  16. package/dist/commands/cloud/whoami.js +81 -0
  17. package/dist/commands/cloud/whoami.js.map +1 -0
  18. package/dist/commands/compile.d.ts +3 -0
  19. package/dist/commands/compile.d.ts.map +1 -1
  20. package/dist/commands/compile.js +128 -6
  21. package/dist/commands/compile.js.map +1 -1
  22. package/dist/commands/create.js +1 -1
  23. package/dist/commands/data/create.js +2 -2
  24. package/dist/commands/data/create.js.map +1 -1
  25. package/dist/commands/data/delete.js +2 -2
  26. package/dist/commands/data/delete.js.map +1 -1
  27. package/dist/commands/data/get.js +2 -2
  28. package/dist/commands/data/get.js.map +1 -1
  29. package/dist/commands/data/query.js +2 -2
  30. package/dist/commands/data/query.js.map +1 -1
  31. package/dist/commands/data/update.js +2 -2
  32. package/dist/commands/data/update.js.map +1 -1
  33. package/dist/commands/dev.d.ts +9 -0
  34. package/dist/commands/dev.d.ts.map +1 -1
  35. package/dist/commands/dev.js +116 -22
  36. package/dist/commands/dev.js.map +1 -1
  37. package/dist/commands/generate.js +9 -9
  38. package/dist/commands/generate.js.map +1 -1
  39. package/dist/commands/i18n/check.d.ts +18 -0
  40. package/dist/commands/i18n/check.d.ts.map +1 -0
  41. package/dist/commands/i18n/check.js +153 -0
  42. package/dist/commands/i18n/check.js.map +1 -0
  43. package/dist/commands/init.js +2 -2
  44. package/dist/commands/lint.d.ts +3 -0
  45. package/dist/commands/lint.d.ts.map +1 -1
  46. package/dist/commands/lint.js +24 -0
  47. package/dist/commands/lint.js.map +1 -1
  48. package/dist/commands/login.d.ts +17 -0
  49. package/dist/commands/login.d.ts.map +1 -0
  50. package/dist/commands/login.js +313 -0
  51. package/dist/commands/login.js.map +1 -0
  52. package/dist/commands/logout.d.ts.map +1 -0
  53. package/dist/commands/{auth/logout.js → logout.js} +14 -2
  54. package/dist/commands/logout.js.map +1 -0
  55. package/dist/commands/meta/delete.js +2 -2
  56. package/dist/commands/meta/delete.js.map +1 -1
  57. package/dist/commands/meta/get.js +2 -2
  58. package/dist/commands/meta/get.js.map +1 -1
  59. package/dist/commands/meta/list.js +2 -2
  60. package/dist/commands/meta/list.js.map +1 -1
  61. package/dist/commands/meta/register.js +2 -2
  62. package/dist/commands/meta/register.js.map +1 -1
  63. package/dist/commands/package/publish.d.ts +32 -0
  64. package/dist/commands/package/publish.d.ts.map +1 -0
  65. package/dist/commands/package/publish.js +324 -0
  66. package/dist/commands/package/publish.js.map +1 -0
  67. package/dist/commands/projects/bind.d.ts +30 -0
  68. package/dist/commands/projects/bind.d.ts.map +1 -0
  69. package/dist/commands/projects/bind.js +132 -0
  70. package/dist/commands/projects/bind.js.map +1 -0
  71. package/dist/commands/projects/create.d.ts +28 -0
  72. package/dist/commands/projects/create.d.ts.map +1 -0
  73. package/dist/commands/projects/create.js +120 -0
  74. package/dist/commands/projects/create.js.map +1 -0
  75. package/dist/commands/projects/list.d.ts +21 -0
  76. package/dist/commands/projects/list.d.ts.map +1 -0
  77. package/dist/commands/projects/list.js +79 -0
  78. package/dist/commands/projects/list.js.map +1 -0
  79. package/dist/commands/projects/projects.test.d.ts +2 -0
  80. package/dist/commands/projects/projects.test.d.ts.map +1 -0
  81. package/dist/commands/projects/projects.test.js +56 -0
  82. package/dist/commands/projects/projects.test.js.map +1 -0
  83. package/dist/commands/projects/show.d.ts +21 -0
  84. package/dist/commands/projects/show.d.ts.map +1 -0
  85. package/dist/commands/projects/show.js +72 -0
  86. package/dist/commands/projects/show.js.map +1 -0
  87. package/dist/commands/projects/switch.d.ts +24 -0
  88. package/dist/commands/projects/switch.d.ts.map +1 -0
  89. package/dist/commands/projects/switch.js +64 -0
  90. package/dist/commands/projects/switch.js.map +1 -0
  91. package/dist/commands/publish.d.ts +17 -0
  92. package/dist/commands/publish.d.ts.map +1 -0
  93. package/dist/commands/publish.js +135 -0
  94. package/dist/commands/publish.js.map +1 -0
  95. package/dist/commands/{auth/login.d.ts → register.d.ts} +3 -2
  96. package/dist/commands/register.d.ts.map +1 -0
  97. package/dist/commands/{auth/login.js → register.js} +44 -61
  98. package/dist/commands/register.js.map +1 -0
  99. package/dist/commands/rollback.d.ts +13 -0
  100. package/dist/commands/rollback.d.ts.map +1 -0
  101. package/dist/commands/rollback.js +77 -0
  102. package/dist/commands/rollback.js.map +1 -0
  103. package/dist/commands/serve.d.ts +22 -0
  104. package/dist/commands/serve.d.ts.map +1 -1
  105. package/dist/commands/serve.js +1173 -58
  106. package/dist/commands/serve.js.map +1 -1
  107. package/dist/commands/start.d.ts +18 -0
  108. package/dist/commands/start.d.ts.map +1 -0
  109. package/dist/commands/start.js +112 -0
  110. package/dist/commands/start.js.map +1 -0
  111. package/dist/commands/whoami.d.ts.map +1 -0
  112. package/dist/commands/{auth/whoami.js → whoami.js} +5 -5
  113. package/dist/commands/whoami.js.map +1 -0
  114. package/dist/index.d.ts +11 -4
  115. package/dist/index.d.ts.map +1 -1
  116. package/dist/index.js +14 -5
  117. package/dist/index.js.map +1 -1
  118. package/dist/utils/account.d.ts +31 -0
  119. package/dist/utils/account.d.ts.map +1 -0
  120. package/dist/utils/account.js +154 -0
  121. package/dist/utils/account.js.map +1 -0
  122. package/dist/utils/api-client.d.ts +10 -4
  123. package/dist/utils/api-client.d.ts.map +1 -1
  124. package/dist/utils/api-client.js +13 -7
  125. package/dist/utils/api-client.js.map +1 -1
  126. package/dist/utils/auth-config.d.ts +6 -0
  127. package/dist/utils/auth-config.d.ts.map +1 -1
  128. package/dist/utils/auth-config.js.map +1 -1
  129. package/dist/utils/auth-flows.d.ts +31 -0
  130. package/dist/utils/auth-flows.d.ts.map +1 -0
  131. package/dist/utils/auth-flows.js +151 -0
  132. package/dist/utils/auth-flows.js.map +1 -0
  133. package/dist/utils/build-runtime.d.ts +45 -0
  134. package/dist/utils/build-runtime.d.ts.map +1 -0
  135. package/dist/utils/build-runtime.js +154 -0
  136. package/dist/utils/build-runtime.js.map +1 -0
  137. package/dist/utils/cloud-config.d.ts +24 -0
  138. package/dist/utils/cloud-config.d.ts.map +1 -0
  139. package/dist/utils/cloud-config.js +75 -0
  140. package/dist/utils/cloud-config.js.map +1 -0
  141. package/dist/utils/config.d.ts.map +1 -1
  142. package/dist/utils/config.js +17 -2
  143. package/dist/utils/config.js.map +1 -1
  144. package/dist/utils/console.d.ts +33 -0
  145. package/dist/utils/console.d.ts.map +1 -0
  146. package/dist/utils/console.js +172 -0
  147. package/dist/utils/console.js.map +1 -0
  148. package/dist/utils/extract-hook-body.d.ts +13 -0
  149. package/dist/utils/extract-hook-body.d.ts.map +1 -0
  150. package/dist/utils/extract-hook-body.js +175 -0
  151. package/dist/utils/extract-hook-body.js.map +1 -0
  152. package/dist/utils/format.d.ts +8 -0
  153. package/dist/utils/format.d.ts.map +1 -1
  154. package/dist/utils/format.js +15 -2
  155. package/dist/utils/format.js.map +1 -1
  156. package/dist/utils/i18n-coverage.d.ts +61 -0
  157. package/dist/utils/i18n-coverage.d.ts.map +1 -0
  158. package/dist/utils/i18n-coverage.js +176 -0
  159. package/dist/utils/i18n-coverage.js.map +1 -0
  160. package/dist/utils/lower-callables.d.ts +17 -0
  161. package/dist/utils/lower-callables.d.ts.map +1 -0
  162. package/dist/utils/lower-callables.js +181 -0
  163. package/dist/utils/lower-callables.js.map +1 -0
  164. package/dist/utils/plugin-detection.d.ts +1 -0
  165. package/dist/utils/plugin-detection.d.ts.map +1 -1
  166. package/dist/utils/plugin-detection.js +41 -0
  167. package/dist/utils/plugin-detection.js.map +1 -1
  168. package/dist/utils/studio.d.ts +1 -0
  169. package/dist/utils/studio.d.ts.map +1 -1
  170. package/dist/utils/studio.js +24 -9
  171. package/dist/utils/studio.js.map +1 -1
  172. package/package.json +60 -22
  173. package/.turbo/turbo-build.log +0 -4
  174. package/CHANGELOG.md +0 -821
  175. package/bin/run-dev.js +0 -5
  176. package/dist/commands/auth/login.d.ts.map +0 -1
  177. package/dist/commands/auth/login.js.map +0 -1
  178. package/dist/commands/auth/logout.d.ts.map +0 -1
  179. package/dist/commands/auth/logout.js.map +0 -1
  180. package/dist/commands/auth/whoami.d.ts.map +0 -1
  181. package/dist/commands/auth/whoami.js.map +0 -1
  182. package/dist/commands/codemod/v2-to-v3.d.ts +0 -10
  183. package/dist/commands/codemod/v2-to-v3.d.ts.map +0 -1
  184. package/dist/commands/codemod/v2-to-v3.js +0 -145
  185. package/dist/commands/codemod/v2-to-v3.js.map +0 -1
  186. package/dist/commands/plugin/add.d.ts +0 -22
  187. package/dist/commands/plugin/add.d.ts.map +0 -1
  188. package/dist/commands/plugin/add.js +0 -93
  189. package/dist/commands/plugin/add.js.map +0 -1
  190. package/dist/commands/plugin/build.d.ts +0 -29
  191. package/dist/commands/plugin/build.d.ts.map +0 -1
  192. package/dist/commands/plugin/build.js +0 -170
  193. package/dist/commands/plugin/build.js.map +0 -1
  194. package/dist/commands/plugin/info.d.ts +0 -10
  195. package/dist/commands/plugin/info.d.ts.map +0 -1
  196. package/dist/commands/plugin/info.js +0 -65
  197. package/dist/commands/plugin/info.js.map +0 -1
  198. package/dist/commands/plugin/list.d.ts +0 -13
  199. package/dist/commands/plugin/list.d.ts.map +0 -1
  200. package/dist/commands/plugin/list.js +0 -78
  201. package/dist/commands/plugin/list.js.map +0 -1
  202. package/dist/commands/plugin/publish.d.ts +0 -27
  203. package/dist/commands/plugin/publish.d.ts.map +0 -1
  204. package/dist/commands/plugin/publish.js +0 -152
  205. package/dist/commands/plugin/publish.js.map +0 -1
  206. package/dist/commands/plugin/remove.d.ts +0 -20
  207. package/dist/commands/plugin/remove.d.ts.map +0 -1
  208. package/dist/commands/plugin/remove.js +0 -79
  209. package/dist/commands/plugin/remove.js.map +0 -1
  210. package/dist/commands/plugin/validate.d.ts +0 -23
  211. package/dist/commands/plugin/validate.d.ts.map +0 -1
  212. package/dist/commands/plugin/validate.js +0 -251
  213. package/dist/commands/plugin/validate.js.map +0 -1
  214. package/src/bin.ts +0 -13
  215. package/src/commands/auth/login.ts +0 -188
  216. package/src/commands/auth/logout.ts +0 -51
  217. package/src/commands/auth/whoami.ts +0 -85
  218. package/src/commands/codemod/v2-to-v3.ts +0 -171
  219. package/src/commands/compile.ts +0 -114
  220. package/src/commands/create.ts +0 -281
  221. package/src/commands/data/create.ts +0 -110
  222. package/src/commands/data/delete.ts +0 -84
  223. package/src/commands/data/get.ts +0 -84
  224. package/src/commands/data/query.ts +0 -127
  225. package/src/commands/data/update.ts +0 -114
  226. package/src/commands/dev.ts +0 -83
  227. package/src/commands/diff.ts +0 -294
  228. package/src/commands/doctor.ts +0 -572
  229. package/src/commands/explain.ts +0 -412
  230. package/src/commands/generate.ts +0 -924
  231. package/src/commands/info.ts +0 -124
  232. package/src/commands/init.ts +0 -327
  233. package/src/commands/lint.ts +0 -315
  234. package/src/commands/meta/delete.ts +0 -79
  235. package/src/commands/meta/get.ts +0 -73
  236. package/src/commands/meta/list.ts +0 -105
  237. package/src/commands/meta/register.ts +0 -97
  238. package/src/commands/plugin/add.ts +0 -112
  239. package/src/commands/plugin/build.ts +0 -193
  240. package/src/commands/plugin/info.ts +0 -79
  241. package/src/commands/plugin/list.ts +0 -93
  242. package/src/commands/plugin/publish.ts +0 -176
  243. package/src/commands/plugin/remove.ts +0 -97
  244. package/src/commands/plugin/validate.ts +0 -268
  245. package/src/commands/serve.ts +0 -411
  246. package/src/commands/studio.ts +0 -52
  247. package/src/commands/test.ts +0 -135
  248. package/src/commands/validate.ts +0 -143
  249. package/src/index.ts +0 -22
  250. package/src/utils/api-client.ts +0 -88
  251. package/src/utils/auth-config.ts +0 -107
  252. package/src/utils/config.ts +0 -80
  253. package/src/utils/format.ts +0 -267
  254. package/src/utils/output-formatter.ts +0 -91
  255. package/src/utils/plugin-detection.ts +0 -16
  256. package/src/utils/plugin-helpers.ts +0 -37
  257. package/src/utils/studio.ts +0 -350
  258. package/test/commands.test.ts +0 -128
  259. package/test/create.test.ts +0 -25
  260. package/test/plugin-commands.test.ts +0 -44
  261. package/test/plugin.test.ts +0 -169
  262. package/test/remote-api-commands.test.ts +0 -188
  263. package/test/remote-api-utils.test.ts +0 -196
  264. package/test/serve-host-config.test.ts +0 -77
  265. package/tsconfig.build.json +0 -20
  266. package/tsconfig.json +0 -25
  267. package/tsup.config.ts +0 -23
  268. /package/dist/commands/{auth/logout.d.ts → logout.d.ts} +0 -0
  269. /package/dist/commands/{auth/whoami.d.ts → whoami.d.ts} +0 -0
@@ -1,97 +0,0 @@
1
- // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
-
3
- import { Args, Command, Flags } from '@oclif/core';
4
- import chalk from 'chalk';
5
- import fs from 'fs';
6
- import path from 'path';
7
- import { resolveConfigPath } from '../../utils/config.js';
8
- import { printHeader, printSuccess, printError } from '../../utils/format.js';
9
-
10
- function escapeRegex(str: string): string {
11
- return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
12
- }
13
-
14
- /**
15
- * Remove a plugin reference from objectstack.config.ts.
16
- *
17
- * Removes matching import line and the entry from the plugins array.
18
- */
19
- function removePluginFromConfig(configPath: string, pluginName: string): void {
20
- let content = fs.readFileSync(configPath, 'utf-8');
21
-
22
- // Remove the import line that references this plugin (exact package name match)
23
- const importRegex = new RegExp(`^import .+['"]${escapeRegex(pluginName)}['"]\\s*;?\\s*$\\n?`, 'gm');
24
- const hadImport = importRegex.test(content);
25
- // Reset regex lastIndex after test()
26
- importRegex.lastIndex = 0;
27
- content = content.replace(importRegex, '');
28
-
29
- // Also try to remove by a derived variable name
30
- const shortName = pluginName
31
- .replace(/^@[^/]+\//, '')
32
- .replace(/^plugin-/, '')
33
- .replace(/-+/g, '-')
34
- .replace(/^-|-$/g, '');
35
- const varName = shortName.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase()) + 'Plugin';
36
-
37
- // Remove import by variable name if it wasn't caught above
38
- if (!hadImport) {
39
- const varImportRegex = new RegExp(`^import .* ${escapeRegex(varName)} .+$\\n?`, 'gm');
40
- content = content.replace(varImportRegex, '');
41
- }
42
-
43
- // Remove the entry from the plugins array
44
- // Match: varName, or 'package-name', or "package-name"
45
- const entryPatterns = [
46
- new RegExp(`\\s*${escapeRegex(varName)},?\\n?`, 'g'),
47
- new RegExp(`\\s*['"]${escapeRegex(pluginName)}['"],?\\n?`, 'g'),
48
- ];
49
-
50
- for (const pattern of entryPatterns) {
51
- content = content.replace(pattern, '\n');
52
- }
53
-
54
- // Clean up empty plugins array: plugins: [\n ],
55
- content = content.replace(/plugins\s*:\s*\[\s*\],?\n?/g, '');
56
-
57
- fs.writeFileSync(configPath, content);
58
- }
59
-
60
- export { removePluginFromConfig };
61
-
62
- export default class PluginRemove extends Command {
63
- static override description = 'Remove a plugin from objectstack.config.ts';
64
-
65
- static override aliases = ['plugin rm'];
66
-
67
- static override args = {
68
- name: Args.string({ description: 'Plugin name or package name to remove', required: true }),
69
- };
70
-
71
- static override flags = {
72
- config: Flags.string({ char: 'c', description: 'Configuration file path' }),
73
- };
74
-
75
- async run(): Promise<void> {
76
- const { args, flags } = await this.parse(PluginRemove);
77
-
78
- try {
79
- const configPath = resolveConfigPath(flags.config);
80
-
81
- printHeader('Remove Plugin');
82
- console.log(` ${chalk.dim('Plugin:')} ${chalk.white(args.name)}`);
83
- console.log(` ${chalk.dim('Config:')} ${chalk.white(path.relative(process.cwd(), configPath))}`);
84
- console.log('');
85
-
86
- removePluginFromConfig(configPath, args.name);
87
- printSuccess(`Removed ${chalk.cyan(args.name)} from config`);
88
-
89
- console.log('');
90
- console.log(chalk.dim(' Tip: Run `pnpm remove ' + args.name + '` to uninstall the package'));
91
- console.log('');
92
- } catch (error: any) {
93
- printError(error.message || String(error));
94
- this.exit(1);
95
- }
96
- }
97
- }
@@ -1,268 +0,0 @@
1
- // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
-
3
- import { Args, Command, Flags } from '@oclif/core';
4
- import chalk from 'chalk';
5
- import path from 'path';
6
- import fs from 'fs';
7
- import crypto from 'crypto';
8
- import { createTimer, printHeader, printKV, printStep, printSuccess, printError, printWarning, printInfo } from '../../utils/format.js';
9
-
10
- /**
11
- * Validate a plugin artifact (.tgz) for structural integrity, checksum
12
- * correctness, digital signature, and platform compatibility.
13
- *
14
- * Architecture alignment: `npm pack --dry-run`, `helm lint`, `vsce ls`.
15
- */
16
- export default class PluginValidate extends Command {
17
- static override description = 'Validate a plugin artifact for integrity and compliance';
18
-
19
- static override args = {
20
- artifact: Args.string({ description: 'Path to the artifact file', required: true }),
21
- };
22
-
23
- static override flags = {
24
- verifySignature: Flags.boolean({ description: 'Verify digital signature', default: true, allowNo: true }),
25
- publicKeyPath: Flags.string({ description: 'Path to public key for signature verification' }),
26
- verifyChecksums: Flags.boolean({ description: 'Verify SHA-256 checksums', default: true, allowNo: true }),
27
- validateMetadata: Flags.boolean({ description: 'Validate metadata schema compliance', default: true, allowNo: true }),
28
- platformVersion: Flags.string({ description: 'Target platform version for compatibility check' }),
29
- json: Flags.boolean({ description: 'Output result as JSON' }),
30
- };
31
-
32
- async run(): Promise<void> {
33
- const { args, flags } = await this.parse(PluginValidate);
34
- const timer = createTimer();
35
-
36
- if (!flags.json) {
37
- printHeader('Plugin Validate');
38
- }
39
-
40
- try {
41
- const artifactPath = path.resolve(process.cwd(), args.artifact);
42
-
43
- if (!fs.existsSync(artifactPath)) {
44
- throw new Error(`Artifact not found: ${artifactPath}`);
45
- }
46
-
47
- if (!flags.json) {
48
- printKV('Artifact', path.relative(process.cwd(), artifactPath));
49
- printStep('Reading artifact...');
50
- }
51
-
52
- const artifactBuffer = fs.readFileSync(artifactPath);
53
- const findings: Array<{ severity: string; rule: string; message: string; path?: string }> = [];
54
-
55
- // 1. Verify file existence and basic structure
56
- if (artifactBuffer.length === 0) {
57
- findings.push({ severity: 'error', rule: 'artifact.empty', message: 'Artifact file is empty' });
58
- }
59
-
60
- // 2. Try to parse as JSON manifest
61
- let manifest: Record<string, unknown> | undefined;
62
- try {
63
- manifest = JSON.parse(artifactBuffer.toString('utf-8'));
64
- findings.push({ severity: 'info', rule: 'manifest.parsed', message: 'Manifest parsed successfully' });
65
- } catch {
66
- findings.push({ severity: 'error', rule: 'manifest.invalid', message: 'Artifact does not contain valid JSON manifest' });
67
- }
68
-
69
- // 3. Validate required manifest fields
70
- if (manifest) {
71
- if (!flags.json) printStep('Validating manifest fields...');
72
-
73
- if (!(manifest as any).manifest && !(manifest as any).name) {
74
- findings.push({ severity: 'warning', rule: 'manifest.name', message: 'No package name found in manifest' });
75
- }
76
- if (!(manifest as any).manifest?.version && !(manifest as any).version) {
77
- findings.push({ severity: 'warning', rule: 'manifest.version', message: 'No version found in manifest' });
78
- }
79
- }
80
-
81
- // 4. Checksum verification
82
- let checksumResult: { passed: boolean; mismatches?: string[] } | undefined;
83
- if (flags.verifyChecksums) {
84
- if (!flags.json) printStep('Verifying checksums...');
85
- const checksumFile = artifactPath + '.sha256';
86
- if (fs.existsSync(checksumFile)) {
87
- const checksumContent = fs.readFileSync(checksumFile, 'utf-8').trim();
88
- const expectedHash = checksumContent.split(/\s+/)[0];
89
- const actualHash = crypto.createHash('sha256').update(artifactBuffer).digest('hex');
90
- if (expectedHash === actualHash) {
91
- checksumResult = { passed: true };
92
- findings.push({ severity: 'info', rule: 'checksum.sha256', message: 'SHA-256 checksum verified' });
93
- } else {
94
- checksumResult = { passed: false, mismatches: ['artifact'] };
95
- findings.push({ severity: 'error', rule: 'checksum.sha256', message: `SHA-256 mismatch: expected ${expectedHash.slice(0, 16)}..., got ${actualHash.slice(0, 16)}...` });
96
- }
97
- } else {
98
- findings.push({ severity: 'warning', rule: 'checksum.missing', message: 'No .sha256 checksum file found alongside artifact' });
99
- }
100
- }
101
-
102
- // 5. Signature verification
103
- let signatureResult: { passed: boolean; failureReason?: string } | undefined;
104
- if (flags.verifySignature) {
105
- if (!flags.json) printStep('Verifying signature...');
106
- const sigFile = artifactPath + '.sig';
107
- if (fs.existsSync(sigFile) && flags.publicKeyPath && fs.existsSync(flags.publicKeyPath)) {
108
- try {
109
- const publicKey = fs.readFileSync(flags.publicKeyPath, 'utf-8');
110
- const signature = fs.readFileSync(sigFile, 'utf-8');
111
- const verifier = crypto.createVerify('RSA-SHA256');
112
- verifier.update(artifactBuffer);
113
- const valid = verifier.verify(publicKey, signature, 'base64');
114
- signatureResult = { passed: valid, failureReason: valid ? undefined : 'Signature does not match' };
115
- findings.push({
116
- severity: valid ? 'info' : 'error',
117
- rule: 'signature.verify',
118
- message: valid ? 'Digital signature verified' : 'Digital signature verification failed',
119
- });
120
- } catch (e: any) {
121
- signatureResult = { passed: false, failureReason: e.message };
122
- findings.push({ severity: 'error', rule: 'signature.verify', message: `Signature verification error: ${e.message}` });
123
- }
124
- } else if (fs.existsSync(sigFile) && !flags.publicKeyPath) {
125
- findings.push({ severity: 'warning', rule: 'signature.nokey', message: 'Signature file found but no --publicKeyPath provided' });
126
- } else if (!fs.existsSync(sigFile)) {
127
- findings.push({ severity: 'info', rule: 'signature.absent', message: 'No signature file found (unsigned artifact)' });
128
- }
129
- }
130
-
131
- // 6. Platform compatibility check
132
- let platformResult: { compatible: boolean; requiredRange?: string; targetVersion?: string } | undefined;
133
- if (flags.platformVersion && manifest) {
134
- if (!flags.json) printStep('Checking platform compatibility...');
135
- const engine = (manifest as any).manifest?.engine || (manifest as any).engine;
136
- const required = engine?.objectstack as string | undefined;
137
- if (required) {
138
- // Semver range check supporting >=, >, ^, ~, and exact versions
139
- const parseSemver = (v: string) => {
140
- const parts = v.replace(/^v/, '').split('.').map(p => parseInt(p, 10));
141
- return { major: parts[0] || 0, minor: parts[1] || 0, patch: parts[2] || 0 };
142
- };
143
-
144
- const target = parseSemver(flags.platformVersion);
145
- let compatible = false;
146
- let matched = false;
147
-
148
- // >=X.Y.Z — greater than or equal
149
- const gteMatch = required.match(/^>=\s*([\d.]+)/);
150
- if (gteMatch) {
151
- const req = parseSemver(gteMatch[1]);
152
- compatible = (target.major > req.major) ||
153
- (target.major === req.major && target.minor > req.minor) ||
154
- (target.major === req.major && target.minor === req.minor && target.patch >= req.patch);
155
- matched = true;
156
- }
157
-
158
- // >X.Y.Z — strictly greater than
159
- if (!matched) {
160
- const gtMatch = required.match(/^>\s*([\d.]+)/);
161
- if (gtMatch) {
162
- const req = parseSemver(gtMatch[1]);
163
- compatible = (target.major > req.major) ||
164
- (target.major === req.major && target.minor > req.minor) ||
165
- (target.major === req.major && target.minor === req.minor && target.patch > req.patch);
166
- matched = true;
167
- }
168
- }
169
-
170
- // ^X.Y.Z — caret range (same major, >= minor.patch)
171
- if (!matched) {
172
- const caretMatch = required.match(/^\^\s*([\d.]+)/);
173
- if (caretMatch) {
174
- const req = parseSemver(caretMatch[1]);
175
- compatible = target.major === req.major &&
176
- ((target.minor > req.minor) ||
177
- (target.minor === req.minor && target.patch >= req.patch));
178
- matched = true;
179
- }
180
- }
181
-
182
- // ~X.Y.Z — tilde range (same major.minor, >= patch)
183
- if (!matched) {
184
- const tildeMatch = required.match(/^~\s*([\d.]+)/);
185
- if (tildeMatch) {
186
- const req = parseSemver(tildeMatch[1]);
187
- compatible = target.major === req.major && target.minor === req.minor && target.patch >= req.patch;
188
- matched = true;
189
- }
190
- }
191
-
192
- // Exact version match
193
- if (!matched && /^\d+\.\d+\.\d+$/.test(required)) {
194
- const req = parseSemver(required);
195
- compatible = target.major === req.major && target.minor === req.minor && target.patch === req.patch;
196
- matched = true;
197
- }
198
-
199
- if (matched) {
200
- platformResult = { compatible, requiredRange: required, targetVersion: flags.platformVersion };
201
- findings.push({
202
- severity: compatible ? 'info' : 'error',
203
- rule: 'platform.compatibility',
204
- message: compatible
205
- ? `Compatible with platform v${flags.platformVersion}`
206
- : `Requires platform ${required}, but target is v${flags.platformVersion}`,
207
- });
208
- }
209
- } else {
210
- platformResult = { compatible: true, targetVersion: flags.platformVersion };
211
- findings.push({ severity: 'info', rule: 'platform.noreq', message: 'No platform version requirement specified — assumed compatible' });
212
- }
213
- }
214
-
215
- // 7. Summary
216
- const errors = findings.filter(f => f.severity === 'error').length;
217
- const warns = findings.filter(f => f.severity === 'warning').length;
218
- const infos = findings.filter(f => f.severity === 'info').length;
219
- const valid = errors === 0;
220
-
221
- const result = {
222
- valid,
223
- checksumVerification: checksumResult,
224
- signatureVerification: signatureResult,
225
- platformCompatibility: platformResult,
226
- findings,
227
- summary: { errors, warnings: warns, infos },
228
- };
229
-
230
- if (flags.json) {
231
- console.log(JSON.stringify(result, null, 2));
232
- return;
233
- }
234
-
235
- console.log('');
236
- if (valid) {
237
- printSuccess(`Validation passed ${chalk.dim(`(${timer.display()})`)}`);
238
- } else {
239
- printError(`Validation failed ${chalk.dim(`(${timer.display()})`)}`);
240
- }
241
-
242
- console.log('');
243
- for (const finding of findings) {
244
- const icon = finding.severity === 'error' ? chalk.red('✗')
245
- : finding.severity === 'warning' ? chalk.yellow('⚠')
246
- : chalk.blue('ℹ');
247
- console.log(` ${icon} ${chalk.dim(`[${finding.rule}]`)} ${finding.message}`);
248
- }
249
-
250
- console.log('');
251
- printKV('Errors', errors);
252
- printKV('Warnings', warns);
253
- printKV('Info', infos);
254
- console.log('');
255
-
256
- if (!valid) {
257
- this.exit(1);
258
- }
259
- } catch (error: any) {
260
- if (flags.json) {
261
- console.log(JSON.stringify({ valid: false, findings: [{ severity: 'error', rule: 'system', message: error.message }], summary: { errors: 1, warnings: 0, infos: 0 } }));
262
- this.exit(1);
263
- }
264
- printError(error.message || String(error));
265
- this.exit(1);
266
- }
267
- }
268
- }