@c15t/cli 2.0.0-rc.4 → 2.0.0-rc.6
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/README.md +43 -14
- package/dist/145.mjs +6509 -0
- package/dist/generate-files.mjs +1797 -0
- package/dist/index.mjs +1 -3547
- package/{dist → dist-types}/actions/show-help-menu.d.ts +0 -1
- package/dist-types/auth/base-url.d.ts +7 -0
- package/{dist → dist-types}/auth/config-store.d.ts +0 -1
- package/{dist → dist-types}/auth/device-flow.d.ts +0 -1
- package/{dist → dist-types}/auth/index.d.ts +1 -1
- package/{dist → dist-types}/auth/types.d.ts +0 -1
- package/{dist → dist-types}/commands/auth/index.d.ts +0 -1
- package/dist-types/commands/codemods/active-ui-api.d.ts +41 -0
- package/dist-types/commands/codemods/add-stylesheet-imports.d.ts +54 -0
- package/dist-types/commands/codemods/component-renames.d.ts +41 -0
- package/dist-types/commands/codemods/gdpr-types-to-consent-categories.d.ts +41 -0
- package/dist-types/commands/codemods/ignore-geo-location-to-overrides.d.ts +41 -0
- package/dist-types/commands/codemods/index.d.ts +28 -0
- package/dist-types/commands/codemods/mode-c15t-to-hosted.d.ts +43 -0
- package/dist-types/commands/codemods/offline-add-policy-packs.d.ts +21 -0
- package/dist-types/commands/codemods/react-options-to-top-level.d.ts +41 -0
- package/dist-types/commands/codemods/tracking-blocker-to-network-blocker.d.ts +41 -0
- package/dist-types/commands/codemods/translations-to-i18n.d.ts +51 -0
- package/dist-types/commands/codemods/versioning.d.ts +49 -0
- package/{dist → dist-types}/commands/generate/index.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/options/shared/backend-options.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/options/shared/dev-tools.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/options/shared/frontend-ui-options.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/options/shared/scripts.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/options/shared/ssr.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/options/types.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/options/utils/dependencies.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/options/utils/generate-files.d.ts +2 -2
- package/{dist → dist-types}/commands/generate/preflight.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/prompts/expanded-theme.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/prompts/index.d.ts +0 -2
- package/{dist → dist-types}/commands/generate/prompts/mode-select.d.ts +1 -7
- package/{dist → dist-types}/commands/generate/prompts/scripts.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/prompts/theme.d.ts +1 -2
- package/{dist → dist-types}/commands/generate/prompts/ui-style.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/summary.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/templates/config.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/templates/css.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/templates/env.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/templates/index.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/templates/layout.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/templates/next/app/layout.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/templates/next/index.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/templates/next/pages/layout.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/templates/next-config.d.ts +1 -4
- package/{dist → dist-types}/commands/generate/templates/shared/components.d.ts +2 -3
- package/{dist → dist-types}/commands/generate/templates/shared/directory.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/templates/shared/expanded-components.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/templates/shared/framework-config.d.ts +4 -1
- package/{dist → dist-types}/commands/generate/templates/shared/layout-pipeline.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/templates/shared/module-specifier.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/templates/shared/options.d.ts +5 -6
- package/{dist → dist-types}/commands/generate/templates/shared/scripts.d.ts +0 -1
- package/{dist → dist-types}/commands/generate/templates/shared/server-components.d.ts +0 -1
- package/{dist → dist-types}/commands/index.d.ts +1 -1
- package/{dist → dist-types}/commands/instances/index.d.ts +1 -2
- package/{dist → dist-types}/commands/self-host/index.d.ts +0 -1
- package/{dist → dist-types}/commands/self-host/migrate/ensure-backend-config.d.ts +0 -1
- package/{dist → dist-types}/commands/self-host/migrate/index.d.ts +0 -1
- package/{dist → dist-types}/commands/self-host/migrate/migrator-result.d.ts +1 -2
- package/{dist → dist-types}/commands/self-host/migrate/orm-result.d.ts +1 -2
- package/{dist → dist-types}/commands/self-host/migrate/read-config.d.ts +1 -2
- package/{dist → dist-types}/commands/skills.d.ts +0 -1
- package/{dist → dist-types}/components/intro.d.ts +0 -1
- package/{dist → dist-types}/constants.d.ts +19 -9
- package/{dist → dist-types}/context/creator.d.ts +0 -1
- package/{dist → dist-types}/context/error-handlers.d.ts +0 -1
- package/{dist → dist-types}/context/file-system.d.ts +0 -1
- package/{dist → dist-types}/context/framework-detection.d.ts +0 -1
- package/{dist → dist-types}/context/package-manager-detection.d.ts +0 -1
- package/{dist → dist-types}/context/parser.d.ts +0 -1
- package/{dist → dist-types}/context/types.d.ts +1 -2
- package/{dist → dist-types}/context/user-interaction.d.ts +0 -1
- package/dist-types/control-plane/client.d.ts +56 -0
- package/dist-types/control-plane/index.d.ts +5 -0
- package/dist-types/control-plane/types.d.ts +73 -0
- package/{dist → dist-types}/core/context.d.ts +0 -1
- package/{dist → dist-types}/core/errors.d.ts +5 -11
- package/{dist → dist-types}/core/index.d.ts +0 -1
- package/{dist → dist-types}/core/logger.d.ts +0 -1
- package/{dist → dist-types}/core/parser.d.ts +0 -1
- package/{dist → dist-types}/core/telemetry.d.ts +0 -1
- package/{dist → dist-types}/detection/framework.d.ts +0 -1
- package/{dist → dist-types}/detection/index.d.ts +0 -1
- package/{dist → dist-types}/detection/layout.d.ts +0 -1
- package/{dist → dist-types}/detection/package-manager.d.ts +0 -1
- package/{dist → dist-types}/index.d.ts +0 -1
- package/{dist → dist-types}/machines/generate/actions.d.ts +0 -1
- package/{dist → dist-types}/machines/generate/actors/dependencies.d.ts +0 -1
- package/{dist → dist-types}/machines/generate/actors/file-generation.d.ts +1 -2
- package/{dist → dist-types}/machines/generate/actors/preflight.d.ts +0 -1
- package/{dist → dist-types}/machines/generate/actors/prompts.d.ts +8 -13
- package/{dist → dist-types}/machines/generate/guards.d.ts +4 -5
- package/{dist → dist-types}/machines/generate/machine.d.ts +10 -23
- package/{dist → dist-types}/machines/generate/runner.d.ts +0 -1
- package/{dist → dist-types}/machines/generate/types.d.ts +4 -3
- package/{dist → dist-types}/machines/index.d.ts +1 -2
- package/{dist → dist-types}/machines/persistence.d.ts +0 -1
- package/{dist → dist-types}/machines/telemetry-plugin.d.ts +0 -1
- package/{dist → dist-types}/machines/types.d.ts +0 -1
- package/{dist → dist-types}/types.d.ts +6 -3
- package/{dist → dist-types}/utils/capitalize-first-letter.d.ts +0 -1
- package/{dist → dist-types}/utils/formatter.d.ts +0 -1
- package/{dist → dist-types}/utils/fs.d.ts +0 -1
- package/{dist → dist-types}/utils/index.d.ts +0 -1
- package/{dist → dist-types}/utils/logger.d.ts +1 -2
- package/{dist → dist-types}/utils/spinner.d.ts +0 -1
- package/{dist → dist-types}/utils/telemetry.d.ts +1 -2
- package/{dist → dist-types}/utils/validation.d.ts +0 -1
- package/package.json +16 -14
- package/readme.json +22 -8
- package/dist/153.mjs +0 -1802
- package/dist/actions/show-help-menu.d.ts.map +0 -1
- package/dist/auth/config-store.d.ts.map +0 -1
- package/dist/auth/device-flow.d.ts.map +0 -1
- package/dist/auth/index.d.ts.map +0 -1
- package/dist/auth/types.d.ts.map +0 -1
- package/dist/commands/auth/index.d.ts.map +0 -1
- package/dist/commands/generate/index.d.ts.map +0 -1
- package/dist/commands/generate/options/c15t-mode.d.ts +0 -27
- package/dist/commands/generate/options/c15t-mode.d.ts.map +0 -1
- package/dist/commands/generate/options/custom-mode.d.ts +0 -26
- package/dist/commands/generate/options/custom-mode.d.ts.map +0 -1
- package/dist/commands/generate/options/offline-mode.d.ts +0 -26
- package/dist/commands/generate/options/offline-mode.d.ts.map +0 -1
- package/dist/commands/generate/options/self-hosted-mode.d.ts +0 -19
- package/dist/commands/generate/options/self-hosted-mode.d.ts.map +0 -1
- package/dist/commands/generate/options/shared/backend-options.d.ts.map +0 -1
- package/dist/commands/generate/options/shared/dev-tools.d.ts.map +0 -1
- package/dist/commands/generate/options/shared/frontend-ui-options.d.ts.map +0 -1
- package/dist/commands/generate/options/shared/index.d.ts +0 -9
- package/dist/commands/generate/options/shared/index.d.ts.map +0 -1
- package/dist/commands/generate/options/shared/scripts.d.ts.map +0 -1
- package/dist/commands/generate/options/shared/ssr.d.ts.map +0 -1
- package/dist/commands/generate/options/types.d.ts.map +0 -1
- package/dist/commands/generate/options/utils/dependencies.d.ts.map +0 -1
- package/dist/commands/generate/options/utils/generate-files.d.ts.map +0 -1
- package/dist/commands/generate/preflight.d.ts.map +0 -1
- package/dist/commands/generate/prompts/expanded-theme.d.ts.map +0 -1
- package/dist/commands/generate/prompts/index.d.ts.map +0 -1
- package/dist/commands/generate/prompts/instance.d.ts +0 -33
- package/dist/commands/generate/prompts/instance.d.ts.map +0 -1
- package/dist/commands/generate/prompts/mode-select.d.ts.map +0 -1
- package/dist/commands/generate/prompts/scripts.d.ts.map +0 -1
- package/dist/commands/generate/prompts/theme.d.ts.map +0 -1
- package/dist/commands/generate/prompts/ui-style.d.ts.map +0 -1
- package/dist/commands/generate/summary.d.ts.map +0 -1
- package/dist/commands/generate/templates/config.d.ts.map +0 -1
- package/dist/commands/generate/templates/css.d.ts.map +0 -1
- package/dist/commands/generate/templates/env.d.ts.map +0 -1
- package/dist/commands/generate/templates/index.d.ts.map +0 -1
- package/dist/commands/generate/templates/layout.d.ts.map +0 -1
- package/dist/commands/generate/templates/next/app/layout.d.ts.map +0 -1
- package/dist/commands/generate/templates/next/index.d.ts.map +0 -1
- package/dist/commands/generate/templates/next/pages/layout.d.ts.map +0 -1
- package/dist/commands/generate/templates/next-config.d.ts.map +0 -1
- package/dist/commands/generate/templates/shared/components.d.ts.map +0 -1
- package/dist/commands/generate/templates/shared/directory.d.ts.map +0 -1
- package/dist/commands/generate/templates/shared/expanded-components.d.ts.map +0 -1
- package/dist/commands/generate/templates/shared/framework-config.d.ts.map +0 -1
- package/dist/commands/generate/templates/shared/layout-pipeline.d.ts.map +0 -1
- package/dist/commands/generate/templates/shared/module-specifier.d.ts.map +0 -1
- package/dist/commands/generate/templates/shared/options.d.ts.map +0 -1
- package/dist/commands/generate/templates/shared/scripts.d.ts.map +0 -1
- package/dist/commands/generate/templates/shared/server-components.d.ts.map +0 -1
- package/dist/commands/index.d.ts.map +0 -1
- package/dist/commands/instances/index.d.ts.map +0 -1
- package/dist/commands/self-host/index.d.ts.map +0 -1
- package/dist/commands/self-host/migrate/ensure-backend-config.d.ts.map +0 -1
- package/dist/commands/self-host/migrate/index.d.ts.map +0 -1
- package/dist/commands/self-host/migrate/migrator-result.d.ts.map +0 -1
- package/dist/commands/self-host/migrate/orm-result.d.ts.map +0 -1
- package/dist/commands/self-host/migrate/read-config.d.ts.map +0 -1
- package/dist/commands/skills.d.ts.map +0 -1
- package/dist/components/intro.d.ts.map +0 -1
- package/dist/constants.d.ts.map +0 -1
- package/dist/context/creator.d.ts.map +0 -1
- package/dist/context/error-handlers.d.ts.map +0 -1
- package/dist/context/file-system.d.ts.map +0 -1
- package/dist/context/framework-detection.d.ts.map +0 -1
- package/dist/context/package-manager-detection.d.ts.map +0 -1
- package/dist/context/parser.d.ts.map +0 -1
- package/dist/context/types.d.ts.map +0 -1
- package/dist/context/user-interaction.d.ts.map +0 -1
- package/dist/core/context.d.ts.map +0 -1
- package/dist/core/errors.d.ts.map +0 -1
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/logger.d.ts.map +0 -1
- package/dist/core/parser.d.ts.map +0 -1
- package/dist/core/telemetry.d.ts.map +0 -1
- package/dist/detection/framework.d.ts.map +0 -1
- package/dist/detection/index.d.ts.map +0 -1
- package/dist/detection/layout.d.ts.map +0 -1
- package/dist/detection/package-manager.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/machines/generate/actions.d.ts.map +0 -1
- package/dist/machines/generate/actors/dependencies.d.ts.map +0 -1
- package/dist/machines/generate/actors/file-generation.d.ts.map +0 -1
- package/dist/machines/generate/actors/preflight.d.ts.map +0 -1
- package/dist/machines/generate/actors/prompts.d.ts.map +0 -1
- package/dist/machines/generate/guards.d.ts.map +0 -1
- package/dist/machines/generate/machine.d.ts.map +0 -1
- package/dist/machines/generate/runner.d.ts.map +0 -1
- package/dist/machines/generate/types.d.ts.map +0 -1
- package/dist/machines/index.d.ts.map +0 -1
- package/dist/machines/persistence.d.ts.map +0 -1
- package/dist/machines/telemetry-plugin.d.ts.map +0 -1
- package/dist/machines/types.d.ts.map +0 -1
- package/dist/mcp/client.d.ts +0 -61
- package/dist/mcp/client.d.ts.map +0 -1
- package/dist/mcp/index.d.ts +0 -6
- package/dist/mcp/index.d.ts.map +0 -1
- package/dist/mcp/types.d.ts +0 -84
- package/dist/mcp/types.d.ts.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/utils/capitalize-first-letter.d.ts.map +0 -1
- package/dist/utils/formatter.d.ts.map +0 -1
- package/dist/utils/fs.d.ts.map +0 -1
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/spinner.d.ts.map +0 -1
- package/dist/utils/telemetry.d.ts.map +0 -1
- package/dist/utils/validation.d.ts.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,3548 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import * as __rspack_external_node_fs_promises_153e37e0 from "node:fs/promises";
|
|
4
|
-
import * as __rspack_external_node_path_c5b9b54f from "node:path";
|
|
5
|
-
import * as __rspack_external_picocolors from "picocolors";
|
|
6
|
-
import "dotenv/config";
|
|
7
|
-
import * as __rspack_external_open from "open";
|
|
8
|
-
import * as __rspack_external_xstate from "xstate";
|
|
9
|
-
import * as __rspack_external_node_crypto_9ba42079 from "node:crypto";
|
|
10
|
-
import * as __rspack_external_node_os_74b4b876 from "node:os";
|
|
11
|
-
import * as __rspack_external_posthog_node_1b07bdf4 from "posthog-node";
|
|
12
|
-
import * as __rspack_external_node_child_process_27f17141 from "node:child_process";
|
|
13
|
-
import * as __rspack_external_node_events_0a6aefe7 from "node:events";
|
|
14
|
-
import * as __rspack_external__c15t_logger_04a510d4 from "@c15t/logger";
|
|
15
|
-
import * as __rspack_external__c15t_backend_db_migrator_ebe6d5c7 from "@c15t/backend/db/migrator";
|
|
16
|
-
import * as __rspack_external__c15t_backend_db_schema_e7c5e6a0 from "@c15t/backend/db/schema";
|
|
17
|
-
import * as __rspack_external_c12 from "c12";
|
|
18
|
-
import * as __rspack_external_figlet from "figlet";
|
|
19
|
-
import * as __rspack_external_fs_extra_ce68a66b from "fs-extra";
|
|
20
|
-
import * as __rspack_external_package_manager_detector_detect_94d6a9ae from "package-manager-detector/detect";
|
|
21
|
-
var __webpack_modules__ = {
|
|
22
|
-
"./src/constants.ts" (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
23
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
24
|
-
$V: ()=>STORAGE_MODES,
|
|
25
|
-
Lk: ()=>LAYOUT_PATTERNS,
|
|
26
|
-
QL: ()=>REGEX,
|
|
27
|
-
Vj: ()=>PAGES_APP_PATTERNS,
|
|
28
|
-
tl: ()=>URLS
|
|
29
|
-
});
|
|
30
|
-
const URLS = {
|
|
31
|
-
CONSENT_IO: 'https://consent.io',
|
|
32
|
-
DOCS: 'https://c15t.dev/docs',
|
|
33
|
-
GITHUB: 'https://github.com/c15t/c15t',
|
|
34
|
-
DISCORD: 'https://c15t.dev/discord',
|
|
35
|
-
API_DOCS: 'https://c15t.dev/docs/api',
|
|
36
|
-
CLI_DOCS: 'https://c15t.dev/docs/cli'
|
|
37
|
-
};
|
|
38
|
-
const REGEX = {
|
|
39
|
-
URL: /^https?:\/\/.+/,
|
|
40
|
-
C15T_URL: /^https:\/\/[\w-]+\.c15t\.dev$/,
|
|
41
|
-
DYNAMIC_SEGMENT: /\[[\w-]+\]/,
|
|
42
|
-
SEMVER: /^\d+\.\d+\.\d+(-[\w.]+)?$/,
|
|
43
|
-
PACKAGE_NAME: /^(@[\w-]+\/)?[\w-]+$/
|
|
44
|
-
};
|
|
45
|
-
const STORAGE_MODES = {
|
|
46
|
-
C15T: 'c15t',
|
|
47
|
-
OFFLINE: 'offline',
|
|
48
|
-
SELF_HOSTED: 'self-hosted',
|
|
49
|
-
CUSTOM: 'custom'
|
|
50
|
-
};
|
|
51
|
-
const LAYOUT_PATTERNS = [
|
|
52
|
-
'app/layout.tsx',
|
|
53
|
-
'app/layout.ts',
|
|
54
|
-
'app/layout.jsx',
|
|
55
|
-
'app/layout.js',
|
|
56
|
-
'src/app/layout.tsx',
|
|
57
|
-
'src/app/layout.ts',
|
|
58
|
-
'src/app/layout.jsx',
|
|
59
|
-
'src/app/layout.js',
|
|
60
|
-
'app/*/layout.tsx',
|
|
61
|
-
'app/*/layout.ts',
|
|
62
|
-
'app/*/layout.jsx',
|
|
63
|
-
'app/*/layout.js',
|
|
64
|
-
'src/app/*/layout.tsx',
|
|
65
|
-
'src/app/*/layout.ts',
|
|
66
|
-
'src/app/*/layout.jsx',
|
|
67
|
-
'src/app/*/layout.js',
|
|
68
|
-
'app/*/*/layout.tsx',
|
|
69
|
-
'app/*/*/layout.ts',
|
|
70
|
-
'src/app/*/*/layout.tsx',
|
|
71
|
-
'src/app/*/*/layout.ts'
|
|
72
|
-
];
|
|
73
|
-
const PAGES_APP_PATTERNS = [
|
|
74
|
-
'pages/_app.tsx',
|
|
75
|
-
'pages/_app.ts',
|
|
76
|
-
'pages/_app.jsx',
|
|
77
|
-
'pages/_app.js',
|
|
78
|
-
'src/pages/_app.tsx',
|
|
79
|
-
'src/pages/_app.ts',
|
|
80
|
-
'src/pages/_app.jsx',
|
|
81
|
-
'src/pages/_app.js'
|
|
82
|
-
];
|
|
83
|
-
},
|
|
84
|
-
"./src/utils/logger.ts" (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
85
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
86
|
-
U0: ()=>validLogLevels,
|
|
87
|
-
$e: ()=>formatLogMessage,
|
|
88
|
-
xw: ()=>createCliLogger
|
|
89
|
-
});
|
|
90
|
-
var prompts_ = __webpack_require__("@clack/prompts");
|
|
91
|
-
var external_picocolors_ = __webpack_require__("picocolors");
|
|
92
|
-
const validLogLevels = [
|
|
93
|
-
'error',
|
|
94
|
-
'warn',
|
|
95
|
-
'info',
|
|
96
|
-
'debug'
|
|
97
|
-
];
|
|
98
|
-
const formatArgs = (args)=>{
|
|
99
|
-
if (0 === args.length) return '';
|
|
100
|
-
return `\n${args.map((arg)=>` - ${JSON.stringify(arg, null, 2)}`).join('\n')}`;
|
|
101
|
-
};
|
|
102
|
-
const formatLogMessage = (logLevel, message, args = [])=>{
|
|
103
|
-
const messageStr = 'string' == typeof message ? message : String(message);
|
|
104
|
-
const formattedArgs = formatArgs(args);
|
|
105
|
-
switch(logLevel){
|
|
106
|
-
case 'error':
|
|
107
|
-
return `${external_picocolors_["default"].bgRed(external_picocolors_["default"].black(' error '))} ${messageStr}${formattedArgs}`;
|
|
108
|
-
case 'warn':
|
|
109
|
-
return `${external_picocolors_["default"].bgYellow(external_picocolors_["default"].black(' warning '))} ${messageStr}${formattedArgs}`;
|
|
110
|
-
case 'info':
|
|
111
|
-
return `${external_picocolors_["default"].bgGreen(external_picocolors_["default"].black(' info '))} ${messageStr}${formattedArgs}`;
|
|
112
|
-
case 'debug':
|
|
113
|
-
return `${external_picocolors_["default"].bgBlack(external_picocolors_["default"].white(' debug '))} ${messageStr}${formattedArgs}`;
|
|
114
|
-
case 'success':
|
|
115
|
-
return `${external_picocolors_["default"].bgGreen(external_picocolors_["default"].white(' success '))} ${messageStr}${formattedArgs}`;
|
|
116
|
-
case 'failed':
|
|
117
|
-
return `${external_picocolors_["default"].bgRed(external_picocolors_["default"].white(' failed '))} ${messageStr}${formattedArgs}`;
|
|
118
|
-
default:
|
|
119
|
-
{
|
|
120
|
-
const levelStr = logLevel;
|
|
121
|
-
return `[${levelStr.toUpperCase()}] ${messageStr}${formattedArgs}`;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
const logMessage = (logLevel, message, ...args)=>{
|
|
126
|
-
const formattedMessage = formatLogMessage(logLevel, message, args);
|
|
127
|
-
switch(logLevel){
|
|
128
|
-
case 'error':
|
|
129
|
-
prompts_.log.error(formattedMessage);
|
|
130
|
-
break;
|
|
131
|
-
case 'warn':
|
|
132
|
-
prompts_.log.warn(formattedMessage);
|
|
133
|
-
break;
|
|
134
|
-
case 'info':
|
|
135
|
-
case 'debug':
|
|
136
|
-
prompts_.log.info(formattedMessage);
|
|
137
|
-
break;
|
|
138
|
-
case 'success':
|
|
139
|
-
case 'failed':
|
|
140
|
-
prompts_.outro(formattedMessage);
|
|
141
|
-
break;
|
|
142
|
-
default:
|
|
143
|
-
prompts_.log.message(formattedMessage);
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
const createCliLogger = (level)=>{
|
|
147
|
-
const baseLogger = (0, __rspack_external__c15t_logger_04a510d4.createLogger)({
|
|
148
|
-
level,
|
|
149
|
-
appName: 'c15t',
|
|
150
|
-
log: (logLevel, message, ...args)=>{
|
|
151
|
-
logMessage(logLevel, message, ...args);
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
const extendedLogger = baseLogger;
|
|
155
|
-
extendedLogger.message = (message)=>{
|
|
156
|
-
prompts_.log.message(message);
|
|
157
|
-
};
|
|
158
|
-
extendedLogger.note = (message, ...args)=>{
|
|
159
|
-
const messageStr = 'string' == typeof message ? message : String(message);
|
|
160
|
-
const title = args.length > 0 && 'string' == typeof args[0] ? args[0] : void 0;
|
|
161
|
-
prompts_.note(messageStr, title, {
|
|
162
|
-
format: (line)=>line
|
|
163
|
-
});
|
|
164
|
-
};
|
|
165
|
-
extendedLogger.success = (message, ...args)=>{
|
|
166
|
-
logMessage('success', message, ...args);
|
|
167
|
-
};
|
|
168
|
-
extendedLogger.failed = (message, ...args)=>{
|
|
169
|
-
logMessage('failed', message, ...args);
|
|
170
|
-
process.exit(0);
|
|
171
|
-
};
|
|
172
|
-
extendedLogger.outro = (message)=>{
|
|
173
|
-
prompts_.outro(message);
|
|
174
|
-
};
|
|
175
|
-
return extendedLogger;
|
|
176
|
-
};
|
|
177
|
-
},
|
|
178
|
-
"@clack/prompts" (module) {
|
|
179
|
-
module.exports = __rspack_external__clack_prompts_3cae1695;
|
|
180
|
-
},
|
|
181
|
-
"node:fs/promises" (module) {
|
|
182
|
-
module.exports = __rspack_external_node_fs_promises_153e37e0;
|
|
183
|
-
},
|
|
184
|
-
"node:path" (module) {
|
|
185
|
-
module.exports = __rspack_external_node_path_c5b9b54f;
|
|
186
|
-
},
|
|
187
|
-
picocolors (module) {
|
|
188
|
-
module.exports = __rspack_external_picocolors;
|
|
189
|
-
}
|
|
190
|
-
};
|
|
191
|
-
var __webpack_module_cache__ = {};
|
|
192
|
-
function __webpack_require__(moduleId) {
|
|
193
|
-
var cachedModule = __webpack_module_cache__[moduleId];
|
|
194
|
-
if (void 0 !== cachedModule) return cachedModule.exports;
|
|
195
|
-
var module = __webpack_module_cache__[moduleId] = {
|
|
196
|
-
exports: {}
|
|
197
|
-
};
|
|
198
|
-
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
|
|
199
|
-
return module.exports;
|
|
200
|
-
}
|
|
201
|
-
__webpack_require__.m = __webpack_modules__;
|
|
202
|
-
(()=>{
|
|
203
|
-
__webpack_require__.d = (exports, definition)=>{
|
|
204
|
-
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) Object.defineProperty(exports, key, {
|
|
205
|
-
enumerable: true,
|
|
206
|
-
get: definition[key]
|
|
207
|
-
});
|
|
208
|
-
};
|
|
209
|
-
})();
|
|
210
|
-
(()=>{
|
|
211
|
-
__webpack_require__.f = {};
|
|
212
|
-
__webpack_require__.e = (chunkId)=>Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key)=>{
|
|
213
|
-
__webpack_require__.f[key](chunkId, promises);
|
|
214
|
-
return promises;
|
|
215
|
-
}, []));
|
|
216
|
-
})();
|
|
217
|
-
(()=>{
|
|
218
|
-
__webpack_require__.u = (chunkId)=>"" + chunkId + ".mjs";
|
|
219
|
-
})();
|
|
220
|
-
(()=>{
|
|
221
|
-
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
222
|
-
})();
|
|
223
|
-
(()=>{
|
|
224
|
-
var installedChunks = {
|
|
225
|
-
410: 0
|
|
226
|
-
};
|
|
227
|
-
var installChunk = (data)=>{
|
|
228
|
-
var __rspack_esm_ids = data.__rspack_esm_ids;
|
|
229
|
-
var __webpack_modules__ = data.__webpack_modules__;
|
|
230
|
-
var __rspack_esm_runtime = data.__rspack_esm_runtime;
|
|
231
|
-
var moduleId, chunkId, i = 0;
|
|
232
|
-
for(moduleId in __webpack_modules__)if (__webpack_require__.o(__webpack_modules__, moduleId)) __webpack_require__.m[moduleId] = __webpack_modules__[moduleId];
|
|
233
|
-
if (__rspack_esm_runtime) __rspack_esm_runtime(__webpack_require__);
|
|
234
|
-
for(; i < __rspack_esm_ids.length; i++){
|
|
235
|
-
chunkId = __rspack_esm_ids[i];
|
|
236
|
-
if (__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) installedChunks[chunkId][0]();
|
|
237
|
-
installedChunks[__rspack_esm_ids[i]] = 0;
|
|
238
|
-
}
|
|
239
|
-
};
|
|
240
|
-
__webpack_require__.f.j = function(chunkId, promises) {
|
|
241
|
-
var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : void 0;
|
|
242
|
-
if (0 !== installedChunkData) if (installedChunkData) promises.push(installedChunkData[1]);
|
|
243
|
-
else {
|
|
244
|
-
var promise = import("./" + __webpack_require__.u(chunkId)).then(installChunk, (e)=>{
|
|
245
|
-
if (0 !== installedChunks[chunkId]) installedChunks[chunkId] = void 0;
|
|
246
|
-
throw e;
|
|
247
|
-
});
|
|
248
|
-
var promise = Promise.race([
|
|
249
|
-
promise,
|
|
250
|
-
new Promise((resolve)=>{
|
|
251
|
-
installedChunkData = installedChunks[chunkId] = [
|
|
252
|
-
resolve
|
|
253
|
-
];
|
|
254
|
-
})
|
|
255
|
-
]);
|
|
256
|
-
promises.push(installedChunkData[1] = promise);
|
|
257
|
-
}
|
|
258
|
-
};
|
|
259
|
-
})();
|
|
260
|
-
var prompts_ = __webpack_require__("@clack/prompts");
|
|
261
|
-
var external_picocolors_ = __webpack_require__("picocolors");
|
|
262
|
-
function showHelpMenu(context, version, commands, flags) {
|
|
263
|
-
const { logger } = context;
|
|
264
|
-
logger.debug('Displaying help menu using command and flag structures.');
|
|
265
|
-
const commandLines = commands.map((cmd)=>` ${cmd.name.padEnd(10)} ${cmd.description}`).join('\n');
|
|
266
|
-
const optionLines = flags.map((flag)=>{
|
|
267
|
-
const names = flag.names.join(', ');
|
|
268
|
-
const valuePlaceholder = flag.expectsValue ? ' <value>' : '';
|
|
269
|
-
return ` ${(names + valuePlaceholder).padEnd(20)} ${flag.description}`;
|
|
270
|
-
}).join('\n');
|
|
271
|
-
const helpContent = `c15t CLI version ${version}
|
|
272
|
-
|
|
273
|
-
Available Commands:
|
|
274
|
-
${commandLines}
|
|
275
|
-
|
|
276
|
-
Options:
|
|
277
|
-
${optionLines}
|
|
278
|
-
|
|
279
|
-
Run a command directly (e.g., ${external_picocolors_["default"].cyan('c15t generate')}) or select one interactively when no command is provided.
|
|
280
|
-
|
|
281
|
-
For more help, visit: https://c15t.dev`;
|
|
282
|
-
logger.debug('Help menu content generated.');
|
|
283
|
-
logger.note(helpContent, 'Usage');
|
|
284
|
-
}
|
|
285
|
-
const TELEMETRY_DISABLED_ENV = 'C15T_TELEMETRY_DISABLED';
|
|
286
|
-
const TelemetryEventName = {
|
|
287
|
-
CLI_INVOKED: 'cli.invoked',
|
|
288
|
-
CLI_COMPLETED: 'cli.completed',
|
|
289
|
-
CLI_EXITED: 'cli.exited',
|
|
290
|
-
CLI_ENVIRONMENT_DETECTED: 'cli.environment_detected',
|
|
291
|
-
COMMAND_EXECUTED: 'command.executed',
|
|
292
|
-
COMMAND_SUCCEEDED: 'command.succeeded',
|
|
293
|
-
COMMAND_FAILED: 'command.failed',
|
|
294
|
-
COMMAND_UNKNOWN: 'command.unknown',
|
|
295
|
-
INTERACTIVE_MENU_OPENED: 'ui.menu.opened',
|
|
296
|
-
INTERACTIVE_MENU_EXITED: 'ui.menu.exited',
|
|
297
|
-
CONFIG_LOADED: 'config.loaded',
|
|
298
|
-
CONFIG_ERROR: 'config.error',
|
|
299
|
-
CONFIG_UPDATED: 'config.updated',
|
|
300
|
-
HELP_DISPLAYED: 'help.displayed',
|
|
301
|
-
VERSION_DISPLAYED: 'version.displayed',
|
|
302
|
-
ONBOARDING_STARTED: 'onboarding.started',
|
|
303
|
-
ONBOARDING_COMPLETED: 'onboarding.completed',
|
|
304
|
-
ONBOARDING_EXITED: 'onboarding.exited',
|
|
305
|
-
ONBOARDING_STORAGE_MODE_SELECTED: 'onboarding.storage_mode_selected',
|
|
306
|
-
ONBOARDING_C15T_MODE_CONFIGURED: 'onboarding.c15t_mode_configured',
|
|
307
|
-
ONBOARDING_OFFLINE_MODE_CONFIGURED: 'onboarding.offline_mode_configured',
|
|
308
|
-
ONBOARDING_SELF_HOSTED_CONFIGURED: 'onboarding.self_hosted_configured',
|
|
309
|
-
ONBOARDING_CUSTOM_MODE_CONFIGURED: 'onboarding.custom_mode_configured',
|
|
310
|
-
ONBOARDING_DEPENDENCIES_CHOICE: 'onboarding.dependencies_choice',
|
|
311
|
-
ONBOARDING_DEPENDENCIES_INSTALLED: 'onboarding.dependencies_installed',
|
|
312
|
-
ONBOARDING_GITHUB_STAR: 'onboarding.github_star',
|
|
313
|
-
ERROR_OCCURRED: 'error.occurred',
|
|
314
|
-
MIGRATION_STARTED: 'migration.started',
|
|
315
|
-
MIGRATION_PLANNED: 'migration.planned',
|
|
316
|
-
MIGRATION_EXECUTED: 'migration.executed',
|
|
317
|
-
MIGRATION_COMPLETED: 'migration.completed',
|
|
318
|
-
MIGRATION_FAILED: 'migration.failed',
|
|
319
|
-
GENERATE_STARTED: 'generate.started',
|
|
320
|
-
GENERATE_COMPLETED: 'generate.completed',
|
|
321
|
-
GENERATE_FAILED: 'generate.failed',
|
|
322
|
-
SELF_HOST_STARTED: 'self-host.started',
|
|
323
|
-
SELF_HOST_COMPLETED: 'self-host.completed',
|
|
324
|
-
SELF_HOST_FAILED: 'self-host.failed',
|
|
325
|
-
CLI_STATE_TRANSITION: 'cli.state.transition',
|
|
326
|
-
CLI_STATE_ERROR: 'cli.state.error',
|
|
327
|
-
CLI_STATE_CANCELLED: 'cli.state.cancelled',
|
|
328
|
-
CLI_STATE_COMPLETE: 'cli.state.complete'
|
|
329
|
-
};
|
|
330
|
-
class Telemetry {
|
|
331
|
-
client = null;
|
|
332
|
-
disabled;
|
|
333
|
-
defaultProperties;
|
|
334
|
-
distinctId;
|
|
335
|
-
apiKey = 'phc_ViY5LtTmh4kqoumXZB2olPFoTz4AbbDfrogNgFi1MH3';
|
|
336
|
-
debug;
|
|
337
|
-
logger;
|
|
338
|
-
constructor(options){
|
|
339
|
-
const envDisabled = '1' === process.env[TELEMETRY_DISABLED_ENV] || process.env[TELEMETRY_DISABLED_ENV]?.toLowerCase() === 'true';
|
|
340
|
-
const hasValidApiKey = !!(this.apiKey && '' !== this.apiKey.trim());
|
|
341
|
-
this.disabled = options?.disabled ?? envDisabled ?? !hasValidApiKey;
|
|
342
|
-
this.defaultProperties = options?.defaultProperties ?? {};
|
|
343
|
-
this.logger = options?.logger;
|
|
344
|
-
this.debug = options?.debug ?? false;
|
|
345
|
-
this.distinctId = this.generateAnonymousId();
|
|
346
|
-
if (this.disabled) {
|
|
347
|
-
if (!hasValidApiKey) this.logDebug('Telemetry disabled: No API key provided');
|
|
348
|
-
} else try {
|
|
349
|
-
this.initClient(options?.client);
|
|
350
|
-
} catch (error) {
|
|
351
|
-
this.disabled = true;
|
|
352
|
-
this.logDebug('Telemetry disabled due to initialization error:', error);
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
trackEvent(eventName, properties = {}) {
|
|
356
|
-
if (this.disabled || !this.client) {
|
|
357
|
-
if (this.debug) this.logDebug(`Telemetry event skipped (${eventName}): Telemetry disabled or client not initialized`);
|
|
358
|
-
return;
|
|
359
|
-
}
|
|
360
|
-
try {
|
|
361
|
-
const safeProperties = {};
|
|
362
|
-
for (const [key, value] of Object.entries(properties))if ('config' !== key && void 0 !== value) safeProperties[key] = value;
|
|
363
|
-
if (this.debug) this.logDebug(`Sending telemetry event: ${eventName}`);
|
|
364
|
-
this.client.capture({
|
|
365
|
-
distinctId: this.distinctId,
|
|
366
|
-
event: eventName,
|
|
367
|
-
properties: {
|
|
368
|
-
...this.defaultProperties,
|
|
369
|
-
...safeProperties,
|
|
370
|
-
timestamp: new Date().toISOString()
|
|
371
|
-
}
|
|
372
|
-
});
|
|
373
|
-
this.client.flush();
|
|
374
|
-
} catch (error) {
|
|
375
|
-
if (this.debug) this.logDebug(`Error sending telemetry event ${eventName}:`, error);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
trackEventSync(eventName, properties = {}) {
|
|
379
|
-
if (this.disabled || !this.client) {
|
|
380
|
-
if (this.debug) this.logDebug('Telemetry disabled or client not initialized');
|
|
381
|
-
return;
|
|
382
|
-
}
|
|
383
|
-
const safeProperties = {};
|
|
384
|
-
for (const [key, value] of Object.entries(properties))if ('config' !== key && void 0 !== value) safeProperties[key] = value;
|
|
385
|
-
if (this.debug) this.logDebug(`Sending telemetry event: ${eventName}`);
|
|
386
|
-
try {
|
|
387
|
-
this.client.capture({
|
|
388
|
-
distinctId: this.distinctId,
|
|
389
|
-
event: eventName,
|
|
390
|
-
properties: {
|
|
391
|
-
...this.defaultProperties,
|
|
392
|
-
...safeProperties,
|
|
393
|
-
timestamp: new Date().toISOString()
|
|
394
|
-
}
|
|
395
|
-
});
|
|
396
|
-
this.client.flush();
|
|
397
|
-
if (this.debug) this.logDebug(`Flushed telemetry event: ${eventName}`);
|
|
398
|
-
} catch (error) {
|
|
399
|
-
if (this.debug) this.logDebug(`Error sending telemetry: ${error}`);
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
trackCommand(command, args = [], flags = {}) {
|
|
403
|
-
if (this.disabled || !this.client) return;
|
|
404
|
-
const safeFlags = {};
|
|
405
|
-
for (const [key, value] of Object.entries(flags))if ('config' !== key && void 0 !== value) safeFlags[key] = value;
|
|
406
|
-
this.trackEvent(TelemetryEventName.COMMAND_EXECUTED, {
|
|
407
|
-
command,
|
|
408
|
-
args: args.join(' '),
|
|
409
|
-
flagsData: JSON.stringify(safeFlags)
|
|
410
|
-
});
|
|
411
|
-
}
|
|
412
|
-
trackError(error, command) {
|
|
413
|
-
if (this.disabled || !this.client) return;
|
|
414
|
-
this.trackEvent(TelemetryEventName.ERROR_OCCURRED, {
|
|
415
|
-
command,
|
|
416
|
-
error: error.message,
|
|
417
|
-
errorName: error.name,
|
|
418
|
-
stack: 'development' === process.env.NODE_ENV ? error.stack : void 0
|
|
419
|
-
});
|
|
420
|
-
}
|
|
421
|
-
disable() {
|
|
422
|
-
this.disabled = true;
|
|
423
|
-
}
|
|
424
|
-
enable() {
|
|
425
|
-
this.disabled = false;
|
|
426
|
-
if (!this.client) this.initClient();
|
|
427
|
-
}
|
|
428
|
-
isDisabled() {
|
|
429
|
-
return this.disabled;
|
|
430
|
-
}
|
|
431
|
-
async shutdown() {
|
|
432
|
-
if (this.client) {
|
|
433
|
-
await this.client.shutdown();
|
|
434
|
-
this.client = null;
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
setLogger(logger) {
|
|
438
|
-
this.logger = logger;
|
|
439
|
-
}
|
|
440
|
-
logDebug(message, ...args) {
|
|
441
|
-
if (this.logger) this.logger.debug(message, ...args);
|
|
442
|
-
else console.debug(message, ...args);
|
|
443
|
-
}
|
|
444
|
-
initClient(customClient) {
|
|
445
|
-
if (customClient) {
|
|
446
|
-
this.client = customClient;
|
|
447
|
-
if (this.debug) this.logDebug('Using custom PostHog client');
|
|
448
|
-
} else {
|
|
449
|
-
if (!this.apiKey || '' === this.apiKey.trim()) {
|
|
450
|
-
this.disabled = true;
|
|
451
|
-
this.logDebug('Telemetry disabled: No API key provided');
|
|
452
|
-
return;
|
|
453
|
-
}
|
|
454
|
-
const startTime = Date.now();
|
|
455
|
-
try {
|
|
456
|
-
const clientConfig = {
|
|
457
|
-
host: 'https://eu.i.posthog.com',
|
|
458
|
-
flushInterval: 0,
|
|
459
|
-
flushAt: 1,
|
|
460
|
-
requestTimeout: 3000
|
|
461
|
-
};
|
|
462
|
-
if (this.debug) this.logDebug('Initializing PostHog client with config:', JSON.stringify(clientConfig));
|
|
463
|
-
this.client = new __rspack_external_posthog_node_1b07bdf4.PostHog(this.apiKey, clientConfig);
|
|
464
|
-
const initTime = Date.now() - startTime;
|
|
465
|
-
if (this.debug) this.logDebug('PostHog client initialized in', initTime, 'ms');
|
|
466
|
-
} catch (error) {
|
|
467
|
-
this.disabled = true;
|
|
468
|
-
const errorDetails = error instanceof Error ? {
|
|
469
|
-
message: error.message,
|
|
470
|
-
name: error.name,
|
|
471
|
-
stack: error.stack
|
|
472
|
-
} : {
|
|
473
|
-
rawError: String(error)
|
|
474
|
-
};
|
|
475
|
-
if (this.debug) this.logDebug('Telemetry disabled due to initialization error:', JSON.stringify(errorDetails, null, 2));
|
|
476
|
-
try {
|
|
477
|
-
if (this.debug) this.logDebug('Attempting fallback PostHog initialization');
|
|
478
|
-
this.client = new __rspack_external_posthog_node_1b07bdf4.PostHog(this.apiKey);
|
|
479
|
-
this.disabled = false;
|
|
480
|
-
if (this.debug) this.logDebug('PostHog client initialized using fallback method');
|
|
481
|
-
} catch (fallbackError) {
|
|
482
|
-
this.logDebug('Fallback initialization also failed:', fallbackError instanceof Error ? fallbackError.message : String(fallbackError));
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
generateAnonymousId() {
|
|
488
|
-
const machineId = __rspack_external_node_crypto_9ba42079["default"].createHash('sha256').update(__rspack_external_node_os_74b4b876["default"].hostname() + __rspack_external_node_os_74b4b876["default"].platform() + __rspack_external_node_os_74b4b876["default"].arch() + __rspack_external_node_os_74b4b876["default"].totalmem()).digest('hex');
|
|
489
|
-
return machineId;
|
|
490
|
-
}
|
|
491
|
-
flushSync() {
|
|
492
|
-
if (this.disabled || !this.client) return;
|
|
493
|
-
try {
|
|
494
|
-
this.client.flush();
|
|
495
|
-
if (this.debug) this.logDebug('Manually flushed telemetry events');
|
|
496
|
-
} catch (error) {
|
|
497
|
-
if (this.debug) this.logDebug(`Error flushing telemetry: ${error}`);
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
function createTelemetry(options) {
|
|
502
|
-
return new Telemetry(options);
|
|
503
|
-
}
|
|
504
|
-
var external_node_path_ = __webpack_require__("node:path");
|
|
505
|
-
const DEFAULT_PERSIST_FILENAME = '.c15t-state.json';
|
|
506
|
-
function getPersistPath(projectRoot) {
|
|
507
|
-
return external_node_path_["default"].join(projectRoot, DEFAULT_PERSIST_FILENAME);
|
|
508
|
-
}
|
|
509
|
-
const NON_SERIALIZABLE_FIELDS = new Set([
|
|
510
|
-
'cliContext',
|
|
511
|
-
'spinner',
|
|
512
|
-
'_parent',
|
|
513
|
-
'_actorScope',
|
|
514
|
-
'_processingStatus',
|
|
515
|
-
'_systemId',
|
|
516
|
-
'logic',
|
|
517
|
-
'src',
|
|
518
|
-
'system',
|
|
519
|
-
'self',
|
|
520
|
-
'_snapshot'
|
|
521
|
-
]);
|
|
522
|
-
function makeSerializable(obj, seen = new WeakSet()) {
|
|
523
|
-
if (null == obj) return obj;
|
|
524
|
-
if ('object' != typeof obj) return obj;
|
|
525
|
-
if (seen.has(obj)) return '[Circular]';
|
|
526
|
-
seen.add(obj);
|
|
527
|
-
if (Array.isArray(obj)) return obj.map((item)=>makeSerializable(item, seen));
|
|
528
|
-
if (obj instanceof Date) return obj.toISOString();
|
|
529
|
-
if (obj instanceof Map) return Object.fromEntries(Array.from(obj.entries()).map(([k, v])=>[
|
|
530
|
-
k,
|
|
531
|
-
makeSerializable(v, seen)
|
|
532
|
-
]));
|
|
533
|
-
if (obj instanceof Set) return Array.from(obj).map((v)=>makeSerializable(v, seen));
|
|
534
|
-
const result = {};
|
|
535
|
-
for (const [key, value] of Object.entries(obj))if (!NON_SERIALIZABLE_FIELDS.has(key)) {
|
|
536
|
-
if ('function' != typeof value && 'symbol' != typeof value) result[key] = makeSerializable(value, seen);
|
|
537
|
-
}
|
|
538
|
-
return result;
|
|
539
|
-
}
|
|
540
|
-
async function saveSnapshot(snapshot, machineId, persistPath) {
|
|
541
|
-
const fs = await import("node:fs/promises");
|
|
542
|
-
const serializableSnapshot = makeSerializable(snapshot);
|
|
543
|
-
const persisted = {
|
|
544
|
-
machineId,
|
|
545
|
-
version: 1,
|
|
546
|
-
savedAt: Date.now(),
|
|
547
|
-
snapshot: serializableSnapshot
|
|
548
|
-
};
|
|
549
|
-
await fs.writeFile(persistPath, JSON.stringify(persisted, null, 2), 'utf-8');
|
|
550
|
-
}
|
|
551
|
-
async function loadSnapshot(persistPath, machineId) {
|
|
552
|
-
const fs = await import("node:fs/promises");
|
|
553
|
-
try {
|
|
554
|
-
const content = await fs.readFile(persistPath, 'utf-8');
|
|
555
|
-
const persisted = JSON.parse(content);
|
|
556
|
-
if (persisted.machineId !== machineId) return null;
|
|
557
|
-
const maxAge = 86400000;
|
|
558
|
-
if (Date.now() - persisted.savedAt > maxAge) {
|
|
559
|
-
await clearSnapshot(persistPath);
|
|
560
|
-
return null;
|
|
561
|
-
}
|
|
562
|
-
return persisted.snapshot;
|
|
563
|
-
} catch {
|
|
564
|
-
return null;
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
async function clearSnapshot(persistPath) {
|
|
568
|
-
const fs = await import("node:fs/promises");
|
|
569
|
-
try {
|
|
570
|
-
await fs.unlink(persistPath);
|
|
571
|
-
} catch {}
|
|
572
|
-
}
|
|
573
|
-
async function hasPersistedState(persistPath) {
|
|
574
|
-
const fs = await import("node:fs/promises");
|
|
575
|
-
try {
|
|
576
|
-
await fs.access(persistPath);
|
|
577
|
-
return true;
|
|
578
|
-
} catch {
|
|
579
|
-
return false;
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
function createPersistenceSubscriber(machineId, persistPath, options = {}) {
|
|
583
|
-
const { persistStates, skipStates = [
|
|
584
|
-
'exited',
|
|
585
|
-
'complete',
|
|
586
|
-
'error'
|
|
587
|
-
] } = options;
|
|
588
|
-
return (snapshot)=>{
|
|
589
|
-
const stateValue = String(snapshot.value);
|
|
590
|
-
if (skipStates.includes(stateValue)) return void clearSnapshot(persistPath).catch(()=>{});
|
|
591
|
-
if (persistStates && !persistStates.includes(stateValue)) return;
|
|
592
|
-
saveSnapshot(snapshot, machineId, persistPath).catch((error)=>{
|
|
593
|
-
console.error('Failed to persist state:', error);
|
|
594
|
-
});
|
|
595
|
-
};
|
|
596
|
-
}
|
|
597
|
-
function createTelemetrySubscriber(config) {
|
|
598
|
-
const { telemetry, machineId, skipStates = [] } = config;
|
|
599
|
-
let lastState = null;
|
|
600
|
-
let lastStateTime = Date.now();
|
|
601
|
-
const stateHistory = [];
|
|
602
|
-
return (snapshot)=>{
|
|
603
|
-
const currentState = String(snapshot.value);
|
|
604
|
-
const now = Date.now();
|
|
605
|
-
if (currentState === lastState) return;
|
|
606
|
-
if (skipStates.includes(currentState)) return;
|
|
607
|
-
if (null !== lastState) {
|
|
608
|
-
const duration = now - lastStateTime;
|
|
609
|
-
telemetry.trackEvent(TelemetryEventName.CLI_STATE_TRANSITION, {
|
|
610
|
-
machineId,
|
|
611
|
-
fromState: lastState,
|
|
612
|
-
toState: currentState,
|
|
613
|
-
duration
|
|
614
|
-
});
|
|
615
|
-
}
|
|
616
|
-
stateHistory.push({
|
|
617
|
-
state: currentState,
|
|
618
|
-
timestamp: now
|
|
619
|
-
});
|
|
620
|
-
if ('error' === currentState || 'preflightError' === currentState) {
|
|
621
|
-
const ctx = snapshot.context;
|
|
622
|
-
const errors = ctx?.errors;
|
|
623
|
-
const lastError = errors?.[errors.length - 1];
|
|
624
|
-
telemetry.trackEvent(TelemetryEventName.CLI_STATE_ERROR, {
|
|
625
|
-
machineId,
|
|
626
|
-
state: currentState,
|
|
627
|
-
error: lastError?.error?.message ?? 'Unknown error',
|
|
628
|
-
stateHistory: stateHistory.map((e)=>e.state).join(',')
|
|
629
|
-
});
|
|
630
|
-
}
|
|
631
|
-
if ('exited' === currentState || 'cancelled' === currentState) telemetry.trackEvent(TelemetryEventName.CLI_STATE_CANCELLED, {
|
|
632
|
-
machineId,
|
|
633
|
-
lastState: lastState ?? 'unknown',
|
|
634
|
-
stateHistory: stateHistory.map((e)=>e.state).join(',')
|
|
635
|
-
});
|
|
636
|
-
if ('complete' === currentState || 'success' === currentState) {
|
|
637
|
-
const totalDuration = now - (stateHistory[0]?.timestamp ?? now);
|
|
638
|
-
telemetry.trackEvent(TelemetryEventName.CLI_STATE_COMPLETE, {
|
|
639
|
-
machineId,
|
|
640
|
-
totalDuration,
|
|
641
|
-
statesVisited: stateHistory.length,
|
|
642
|
-
stateHistory: stateHistory.map((e)=>e.state).join(',')
|
|
643
|
-
});
|
|
644
|
-
}
|
|
645
|
-
lastState = currentState;
|
|
646
|
-
lastStateTime = now;
|
|
647
|
-
};
|
|
648
|
-
}
|
|
649
|
-
function combineSubscribers(...subscribers) {
|
|
650
|
-
return (snapshot)=>{
|
|
651
|
-
for (const subscriber of subscribers)try {
|
|
652
|
-
subscriber(snapshot);
|
|
653
|
-
} catch (error) {
|
|
654
|
-
console.error('Subscriber error:', error);
|
|
655
|
-
}
|
|
656
|
-
};
|
|
657
|
-
}
|
|
658
|
-
function createDebugSubscriber(machineId, logger) {
|
|
659
|
-
let lastState = null;
|
|
660
|
-
return (snapshot)=>{
|
|
661
|
-
const currentState = String(snapshot.value);
|
|
662
|
-
if (currentState !== lastState) {
|
|
663
|
-
const log = logger?.debug ?? console.debug;
|
|
664
|
-
log(`[${machineId}] State: ${lastState ?? 'initial'} -> ${currentState}`);
|
|
665
|
-
lastState = currentState;
|
|
666
|
-
}
|
|
667
|
-
};
|
|
668
|
-
}
|
|
669
|
-
async function runPackageManagerInstall(projectRoot, dependencies, packageManager) {
|
|
670
|
-
if (0 === dependencies.length) return;
|
|
671
|
-
let command;
|
|
672
|
-
let args;
|
|
673
|
-
switch(packageManager){
|
|
674
|
-
case 'npm':
|
|
675
|
-
command = 'npm';
|
|
676
|
-
args = [
|
|
677
|
-
'install',
|
|
678
|
-
...dependencies
|
|
679
|
-
];
|
|
680
|
-
break;
|
|
681
|
-
case 'yarn':
|
|
682
|
-
command = 'yarn';
|
|
683
|
-
args = [
|
|
684
|
-
'add',
|
|
685
|
-
...dependencies
|
|
686
|
-
];
|
|
687
|
-
break;
|
|
688
|
-
case 'pnpm':
|
|
689
|
-
command = 'pnpm';
|
|
690
|
-
args = [
|
|
691
|
-
'add',
|
|
692
|
-
...dependencies
|
|
693
|
-
];
|
|
694
|
-
break;
|
|
695
|
-
case 'bun':
|
|
696
|
-
command = 'bun';
|
|
697
|
-
args = [
|
|
698
|
-
'add',
|
|
699
|
-
...dependencies
|
|
700
|
-
];
|
|
701
|
-
break;
|
|
702
|
-
default:
|
|
703
|
-
throw new Error(`Unsupported package manager: ${packageManager}`);
|
|
704
|
-
}
|
|
705
|
-
const child = (0, __rspack_external_node_child_process_27f17141.spawn)(command, args, {
|
|
706
|
-
cwd: projectRoot,
|
|
707
|
-
stdio: 'inherit'
|
|
708
|
-
});
|
|
709
|
-
const [exitCode] = await (0, __rspack_external_node_events_0a6aefe7.once)(child, 'exit');
|
|
710
|
-
if (0 !== exitCode) throw new Error(`Package manager exited with code ${exitCode}`);
|
|
711
|
-
}
|
|
712
|
-
const dependencyInstallActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
|
|
713
|
-
const { cliContext, dependencies } = input;
|
|
714
|
-
const { projectRoot, packageManager, logger } = cliContext;
|
|
715
|
-
if (0 === dependencies.length) return {
|
|
716
|
-
success: true,
|
|
717
|
-
installedDependencies: []
|
|
718
|
-
};
|
|
719
|
-
logger.debug(`Installing dependencies: ${dependencies.join(', ')}`);
|
|
720
|
-
logger.debug(`Using package manager: ${packageManager.name}`);
|
|
721
|
-
try {
|
|
722
|
-
await runPackageManagerInstall(projectRoot, dependencies, packageManager.name);
|
|
723
|
-
return {
|
|
724
|
-
success: true,
|
|
725
|
-
installedDependencies: dependencies
|
|
726
|
-
};
|
|
727
|
-
} catch (error) {
|
|
728
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
729
|
-
logger.error(`Dependency installation failed: ${errorMessage}`);
|
|
730
|
-
return {
|
|
731
|
-
success: false,
|
|
732
|
-
installedDependencies: [],
|
|
733
|
-
error: errorMessage
|
|
734
|
-
};
|
|
735
|
-
}
|
|
736
|
-
});
|
|
737
|
-
function getManualInstallCommand(dependencies, packageManager) {
|
|
738
|
-
switch(packageManager){
|
|
739
|
-
case 'npm':
|
|
740
|
-
return `npm install ${dependencies.join(' ')}`;
|
|
741
|
-
case 'yarn':
|
|
742
|
-
return `yarn add ${dependencies.join(' ')}`;
|
|
743
|
-
case 'pnpm':
|
|
744
|
-
return `pnpm add ${dependencies.join(' ')}`;
|
|
745
|
-
case 'bun':
|
|
746
|
-
return `bun add ${dependencies.join(' ')}`;
|
|
747
|
-
default:
|
|
748
|
-
return `npm install ${dependencies.join(' ')}`;
|
|
749
|
-
}
|
|
750
|
-
}
|
|
751
|
-
const checkDependenciesActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
|
|
752
|
-
const { projectRoot, dependencies } = input;
|
|
753
|
-
const fs = await import("node:fs/promises");
|
|
754
|
-
const path = await import("node:path");
|
|
755
|
-
const installed = [];
|
|
756
|
-
const missing = [];
|
|
757
|
-
try {
|
|
758
|
-
const packageJsonPath = path.join(projectRoot, 'package.json');
|
|
759
|
-
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8'));
|
|
760
|
-
const allDeps = {
|
|
761
|
-
...packageJson.dependencies,
|
|
762
|
-
...packageJson.devDependencies
|
|
763
|
-
};
|
|
764
|
-
for (const dep of dependencies){
|
|
765
|
-
const depName = dep.startsWith('@') ? dep : dep.split('@')[0];
|
|
766
|
-
if (depName && depName in allDeps) installed.push(dep);
|
|
767
|
-
else missing.push(dep);
|
|
768
|
-
}
|
|
769
|
-
} catch {
|
|
770
|
-
missing.push(...dependencies);
|
|
771
|
-
}
|
|
772
|
-
return {
|
|
773
|
-
installed,
|
|
774
|
-
missing
|
|
775
|
-
};
|
|
776
|
-
});
|
|
777
|
-
async function readFileForBackup(filePath) {
|
|
778
|
-
const fs = await import("node:fs/promises");
|
|
779
|
-
try {
|
|
780
|
-
return await fs.readFile(filePath, 'utf-8');
|
|
781
|
-
} catch {
|
|
782
|
-
return null;
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
async function fileExists(filePath) {
|
|
786
|
-
const fs = await import("node:fs/promises");
|
|
787
|
-
try {
|
|
788
|
-
await fs.access(filePath);
|
|
789
|
-
return true;
|
|
790
|
-
} catch {
|
|
791
|
-
return false;
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
async function formatGeneratedFiles(projectRoot, files, logger) {
|
|
795
|
-
const fs = await import("node:fs/promises");
|
|
796
|
-
const { execFile } = await import("node:child_process");
|
|
797
|
-
const { promisify } = await import("node:util");
|
|
798
|
-
const execFileAsync = promisify(execFile);
|
|
799
|
-
const codeFiles = files.filter((f)=>f.endsWith('.ts') || f.endsWith('.tsx') || f.endsWith('.js') || f.endsWith('.jsx'));
|
|
800
|
-
if (0 === codeFiles.length) return;
|
|
801
|
-
const formatters = [
|
|
802
|
-
{
|
|
803
|
-
bin: external_node_path_["default"].join(projectRoot, 'node_modules', '.bin', 'prettier'),
|
|
804
|
-
args: [
|
|
805
|
-
'--write'
|
|
806
|
-
]
|
|
807
|
-
},
|
|
808
|
-
{
|
|
809
|
-
bin: external_node_path_["default"].join(projectRoot, 'node_modules', '.bin', 'biome'),
|
|
810
|
-
args: [
|
|
811
|
-
'format',
|
|
812
|
-
'--write'
|
|
813
|
-
]
|
|
814
|
-
}
|
|
815
|
-
];
|
|
816
|
-
for (const { bin, args } of formatters)try {
|
|
817
|
-
await fs.access(bin);
|
|
818
|
-
await execFileAsync(bin, [
|
|
819
|
-
...args,
|
|
820
|
-
...codeFiles
|
|
821
|
-
], {
|
|
822
|
-
cwd: projectRoot
|
|
823
|
-
});
|
|
824
|
-
logger.debug(`Formatted ${codeFiles.length} files with ${external_node_path_["default"].basename(bin)}`);
|
|
825
|
-
return;
|
|
826
|
-
} catch {}
|
|
827
|
-
logger.debug('No formatter found, skipping formatting');
|
|
828
|
-
}
|
|
829
|
-
const fileGenerationActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
|
|
830
|
-
const { cliContext, mode, backendURL, useEnvFile, proxyNextjs, enableSSR, enableDevTools, uiStyle, expandedTheme, selectedScripts } = input;
|
|
831
|
-
const filesCreated = [];
|
|
832
|
-
const filesModified = [];
|
|
833
|
-
const result = {
|
|
834
|
-
filesCreated: [],
|
|
835
|
-
filesModified: [],
|
|
836
|
-
configPath: null,
|
|
837
|
-
layoutPath: null,
|
|
838
|
-
nextConfigPath: null,
|
|
839
|
-
envPath: null
|
|
840
|
-
};
|
|
841
|
-
const { projectRoot, framework, cwd, logger } = cliContext;
|
|
842
|
-
framework.pkg;
|
|
843
|
-
const { generateFiles } = await __webpack_require__.e("153").then(__webpack_require__.bind(__webpack_require__, "./src/commands/generate/options/utils/generate-files.ts"));
|
|
844
|
-
const spinnerMock = {
|
|
845
|
-
start: (msg)=>logger.debug(`[spinner] ${msg}`),
|
|
846
|
-
stop: (msg)=>logger.debug(`[spinner] ${msg}`),
|
|
847
|
-
message: (msg)=>logger.debug(`[spinner] ${msg}`)
|
|
848
|
-
};
|
|
849
|
-
try {
|
|
850
|
-
const potentialFiles = [
|
|
851
|
-
external_node_path_["default"].join(projectRoot, 'c15t.config.ts'),
|
|
852
|
-
external_node_path_["default"].join(projectRoot, '.env.local'),
|
|
853
|
-
external_node_path_["default"].join(projectRoot, '.env.example'),
|
|
854
|
-
external_node_path_["default"].join(projectRoot, 'next.config.ts'),
|
|
855
|
-
external_node_path_["default"].join(projectRoot, 'next.config.js'),
|
|
856
|
-
external_node_path_["default"].join(projectRoot, 'next.config.mjs')
|
|
857
|
-
];
|
|
858
|
-
for (const filePath of potentialFiles){
|
|
859
|
-
const exists = await fileExists(filePath);
|
|
860
|
-
if (exists) {
|
|
861
|
-
const backup = await readFileForBackup(filePath);
|
|
862
|
-
if (null !== backup) filesModified.push({
|
|
863
|
-
path: filePath,
|
|
864
|
-
backup,
|
|
865
|
-
type: 'modified'
|
|
866
|
-
});
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
const generateResult = await generateFiles({
|
|
870
|
-
context: cliContext,
|
|
871
|
-
mode: mode,
|
|
872
|
-
spinner: spinnerMock,
|
|
873
|
-
backendURL: backendURL ?? void 0,
|
|
874
|
-
useEnvFile,
|
|
875
|
-
proxyNextjs,
|
|
876
|
-
enableSSR,
|
|
877
|
-
enableDevTools,
|
|
878
|
-
uiStyle,
|
|
879
|
-
expandedTheme: expandedTheme ?? void 0,
|
|
880
|
-
selectedScripts
|
|
881
|
-
});
|
|
882
|
-
if (generateResult.configPath) {
|
|
883
|
-
result.configPath = generateResult.configPath;
|
|
884
|
-
if (!filesModified.some((f)=>f.path === generateResult.configPath)) filesCreated.push(generateResult.configPath);
|
|
885
|
-
}
|
|
886
|
-
if (generateResult.layoutPath) result.layoutPath = generateResult.layoutPath;
|
|
887
|
-
if (generateResult.nextConfigPath) {
|
|
888
|
-
result.nextConfigPath = generateResult.nextConfigPath;
|
|
889
|
-
if (generateResult.nextConfigCreated) filesCreated.push(generateResult.nextConfigPath);
|
|
890
|
-
}
|
|
891
|
-
if (useEnvFile && backendURL) {
|
|
892
|
-
const envPath = external_node_path_["default"].join(projectRoot, '.env.local');
|
|
893
|
-
const envExamplePath = external_node_path_["default"].join(projectRoot, '.env.example');
|
|
894
|
-
if (!filesModified.some((f)=>f.path === envPath) && await fileExists(envPath)) filesCreated.push(envPath);
|
|
895
|
-
result.envPath = envPath;
|
|
896
|
-
if (!filesModified.some((f)=>f.path === envExamplePath) && await fileExists(envExamplePath)) filesCreated.push(envExamplePath);
|
|
897
|
-
}
|
|
898
|
-
result.filesCreated = filesCreated;
|
|
899
|
-
result.filesModified = filesModified;
|
|
900
|
-
const allFiles = [
|
|
901
|
-
...filesCreated,
|
|
902
|
-
...filesModified.map((f)=>f.path),
|
|
903
|
-
generateResult.layoutPath
|
|
904
|
-
].filter((f)=>!!f);
|
|
905
|
-
await formatGeneratedFiles(projectRoot, allFiles, logger);
|
|
906
|
-
return result;
|
|
907
|
-
} catch (error) {
|
|
908
|
-
result.filesCreated = filesCreated;
|
|
909
|
-
result.filesModified = filesModified;
|
|
910
|
-
throw error;
|
|
911
|
-
}
|
|
912
|
-
});
|
|
913
|
-
const rollbackActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
|
|
914
|
-
const { filesCreated, filesModified } = input;
|
|
915
|
-
const fs = await import("node:fs/promises");
|
|
916
|
-
const errors = [];
|
|
917
|
-
for (const filePath of filesCreated)try {
|
|
918
|
-
await fs.unlink(filePath);
|
|
919
|
-
} catch (error) {
|
|
920
|
-
errors.push(`Failed to delete ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
921
|
-
}
|
|
922
|
-
for (const mod of filesModified)try {
|
|
923
|
-
await fs.writeFile(mod.path, mod.backup, 'utf-8');
|
|
924
|
-
} catch (error) {
|
|
925
|
-
errors.push(`Failed to restore ${mod.path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
926
|
-
}
|
|
927
|
-
return {
|
|
928
|
-
success: 0 === errors.length,
|
|
929
|
-
errors
|
|
930
|
-
};
|
|
931
|
-
});
|
|
932
|
-
async function preflight_fileExists(filePath) {
|
|
933
|
-
try {
|
|
934
|
-
const fs = await import("node:fs/promises");
|
|
935
|
-
await fs.access(filePath);
|
|
936
|
-
return true;
|
|
937
|
-
} catch {
|
|
938
|
-
return false;
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
async function checkGitStatus(projectRoot) {
|
|
942
|
-
try {
|
|
943
|
-
const gitDir = external_node_path_["default"].join(projectRoot, '.git');
|
|
944
|
-
const isGitRepo = await preflight_fileExists(gitDir);
|
|
945
|
-
if (!isGitRepo) return {
|
|
946
|
-
name: 'Git',
|
|
947
|
-
status: 'warn',
|
|
948
|
-
message: 'Not a git repository',
|
|
949
|
-
hint: 'Consider initializing git to track changes'
|
|
950
|
-
};
|
|
951
|
-
return {
|
|
952
|
-
name: 'Git',
|
|
953
|
-
status: 'pass',
|
|
954
|
-
message: 'Git repository detected'
|
|
955
|
-
};
|
|
956
|
-
} catch {
|
|
957
|
-
return {
|
|
958
|
-
name: 'Git',
|
|
959
|
-
status: 'warn',
|
|
960
|
-
message: 'Could not check git status'
|
|
961
|
-
};
|
|
962
|
-
}
|
|
963
|
-
}
|
|
964
|
-
async function runPreflightChecks(context) {
|
|
965
|
-
const { projectRoot, framework, packageManager, logger } = context;
|
|
966
|
-
const checks = [];
|
|
967
|
-
logger.debug('Running preflight checks...');
|
|
968
|
-
const packageJsonPath = external_node_path_["default"].join(projectRoot, 'package.json');
|
|
969
|
-
const hasPackageJson = await preflight_fileExists(packageJsonPath);
|
|
970
|
-
checks.push({
|
|
971
|
-
name: 'package.json',
|
|
972
|
-
status: hasPackageJson ? 'pass' : 'fail',
|
|
973
|
-
message: hasPackageJson ? 'Found package.json' : 'No package.json found',
|
|
974
|
-
hint: hasPackageJson ? void 0 : 'Make sure you are in a JavaScript/TypeScript project'
|
|
975
|
-
});
|
|
976
|
-
checks.push({
|
|
977
|
-
name: 'Framework',
|
|
978
|
-
status: framework.framework ? 'pass' : 'warn',
|
|
979
|
-
message: framework.framework ? `Detected ${framework.framework}` : 'No framework detected',
|
|
980
|
-
hint: framework.framework ? void 0 : 'Will use vanilla JavaScript setup'
|
|
981
|
-
});
|
|
982
|
-
if ('c15t' !== framework.pkg) checks.push({
|
|
983
|
-
name: 'React',
|
|
984
|
-
status: framework.hasReact ? 'pass' : 'warn',
|
|
985
|
-
message: framework.hasReact ? `Found React ${framework.reactVersion || ''}` : 'React not detected',
|
|
986
|
-
hint: framework.hasReact ? void 0 : 'c15t works best with React'
|
|
987
|
-
});
|
|
988
|
-
checks.push({
|
|
989
|
-
name: 'Package Manager',
|
|
990
|
-
status: packageManager.name ? 'pass' : 'warn',
|
|
991
|
-
message: packageManager.name ? `Using ${packageManager.name}` : 'No package manager detected',
|
|
992
|
-
hint: packageManager.name ? void 0 : 'Will default to npm'
|
|
993
|
-
});
|
|
994
|
-
const gitCheck = await checkGitStatus(projectRoot);
|
|
995
|
-
checks.push(gitCheck);
|
|
996
|
-
const configPath = external_node_path_["default"].join(projectRoot, 'c15t.config.ts');
|
|
997
|
-
const hasExistingConfig = await preflight_fileExists(configPath);
|
|
998
|
-
checks.push({
|
|
999
|
-
name: 'Existing config',
|
|
1000
|
-
status: hasExistingConfig ? 'warn' : 'pass',
|
|
1001
|
-
message: hasExistingConfig ? 'c15t.config.ts already exists' : 'No existing configuration',
|
|
1002
|
-
hint: hasExistingConfig ? 'Existing config will be overwritten' : void 0
|
|
1003
|
-
});
|
|
1004
|
-
const hasFailures = checks.some((c)=>'fail' === c.status);
|
|
1005
|
-
return {
|
|
1006
|
-
passed: !hasFailures,
|
|
1007
|
-
checks,
|
|
1008
|
-
projectRoot,
|
|
1009
|
-
framework: {
|
|
1010
|
-
name: framework.framework,
|
|
1011
|
-
version: framework.frameworkVersion,
|
|
1012
|
-
pkg: framework.pkg,
|
|
1013
|
-
hasReact: framework.hasReact,
|
|
1014
|
-
reactVersion: framework.reactVersion,
|
|
1015
|
-
tailwindVersion: framework.tailwindVersion
|
|
1016
|
-
},
|
|
1017
|
-
packageManager
|
|
1018
|
-
};
|
|
1019
|
-
}
|
|
1020
|
-
const preflightActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
|
|
1021
|
-
const { cliContext } = input;
|
|
1022
|
-
if (!cliContext) throw new Error('CLI context is required for preflight checks');
|
|
1023
|
-
return runPreflightChecks(cliContext);
|
|
1024
|
-
});
|
|
1025
|
-
function getStatusIcon(status) {
|
|
1026
|
-
switch(status){
|
|
1027
|
-
case 'pass':
|
|
1028
|
-
return external_picocolors_["default"].green('✓');
|
|
1029
|
-
case 'warn':
|
|
1030
|
-
return external_picocolors_["default"].yellow('⚠');
|
|
1031
|
-
case 'fail':
|
|
1032
|
-
return external_picocolors_["default"].red('✗');
|
|
1033
|
-
default:
|
|
1034
|
-
return ' ';
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
function displayPreflightResults(context, checks) {
|
|
1038
|
-
const { logger } = context;
|
|
1039
|
-
const lines = [];
|
|
1040
|
-
lines.push('');
|
|
1041
|
-
lines.push(external_picocolors_["default"].bold('Pre-flight checks:'));
|
|
1042
|
-
for (const check of checks){
|
|
1043
|
-
const icon = getStatusIcon(check.status);
|
|
1044
|
-
lines.push(` ${icon} ${check.message}`);
|
|
1045
|
-
if (check.hint && 'pass' !== check.status) lines.push(` ${external_picocolors_["default"].dim(check.hint)}`);
|
|
1046
|
-
}
|
|
1047
|
-
lines.push('');
|
|
1048
|
-
logger.message(lines.join('\n'));
|
|
1049
|
-
}
|
|
1050
|
-
function displayPreflightFailure(context, checks) {
|
|
1051
|
-
const { logger } = context;
|
|
1052
|
-
const lines = [];
|
|
1053
|
-
lines.push(external_picocolors_["default"].red('Pre-flight checks failed'));
|
|
1054
|
-
lines.push('');
|
|
1055
|
-
const failures = checks.filter((c)=>'fail' === c.status);
|
|
1056
|
-
for (const check of failures){
|
|
1057
|
-
lines.push(` ${external_picocolors_["default"].red('•')} ${check.message}`);
|
|
1058
|
-
if (check.hint) lines.push(` ${check.hint}`);
|
|
1059
|
-
}
|
|
1060
|
-
lines.push('');
|
|
1061
|
-
lines.push('Please fix the issues above and try again.');
|
|
1062
|
-
logger.message(lines.join('\n'));
|
|
1063
|
-
}
|
|
1064
|
-
async function getDevToolsOption({ context, handleCancel, onCancel }) {
|
|
1065
|
-
const isReactProject = '@c15t/react' === context.framework.pkg || '@c15t/nextjs' === context.framework.pkg;
|
|
1066
|
-
context.logger.info("c15t DevTools helps you inspect consent state, scripts, and location overrides during development.");
|
|
1067
|
-
context.logger.info('Learn more: https://c15t.com/docs/dev-tools/overview');
|
|
1068
|
-
const enableDevTools = await prompts_.select({
|
|
1069
|
-
message: 'Install and enable c15t DevTools?',
|
|
1070
|
-
options: [
|
|
1071
|
-
{
|
|
1072
|
-
value: true,
|
|
1073
|
-
label: 'Yes (Recommended)',
|
|
1074
|
-
hint: isReactProject ? 'Adds <DevTools /> to generated consent components' : 'Adds createDevTools() setup to c15t.config.ts'
|
|
1075
|
-
},
|
|
1076
|
-
{
|
|
1077
|
-
value: false,
|
|
1078
|
-
label: 'No',
|
|
1079
|
-
hint: 'Skip DevTools installation and setup'
|
|
1080
|
-
}
|
|
1081
|
-
],
|
|
1082
|
-
initialValue: true
|
|
1083
|
-
});
|
|
1084
|
-
const cancelled = handleCancel?.(enableDevTools) ?? prompts_.isCancel(enableDevTools);
|
|
1085
|
-
if (cancelled) {
|
|
1086
|
-
if (onCancel) onCancel();
|
|
1087
|
-
context.error.handleCancel('Setup cancelled.', {
|
|
1088
|
-
command: 'onboarding',
|
|
1089
|
-
stage: 'dev_tools_option'
|
|
1090
|
-
});
|
|
1091
|
-
}
|
|
1092
|
-
return enableDevTools;
|
|
1093
|
-
}
|
|
1094
|
-
async function getSSROption({ context, handleCancel, onCancel }) {
|
|
1095
|
-
context.logger.info('SSR consent prefetch starts data loading on the server for faster banner visibility.');
|
|
1096
|
-
context.logger.info('Tradeoff: this uses Next.js headers() and makes the route dynamic (not fully static).');
|
|
1097
|
-
context.logger.info('On slow backends or cross-region setups, SSR can increase TTFB. Measure both TTFB and banner visibility.');
|
|
1098
|
-
context.logger.info('Learn more: https://c15t.com/docs/frameworks/nextjs/ssr');
|
|
1099
|
-
const enableSSR = await prompts_.select({
|
|
1100
|
-
message: 'Enable SSR consent prefetch? (faster first banner visibility, dynamic route)',
|
|
1101
|
-
options: [
|
|
1102
|
-
{
|
|
1103
|
-
value: true,
|
|
1104
|
-
label: 'Yes (Recommended)',
|
|
1105
|
-
hint: 'Fetch consent data on server and stream to client'
|
|
1106
|
-
},
|
|
1107
|
-
{
|
|
1108
|
-
value: false,
|
|
1109
|
-
label: 'No',
|
|
1110
|
-
hint: 'Client-only fetch after hydration (better for fully static pages)'
|
|
1111
|
-
}
|
|
1112
|
-
],
|
|
1113
|
-
initialValue: true
|
|
1114
|
-
});
|
|
1115
|
-
const cancelled = handleCancel?.(enableSSR) ?? prompts_.isCancel(enableSSR);
|
|
1116
|
-
if (cancelled) {
|
|
1117
|
-
if (onCancel) onCancel();
|
|
1118
|
-
context.error.handleCancel('Setup cancelled.', {
|
|
1119
|
-
command: 'onboarding',
|
|
1120
|
-
stage: 'ssr_option'
|
|
1121
|
-
});
|
|
1122
|
-
}
|
|
1123
|
-
return enableSSR;
|
|
1124
|
-
}
|
|
1125
|
-
function isCancel(value) {
|
|
1126
|
-
return prompts_.isCancel(value);
|
|
1127
|
-
}
|
|
1128
|
-
class PromptCancelledError extends Error {
|
|
1129
|
-
constructor(stage){
|
|
1130
|
-
super(`Prompt cancelled at stage: ${stage}`);
|
|
1131
|
-
this.name = 'PromptCancelledError';
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1134
|
-
const modeSelectionActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
|
|
1135
|
-
const result = await prompts_.select({
|
|
1136
|
-
message: 'How would you like to store consent decisions?',
|
|
1137
|
-
initialValue: input.initialMode ?? 'c15t',
|
|
1138
|
-
options: [
|
|
1139
|
-
{
|
|
1140
|
-
value: 'c15t',
|
|
1141
|
-
label: 'Hosted c15t (consent.io)',
|
|
1142
|
-
hint: 'Recommended: Fully managed service'
|
|
1143
|
-
},
|
|
1144
|
-
{
|
|
1145
|
-
value: 'offline',
|
|
1146
|
-
label: 'Offline Mode',
|
|
1147
|
-
hint: 'Store in browser, no backend needed'
|
|
1148
|
-
},
|
|
1149
|
-
{
|
|
1150
|
-
value: 'self-hosted',
|
|
1151
|
-
label: 'Self-Hosted',
|
|
1152
|
-
hint: 'Run your own c15t backend'
|
|
1153
|
-
},
|
|
1154
|
-
{
|
|
1155
|
-
value: 'custom',
|
|
1156
|
-
label: 'Custom Implementation',
|
|
1157
|
-
hint: 'Full control over storage logic'
|
|
1158
|
-
}
|
|
1159
|
-
]
|
|
1160
|
-
});
|
|
1161
|
-
if (isCancel(result)) throw new PromptCancelledError('mode_selection');
|
|
1162
|
-
return {
|
|
1163
|
-
mode: result
|
|
1164
|
-
};
|
|
1165
|
-
});
|
|
1166
|
-
const accountCreationActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
|
|
1167
|
-
const { cliContext } = input;
|
|
1168
|
-
const needsAccount = await prompts_.confirm({
|
|
1169
|
-
message: 'Do you need to create a consent.io account?',
|
|
1170
|
-
initialValue: true
|
|
1171
|
-
});
|
|
1172
|
-
if (isCancel(needsAccount)) throw new PromptCancelledError('account_creation');
|
|
1173
|
-
if (!needsAccount) return {
|
|
1174
|
-
needsAccount: false,
|
|
1175
|
-
browserOpened: false
|
|
1176
|
-
};
|
|
1177
|
-
prompts_.note(`We'll open your browser to create a consent.io account and set up your instance.\nFollow these steps:\n1. Sign up for a consent.io account\n2. Create a new instance in the dashboard\n3. Configure your trusted origins (domains that can connect)\n4. Copy the provided backendURL (e.g., https://your-instance.c15t.dev)`, 'consent.io Setup');
|
|
1178
|
-
const shouldOpen = await prompts_.confirm({
|
|
1179
|
-
message: 'Open browser to sign up for consent.io?',
|
|
1180
|
-
initialValue: true
|
|
1181
|
-
});
|
|
1182
|
-
if (isCancel(shouldOpen)) throw new PromptCancelledError('browser_open');
|
|
1183
|
-
let browserOpened = false;
|
|
1184
|
-
if (shouldOpen) try {
|
|
1185
|
-
const open = (await import("open")).default;
|
|
1186
|
-
await open('https://consent.io/dashboard/register?ref=cli');
|
|
1187
|
-
browserOpened = true;
|
|
1188
|
-
const enterPressed = await prompts_.text({
|
|
1189
|
-
message: 'Press Enter once you have created your instance and have the backendURL'
|
|
1190
|
-
});
|
|
1191
|
-
if (isCancel(enterPressed)) throw new PromptCancelledError('url_input_wait');
|
|
1192
|
-
} catch (error) {
|
|
1193
|
-
if (error instanceof PromptCancelledError) throw error;
|
|
1194
|
-
cliContext.logger.warn('Failed to open browser automatically. Please visit https://consent.io/dashboard/register manually.');
|
|
1195
|
-
}
|
|
1196
|
-
return {
|
|
1197
|
-
needsAccount: true,
|
|
1198
|
-
browserOpened
|
|
1199
|
-
};
|
|
1200
|
-
});
|
|
1201
|
-
const backendURLActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
|
|
1202
|
-
const { initialURL, isC15tMode } = input;
|
|
1203
|
-
const placeholder = isC15tMode ? 'https://your-instance.c15t.dev' : 'https://your-backend.example.com/api/c15t';
|
|
1204
|
-
const result = await prompts_.text({
|
|
1205
|
-
message: isC15tMode ? 'Enter your consent.io instance URL:' : 'Enter your self-hosted backend URL:',
|
|
1206
|
-
placeholder,
|
|
1207
|
-
initialValue: initialURL,
|
|
1208
|
-
validate: (value)=>{
|
|
1209
|
-
if (!value || '' === value) return 'URL is required';
|
|
1210
|
-
try {
|
|
1211
|
-
const url = new URL(value);
|
|
1212
|
-
if (isC15tMode && !url.hostname.endsWith('.c15t.dev')) return 'Please enter a valid *.c15t.dev URL';
|
|
1213
|
-
} catch {
|
|
1214
|
-
return 'Please enter a valid URL';
|
|
1215
|
-
}
|
|
1216
|
-
}
|
|
1217
|
-
});
|
|
1218
|
-
if (isCancel(result)) throw new PromptCancelledError('backend_url');
|
|
1219
|
-
return {
|
|
1220
|
-
url: result
|
|
1221
|
-
};
|
|
1222
|
-
});
|
|
1223
|
-
const backendOptionsActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
|
|
1224
|
-
const { cliContext } = input;
|
|
1225
|
-
const useEnvFile = await prompts_.confirm({
|
|
1226
|
-
message: 'Store the backendURL in a .env file? (Recommended, URL is public)',
|
|
1227
|
-
initialValue: true
|
|
1228
|
-
});
|
|
1229
|
-
if (isCancel(useEnvFile)) throw new PromptCancelledError('env_file');
|
|
1230
|
-
let proxyNextjs = false;
|
|
1231
|
-
if ('@c15t/nextjs' === cliContext.framework.pkg) {
|
|
1232
|
-
cliContext.logger.info('Learn more about Next.js Rewrites: https://nextjs.org/docs/app/api-reference/config/next-config-js/rewrites');
|
|
1233
|
-
const proxyResult = await prompts_.confirm({
|
|
1234
|
-
message: 'Proxy requests to your instance with Next.js Rewrites? (Recommended)',
|
|
1235
|
-
initialValue: true
|
|
1236
|
-
});
|
|
1237
|
-
if (isCancel(proxyResult)) throw new PromptCancelledError('proxy_nextjs');
|
|
1238
|
-
proxyNextjs = proxyResult;
|
|
1239
|
-
}
|
|
1240
|
-
return {
|
|
1241
|
-
useEnvFile: useEnvFile,
|
|
1242
|
-
proxyNextjs
|
|
1243
|
-
};
|
|
1244
|
-
});
|
|
1245
|
-
const frontendOptionsActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
|
|
1246
|
-
const { cliContext, hasBackend } = input;
|
|
1247
|
-
const pkg = cliContext.framework.pkg;
|
|
1248
|
-
let enableSSR;
|
|
1249
|
-
let enableDevTools = false;
|
|
1250
|
-
let uiStyle = 'prebuilt';
|
|
1251
|
-
let expandedTheme;
|
|
1252
|
-
if ('@c15t/nextjs' === pkg) {
|
|
1253
|
-
if (hasBackend) {
|
|
1254
|
-
const { existsSync } = await import("node:fs");
|
|
1255
|
-
const { join } = await import("node:path");
|
|
1256
|
-
const projectRoot = cliContext.projectRoot;
|
|
1257
|
-
const isAppRouter = [
|
|
1258
|
-
'app/layout.tsx',
|
|
1259
|
-
'src/app/layout.tsx',
|
|
1260
|
-
'app/layout.ts',
|
|
1261
|
-
'src/app/layout.ts'
|
|
1262
|
-
].some((p)=>existsSync(join(projectRoot, p)));
|
|
1263
|
-
if (isAppRouter) enableSSR = await getSSROption({
|
|
1264
|
-
context: cliContext,
|
|
1265
|
-
onCancel: ()=>{
|
|
1266
|
-
throw new PromptCancelledError('ssr_option');
|
|
1267
|
-
}
|
|
1268
|
-
});
|
|
1269
|
-
}
|
|
1270
|
-
cliContext.logger.info('Choose how you want your consent UI components generated.');
|
|
1271
|
-
cliContext.logger.info('Learn more: https://c15t.com/docs/frameworks/nextjs/customization');
|
|
1272
|
-
const styleResult = await prompts_.select({
|
|
1273
|
-
message: 'UI component style:',
|
|
1274
|
-
options: [
|
|
1275
|
-
{
|
|
1276
|
-
value: 'prebuilt',
|
|
1277
|
-
label: 'Prebuilt (Recommended)',
|
|
1278
|
-
hint: 'Ready-to-use components'
|
|
1279
|
-
},
|
|
1280
|
-
{
|
|
1281
|
-
value: 'expanded',
|
|
1282
|
-
label: 'Compound components',
|
|
1283
|
-
hint: 'Full customization control'
|
|
1284
|
-
}
|
|
1285
|
-
],
|
|
1286
|
-
initialValue: 'prebuilt'
|
|
1287
|
-
});
|
|
1288
|
-
if (isCancel(styleResult)) throw new PromptCancelledError('ui_style');
|
|
1289
|
-
uiStyle = styleResult;
|
|
1290
|
-
const themeResult = await prompts_.select({
|
|
1291
|
-
message: 'Theme preset:',
|
|
1292
|
-
options: [
|
|
1293
|
-
{
|
|
1294
|
-
value: 'none',
|
|
1295
|
-
label: 'None',
|
|
1296
|
-
hint: 'No preset styling'
|
|
1297
|
-
},
|
|
1298
|
-
{
|
|
1299
|
-
value: 'minimal',
|
|
1300
|
-
label: 'Minimal',
|
|
1301
|
-
hint: 'Clean light theme'
|
|
1302
|
-
},
|
|
1303
|
-
{
|
|
1304
|
-
value: 'dark',
|
|
1305
|
-
label: 'Dark',
|
|
1306
|
-
hint: 'High contrast dark mode'
|
|
1307
|
-
},
|
|
1308
|
-
{
|
|
1309
|
-
value: 'tailwind',
|
|
1310
|
-
label: 'Tailwind',
|
|
1311
|
-
hint: 'Uses Tailwind utility classes'
|
|
1312
|
-
}
|
|
1313
|
-
],
|
|
1314
|
-
initialValue: 'none'
|
|
1315
|
-
});
|
|
1316
|
-
if (isCancel(themeResult)) throw new PromptCancelledError('expanded_theme');
|
|
1317
|
-
expandedTheme = themeResult;
|
|
1318
|
-
}
|
|
1319
|
-
if ('@c15t/react' === pkg) {
|
|
1320
|
-
cliContext.logger.info('Choose how you want your consent UI components generated.');
|
|
1321
|
-
const styleResult = await prompts_.select({
|
|
1322
|
-
message: 'UI component style:',
|
|
1323
|
-
options: [
|
|
1324
|
-
{
|
|
1325
|
-
value: 'prebuilt',
|
|
1326
|
-
label: 'Prebuilt (Recommended)',
|
|
1327
|
-
hint: 'Ready-to-use components'
|
|
1328
|
-
},
|
|
1329
|
-
{
|
|
1330
|
-
value: 'expanded',
|
|
1331
|
-
label: 'Compound components',
|
|
1332
|
-
hint: 'Full customization control'
|
|
1333
|
-
}
|
|
1334
|
-
],
|
|
1335
|
-
initialValue: 'prebuilt'
|
|
1336
|
-
});
|
|
1337
|
-
if (isCancel(styleResult)) throw new PromptCancelledError('ui_style');
|
|
1338
|
-
uiStyle = styleResult;
|
|
1339
|
-
const reactThemeResult = await prompts_.select({
|
|
1340
|
-
message: 'Theme preset:',
|
|
1341
|
-
options: [
|
|
1342
|
-
{
|
|
1343
|
-
value: 'none',
|
|
1344
|
-
label: 'None',
|
|
1345
|
-
hint: 'No preset styling'
|
|
1346
|
-
},
|
|
1347
|
-
{
|
|
1348
|
-
value: 'minimal',
|
|
1349
|
-
label: 'Minimal',
|
|
1350
|
-
hint: 'Clean light theme'
|
|
1351
|
-
},
|
|
1352
|
-
{
|
|
1353
|
-
value: 'dark',
|
|
1354
|
-
label: 'Dark',
|
|
1355
|
-
hint: 'High contrast dark mode'
|
|
1356
|
-
},
|
|
1357
|
-
{
|
|
1358
|
-
value: 'tailwind',
|
|
1359
|
-
label: 'Tailwind',
|
|
1360
|
-
hint: 'Uses Tailwind utility classes'
|
|
1361
|
-
}
|
|
1362
|
-
],
|
|
1363
|
-
initialValue: 'none'
|
|
1364
|
-
});
|
|
1365
|
-
if (isCancel(reactThemeResult)) throw new PromptCancelledError('expanded_theme');
|
|
1366
|
-
expandedTheme = reactThemeResult;
|
|
1367
|
-
}
|
|
1368
|
-
if ('c15t' === pkg || '@c15t/react' === pkg || '@c15t/nextjs' === pkg) enableDevTools = await getDevToolsOption({
|
|
1369
|
-
context: cliContext,
|
|
1370
|
-
onCancel: ()=>{
|
|
1371
|
-
throw new PromptCancelledError('dev_tools_option');
|
|
1372
|
-
}
|
|
1373
|
-
});
|
|
1374
|
-
return {
|
|
1375
|
-
enableSSR,
|
|
1376
|
-
enableDevTools,
|
|
1377
|
-
uiStyle,
|
|
1378
|
-
expandedTheme
|
|
1379
|
-
};
|
|
1380
|
-
});
|
|
1381
|
-
const AVAILABLE_SCRIPTS = [
|
|
1382
|
-
{
|
|
1383
|
-
value: 'google-tag-manager',
|
|
1384
|
-
label: 'Google Tag Manager',
|
|
1385
|
-
hint: "GTM container script"
|
|
1386
|
-
},
|
|
1387
|
-
{
|
|
1388
|
-
value: 'google-tag',
|
|
1389
|
-
label: 'Google Tag (gtag.js)',
|
|
1390
|
-
hint: 'Google Analytics 4'
|
|
1391
|
-
},
|
|
1392
|
-
{
|
|
1393
|
-
value: 'meta-pixel',
|
|
1394
|
-
label: 'Meta Pixel',
|
|
1395
|
-
hint: 'Facebook/Instagram tracking'
|
|
1396
|
-
},
|
|
1397
|
-
{
|
|
1398
|
-
value: 'posthog',
|
|
1399
|
-
label: 'PostHog',
|
|
1400
|
-
hint: 'Product analytics'
|
|
1401
|
-
},
|
|
1402
|
-
{
|
|
1403
|
-
value: 'linkedin-insights',
|
|
1404
|
-
label: 'LinkedIn Insight Tag',
|
|
1405
|
-
hint: 'LinkedIn conversion tracking'
|
|
1406
|
-
},
|
|
1407
|
-
{
|
|
1408
|
-
value: 'tiktok-pixel',
|
|
1409
|
-
label: 'TikTok Pixel',
|
|
1410
|
-
hint: 'TikTok ads tracking'
|
|
1411
|
-
},
|
|
1412
|
-
{
|
|
1413
|
-
value: 'x-pixel',
|
|
1414
|
-
label: 'X (Twitter) Pixel',
|
|
1415
|
-
hint: 'X/Twitter conversion tracking'
|
|
1416
|
-
},
|
|
1417
|
-
{
|
|
1418
|
-
value: 'microsoft-uet',
|
|
1419
|
-
label: 'Microsoft UET',
|
|
1420
|
-
hint: 'Bing Ads tracking'
|
|
1421
|
-
},
|
|
1422
|
-
{
|
|
1423
|
-
value: 'databuddy',
|
|
1424
|
-
label: 'Databuddy',
|
|
1425
|
-
hint: 'Data collection'
|
|
1426
|
-
}
|
|
1427
|
-
];
|
|
1428
|
-
const scriptsOptionActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
|
|
1429
|
-
const { cliContext } = input;
|
|
1430
|
-
cliContext.logger.info("The @c15t/scripts package provides pre-configured third-party scripts with consent management.");
|
|
1431
|
-
const addScripts = await prompts_.confirm({
|
|
1432
|
-
message: "Add @c15t/scripts for third-party script management?",
|
|
1433
|
-
initialValue: true
|
|
1434
|
-
});
|
|
1435
|
-
if (isCancel(addScripts)) throw new PromptCancelledError("scripts_option");
|
|
1436
|
-
if (!addScripts) return {
|
|
1437
|
-
addScripts: false,
|
|
1438
|
-
selectedScripts: []
|
|
1439
|
-
};
|
|
1440
|
-
const selected = await prompts_.multiselect({
|
|
1441
|
-
message: "Which scripts do you want to add?",
|
|
1442
|
-
options: AVAILABLE_SCRIPTS.map((s)=>({
|
|
1443
|
-
value: s.value,
|
|
1444
|
-
label: s.label,
|
|
1445
|
-
hint: s.hint
|
|
1446
|
-
})),
|
|
1447
|
-
required: false
|
|
1448
|
-
});
|
|
1449
|
-
if (isCancel(selected)) throw new PromptCancelledError("scripts_selection");
|
|
1450
|
-
return {
|
|
1451
|
-
addScripts: true,
|
|
1452
|
-
selectedScripts: selected
|
|
1453
|
-
};
|
|
1454
|
-
});
|
|
1455
|
-
const installConfirmActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
|
|
1456
|
-
const { dependencies, packageManager } = input;
|
|
1457
|
-
const depList = dependencies.join(', ');
|
|
1458
|
-
const result = await prompts_.confirm({
|
|
1459
|
-
message: `Install dependencies (${depList}) with ${packageManager}?`,
|
|
1460
|
-
initialValue: true
|
|
1461
|
-
});
|
|
1462
|
-
if (isCancel(result)) throw new PromptCancelledError('install_confirm');
|
|
1463
|
-
return {
|
|
1464
|
-
confirmed: result
|
|
1465
|
-
};
|
|
1466
|
-
});
|
|
1467
|
-
const skillsInstallActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
|
|
1468
|
-
const { cliContext } = input;
|
|
1469
|
-
const result = await prompts_.confirm({
|
|
1470
|
-
message: 'Install c15t agent skills for AI-assisted development? (Claude, Cursor, etc.)',
|
|
1471
|
-
initialValue: true
|
|
1472
|
-
});
|
|
1473
|
-
if (isCancel(result)) return {
|
|
1474
|
-
installed: false
|
|
1475
|
-
};
|
|
1476
|
-
if (result) try {
|
|
1477
|
-
const { spawn } = await import("node:child_process");
|
|
1478
|
-
const pmName = cliContext.packageManager.name;
|
|
1479
|
-
const execCommands = {
|
|
1480
|
-
bun: 'bunx',
|
|
1481
|
-
pnpm: 'pnpm dlx',
|
|
1482
|
-
yarn: 'yarn dlx',
|
|
1483
|
-
npm: 'npx'
|
|
1484
|
-
};
|
|
1485
|
-
const execCommand = execCommands[pmName] ?? 'npx';
|
|
1486
|
-
const [cmd, ...baseArgs] = execCommand.split(' ');
|
|
1487
|
-
cliContext.logger.info('Installing c15t agent skills...');
|
|
1488
|
-
const child = spawn(cmd, [
|
|
1489
|
-
...baseArgs,
|
|
1490
|
-
'skills',
|
|
1491
|
-
'add',
|
|
1492
|
-
'c15t/skills'
|
|
1493
|
-
], {
|
|
1494
|
-
cwd: cliContext.projectRoot,
|
|
1495
|
-
stdio: 'inherit'
|
|
1496
|
-
});
|
|
1497
|
-
const exitCode = await new Promise((resolve)=>{
|
|
1498
|
-
child.on('exit', (code)=>resolve(code));
|
|
1499
|
-
});
|
|
1500
|
-
if (0 === exitCode) {
|
|
1501
|
-
cliContext.logger.success('Agent skills installed successfully!');
|
|
1502
|
-
return {
|
|
1503
|
-
installed: true
|
|
1504
|
-
};
|
|
1505
|
-
}
|
|
1506
|
-
cliContext.logger.warn('Skills installation failed. You can install later with: npx skills add c15t/skills');
|
|
1507
|
-
} catch {
|
|
1508
|
-
cliContext.logger.warn('Skills installation failed. You can install later with: npx skills add c15t/skills');
|
|
1509
|
-
}
|
|
1510
|
-
return {
|
|
1511
|
-
installed: false
|
|
1512
|
-
};
|
|
1513
|
-
});
|
|
1514
|
-
const githubStarActor = (0, __rspack_external_xstate.fromPromise)(async ({ input })=>{
|
|
1515
|
-
const { cliContext } = input;
|
|
1516
|
-
const result = await prompts_.confirm({
|
|
1517
|
-
message: 'Would you like to star c15t on GitHub now?',
|
|
1518
|
-
initialValue: true
|
|
1519
|
-
});
|
|
1520
|
-
if (isCancel(result)) return {
|
|
1521
|
-
opened: false
|
|
1522
|
-
};
|
|
1523
|
-
if (result) try {
|
|
1524
|
-
const open = (await import("open")).default;
|
|
1525
|
-
await open('https://github.com/c15t/c15t');
|
|
1526
|
-
cliContext.logger.success('GitHub repository opened. Thank you for your support!');
|
|
1527
|
-
return {
|
|
1528
|
-
opened: true
|
|
1529
|
-
};
|
|
1530
|
-
} catch {
|
|
1531
|
-
cliContext.logger.info('You can star us later by visiting: https://github.com/c15t/c15t');
|
|
1532
|
-
}
|
|
1533
|
-
return {
|
|
1534
|
-
opened: false
|
|
1535
|
-
};
|
|
1536
|
-
});
|
|
1537
|
-
function preflightPassed({ context }) {
|
|
1538
|
-
return context.preflightPassed;
|
|
1539
|
-
}
|
|
1540
|
-
function preflightFailed({ context }) {
|
|
1541
|
-
return !context.preflightPassed;
|
|
1542
|
-
}
|
|
1543
|
-
function hasModeArg({ context }) {
|
|
1544
|
-
return null !== context.modeArg;
|
|
1545
|
-
}
|
|
1546
|
-
function guards_isC15tMode({ context }) {
|
|
1547
|
-
return 'c15t' === context.selectedMode;
|
|
1548
|
-
}
|
|
1549
|
-
function isOfflineMode({ context }) {
|
|
1550
|
-
return 'offline' === context.selectedMode;
|
|
1551
|
-
}
|
|
1552
|
-
function isSelfHostedMode({ context }) {
|
|
1553
|
-
return 'self-hosted' === context.selectedMode;
|
|
1554
|
-
}
|
|
1555
|
-
function isCustomMode({ context }) {
|
|
1556
|
-
return 'custom' === context.selectedMode;
|
|
1557
|
-
}
|
|
1558
|
-
function modeRequiresBackend({ context }) {
|
|
1559
|
-
return 'c15t' === context.selectedMode || 'self-hosted' === context.selectedMode;
|
|
1560
|
-
}
|
|
1561
|
-
function modeNoBackend({ context }) {
|
|
1562
|
-
return 'offline' === context.selectedMode || 'custom' === context.selectedMode;
|
|
1563
|
-
}
|
|
1564
|
-
function isNextjs({ context }) {
|
|
1565
|
-
return context.framework?.pkg === '@c15t/nextjs';
|
|
1566
|
-
}
|
|
1567
|
-
function isReact({ context }) {
|
|
1568
|
-
return context.framework?.pkg === '@c15t/react';
|
|
1569
|
-
}
|
|
1570
|
-
function isCore({ context }) {
|
|
1571
|
-
return context.framework?.pkg === 'c15t';
|
|
1572
|
-
}
|
|
1573
|
-
function guards_hasReact({ context }) {
|
|
1574
|
-
return context.framework?.hasReact ?? false;
|
|
1575
|
-
}
|
|
1576
|
-
function hasTailwind({ context }) {
|
|
1577
|
-
return context.framework?.tailwindVersion !== null;
|
|
1578
|
-
}
|
|
1579
|
-
function hasBackendURL({ context }) {
|
|
1580
|
-
return null !== context.backendURL && '' !== context.backendURL;
|
|
1581
|
-
}
|
|
1582
|
-
function isExpandedUIStyle({ context }) {
|
|
1583
|
-
return 'expanded' === context.uiStyle;
|
|
1584
|
-
}
|
|
1585
|
-
function installConfirmed({ context }) {
|
|
1586
|
-
return context.installConfirmed;
|
|
1587
|
-
}
|
|
1588
|
-
function installSucceeded({ context }) {
|
|
1589
|
-
return context.installSucceeded;
|
|
1590
|
-
}
|
|
1591
|
-
function hasFilesToRollback({ context }) {
|
|
1592
|
-
return context.filesCreated.length > 0 || context.filesModified.length > 0;
|
|
1593
|
-
}
|
|
1594
|
-
function hasDependencies({ context }) {
|
|
1595
|
-
return context.dependenciesToAdd.length > 0;
|
|
1596
|
-
}
|
|
1597
|
-
function hasErrors({ context }) {
|
|
1598
|
-
return context.errors.length > 0;
|
|
1599
|
-
}
|
|
1600
|
-
function needsCleanup({ context }) {
|
|
1601
|
-
return !context.cleanupDone && (context.filesCreated.length > 0 || context.filesModified.length > 0);
|
|
1602
|
-
}
|
|
1603
|
-
function shouldPromptSSR({ context }) {
|
|
1604
|
-
return context.framework?.pkg === '@c15t/nextjs' && ('c15t' === context.selectedMode || 'self-hosted' === context.selectedMode);
|
|
1605
|
-
}
|
|
1606
|
-
function shouldPromptUIStyle({ context }) {
|
|
1607
|
-
return context.framework?.pkg === '@c15t/nextjs' || context.framework?.pkg === '@c15t/react';
|
|
1608
|
-
}
|
|
1609
|
-
const guards = {
|
|
1610
|
-
preflightPassed,
|
|
1611
|
-
preflightFailed,
|
|
1612
|
-
hasModeArg,
|
|
1613
|
-
isC15tMode: guards_isC15tMode,
|
|
1614
|
-
isOfflineMode,
|
|
1615
|
-
isSelfHostedMode,
|
|
1616
|
-
isCustomMode,
|
|
1617
|
-
modeRequiresBackend,
|
|
1618
|
-
modeNoBackend,
|
|
1619
|
-
isNextjs,
|
|
1620
|
-
isReact,
|
|
1621
|
-
isCore,
|
|
1622
|
-
hasReact: guards_hasReact,
|
|
1623
|
-
hasTailwind,
|
|
1624
|
-
hasBackendURL,
|
|
1625
|
-
isExpandedUIStyle,
|
|
1626
|
-
installConfirmed,
|
|
1627
|
-
installSucceeded,
|
|
1628
|
-
hasFilesToRollback,
|
|
1629
|
-
hasDependencies,
|
|
1630
|
-
hasErrors,
|
|
1631
|
-
needsCleanup,
|
|
1632
|
-
shouldPromptSSR,
|
|
1633
|
-
shouldPromptUIStyle
|
|
1634
|
-
};
|
|
1635
|
-
function createInitialContext(cliContext, modeArg) {
|
|
1636
|
-
return {
|
|
1637
|
-
cliContext: cliContext ?? null,
|
|
1638
|
-
projectRoot: cliContext?.projectRoot ?? '',
|
|
1639
|
-
framework: null,
|
|
1640
|
-
packageManager: null,
|
|
1641
|
-
preflightPassed: false,
|
|
1642
|
-
preflightChecks: [],
|
|
1643
|
-
selectedMode: null,
|
|
1644
|
-
modeArg: modeArg ?? null,
|
|
1645
|
-
backendURL: null,
|
|
1646
|
-
useEnvFile: true,
|
|
1647
|
-
proxyNextjs: true,
|
|
1648
|
-
enableSSR: false,
|
|
1649
|
-
enableDevTools: false,
|
|
1650
|
-
uiStyle: 'prebuilt',
|
|
1651
|
-
expandedTheme: null,
|
|
1652
|
-
addScripts: false,
|
|
1653
|
-
selectedScripts: [],
|
|
1654
|
-
filesCreated: [],
|
|
1655
|
-
filesModified: [],
|
|
1656
|
-
dependenciesToAdd: [],
|
|
1657
|
-
installConfirmed: false,
|
|
1658
|
-
installAttempted: false,
|
|
1659
|
-
installSucceeded: false,
|
|
1660
|
-
runMigrations: false,
|
|
1661
|
-
skillsInstalled: false,
|
|
1662
|
-
cancelReason: null,
|
|
1663
|
-
cleanupDone: false,
|
|
1664
|
-
errors: [],
|
|
1665
|
-
stateHistory: []
|
|
1666
|
-
};
|
|
1667
|
-
}
|
|
1668
|
-
const generateMachine = (0, __rspack_external_xstate.setup)({
|
|
1669
|
-
types: {
|
|
1670
|
-
context: {},
|
|
1671
|
-
events: {},
|
|
1672
|
-
input: {}
|
|
1673
|
-
},
|
|
1674
|
-
guards: guards,
|
|
1675
|
-
actors: {
|
|
1676
|
-
preflight: preflightActor,
|
|
1677
|
-
modeSelection: modeSelectionActor,
|
|
1678
|
-
accountCreation: accountCreationActor,
|
|
1679
|
-
backendURL: backendURLActor,
|
|
1680
|
-
backendOptions: backendOptionsActor,
|
|
1681
|
-
frontendOptions: frontendOptionsActor,
|
|
1682
|
-
scriptsOption: scriptsOptionActor,
|
|
1683
|
-
fileGeneration: fileGenerationActor,
|
|
1684
|
-
checkDependencies: checkDependenciesActor,
|
|
1685
|
-
installConfirm: installConfirmActor,
|
|
1686
|
-
dependencyInstall: dependencyInstallActor,
|
|
1687
|
-
rollback: rollbackActor,
|
|
1688
|
-
skillsInstall: skillsInstallActor,
|
|
1689
|
-
githubStar: githubStarActor
|
|
1690
|
-
}
|
|
1691
|
-
}).createMachine({
|
|
1692
|
-
id: 'generate',
|
|
1693
|
-
initial: 'idle',
|
|
1694
|
-
context: ({ input })=>createInitialContext(input.cliContext, input.modeArg),
|
|
1695
|
-
on: {
|
|
1696
|
-
CANCEL: {
|
|
1697
|
-
target: '.cancelling',
|
|
1698
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
1699
|
-
cancelReason: ({ event })=>event.reason ?? 'User cancelled'
|
|
1700
|
-
})
|
|
1701
|
-
}
|
|
1702
|
-
},
|
|
1703
|
-
states: {
|
|
1704
|
-
idle: {
|
|
1705
|
-
on: {
|
|
1706
|
-
START: 'preflight'
|
|
1707
|
-
}
|
|
1708
|
-
},
|
|
1709
|
-
preflight: {
|
|
1710
|
-
invoke: {
|
|
1711
|
-
src: 'preflight',
|
|
1712
|
-
input: ({ context })=>({
|
|
1713
|
-
cliContext: context.cliContext
|
|
1714
|
-
}),
|
|
1715
|
-
onDone: [
|
|
1716
|
-
{
|
|
1717
|
-
guard: ({ event })=>event.output.passed,
|
|
1718
|
-
target: 'modeSelection',
|
|
1719
|
-
actions: [
|
|
1720
|
-
(0, __rspack_external_xstate.assign)({
|
|
1721
|
-
preflightPassed: ({ event })=>event.output.passed,
|
|
1722
|
-
preflightChecks: ({ event })=>event.output.checks,
|
|
1723
|
-
projectRoot: ({ event })=>event.output.projectRoot,
|
|
1724
|
-
framework: ({ event })=>event.output.framework,
|
|
1725
|
-
packageManager: ({ event })=>event.output.packageManager
|
|
1726
|
-
}),
|
|
1727
|
-
({ context, event })=>{
|
|
1728
|
-
if (context.cliContext) displayPreflightResults(context.cliContext, event.output.checks);
|
|
1729
|
-
}
|
|
1730
|
-
]
|
|
1731
|
-
},
|
|
1732
|
-
{
|
|
1733
|
-
target: 'preflightError',
|
|
1734
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
1735
|
-
preflightPassed: false,
|
|
1736
|
-
preflightChecks: ({ event })=>event.output.checks
|
|
1737
|
-
})
|
|
1738
|
-
}
|
|
1739
|
-
],
|
|
1740
|
-
onError: {
|
|
1741
|
-
target: 'error',
|
|
1742
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
1743
|
-
errors: ({ context, event })=>[
|
|
1744
|
-
...context.errors,
|
|
1745
|
-
{
|
|
1746
|
-
state: 'preflight',
|
|
1747
|
-
error: event.error,
|
|
1748
|
-
timestamp: Date.now()
|
|
1749
|
-
}
|
|
1750
|
-
]
|
|
1751
|
-
})
|
|
1752
|
-
}
|
|
1753
|
-
}
|
|
1754
|
-
},
|
|
1755
|
-
preflightError: {
|
|
1756
|
-
entry: ({ context })=>{
|
|
1757
|
-
if (context.cliContext) displayPreflightFailure(context.cliContext, context.preflightChecks);
|
|
1758
|
-
},
|
|
1759
|
-
on: {
|
|
1760
|
-
RETRY: {
|
|
1761
|
-
target: 'preflight',
|
|
1762
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
1763
|
-
preflightPassed: false,
|
|
1764
|
-
preflightChecks: [],
|
|
1765
|
-
errors: []
|
|
1766
|
-
})
|
|
1767
|
-
}
|
|
1768
|
-
},
|
|
1769
|
-
after: {
|
|
1770
|
-
100: 'exited'
|
|
1771
|
-
}
|
|
1772
|
-
},
|
|
1773
|
-
modeSelection: {
|
|
1774
|
-
always: [
|
|
1775
|
-
{
|
|
1776
|
-
guard: 'hasModeArg',
|
|
1777
|
-
target: 'routeToMode',
|
|
1778
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
1779
|
-
selectedMode: ({ context })=>context.modeArg
|
|
1780
|
-
})
|
|
1781
|
-
}
|
|
1782
|
-
],
|
|
1783
|
-
invoke: {
|
|
1784
|
-
src: 'modeSelection',
|
|
1785
|
-
input: ()=>({}),
|
|
1786
|
-
onDone: {
|
|
1787
|
-
target: 'routeToMode',
|
|
1788
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
1789
|
-
selectedMode: ({ event })=>event.output.mode
|
|
1790
|
-
})
|
|
1791
|
-
},
|
|
1792
|
-
onError: {
|
|
1793
|
-
target: 'cancelling',
|
|
1794
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
1795
|
-
cancelReason: 'Mode selection cancelled'
|
|
1796
|
-
})
|
|
1797
|
-
}
|
|
1798
|
-
}
|
|
1799
|
-
},
|
|
1800
|
-
routeToMode: {
|
|
1801
|
-
always: [
|
|
1802
|
-
{
|
|
1803
|
-
guard: 'isC15tMode',
|
|
1804
|
-
target: 'c15tMode'
|
|
1805
|
-
},
|
|
1806
|
-
{
|
|
1807
|
-
guard: 'isOfflineMode',
|
|
1808
|
-
target: 'offlineMode'
|
|
1809
|
-
},
|
|
1810
|
-
{
|
|
1811
|
-
guard: 'isSelfHostedMode',
|
|
1812
|
-
target: 'selfHostedMode'
|
|
1813
|
-
},
|
|
1814
|
-
{
|
|
1815
|
-
guard: 'isCustomMode',
|
|
1816
|
-
target: 'customMode'
|
|
1817
|
-
},
|
|
1818
|
-
{
|
|
1819
|
-
target: 'customMode'
|
|
1820
|
-
}
|
|
1821
|
-
]
|
|
1822
|
-
},
|
|
1823
|
-
c15tMode: {
|
|
1824
|
-
initial: 'accountCreation',
|
|
1825
|
-
states: {
|
|
1826
|
-
accountCreation: {
|
|
1827
|
-
invoke: {
|
|
1828
|
-
src: 'accountCreation',
|
|
1829
|
-
input: ({ context })=>({
|
|
1830
|
-
cliContext: context.cliContext
|
|
1831
|
-
}),
|
|
1832
|
-
onDone: 'backendURL',
|
|
1833
|
-
onError: {
|
|
1834
|
-
target: '#generate.cancelling',
|
|
1835
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
1836
|
-
cancelReason: 'Account creation cancelled'
|
|
1837
|
-
})
|
|
1838
|
-
}
|
|
1839
|
-
}
|
|
1840
|
-
},
|
|
1841
|
-
backendURL: {
|
|
1842
|
-
invoke: {
|
|
1843
|
-
src: 'backendURL',
|
|
1844
|
-
input: ()=>({
|
|
1845
|
-
isC15tMode: true
|
|
1846
|
-
}),
|
|
1847
|
-
onDone: {
|
|
1848
|
-
target: '#generate.backendOptions',
|
|
1849
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
1850
|
-
backendURL: ({ event })=>event.output.url
|
|
1851
|
-
})
|
|
1852
|
-
},
|
|
1853
|
-
onError: {
|
|
1854
|
-
target: '#generate.cancelling',
|
|
1855
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
1856
|
-
cancelReason: 'Backend URL entry cancelled'
|
|
1857
|
-
})
|
|
1858
|
-
}
|
|
1859
|
-
}
|
|
1860
|
-
}
|
|
1861
|
-
}
|
|
1862
|
-
},
|
|
1863
|
-
offlineMode: {
|
|
1864
|
-
always: 'frontendOptions'
|
|
1865
|
-
},
|
|
1866
|
-
selfHostedMode: {
|
|
1867
|
-
invoke: {
|
|
1868
|
-
src: 'backendURL',
|
|
1869
|
-
input: ()=>({
|
|
1870
|
-
isC15tMode: false
|
|
1871
|
-
}),
|
|
1872
|
-
onDone: {
|
|
1873
|
-
target: 'backendOptions',
|
|
1874
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
1875
|
-
backendURL: ({ event })=>event.output.url
|
|
1876
|
-
})
|
|
1877
|
-
},
|
|
1878
|
-
onError: {
|
|
1879
|
-
target: 'cancelling',
|
|
1880
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
1881
|
-
cancelReason: 'Backend URL entry cancelled'
|
|
1882
|
-
})
|
|
1883
|
-
}
|
|
1884
|
-
}
|
|
1885
|
-
},
|
|
1886
|
-
customMode: {
|
|
1887
|
-
always: 'frontendOptions'
|
|
1888
|
-
},
|
|
1889
|
-
backendOptions: {
|
|
1890
|
-
invoke: {
|
|
1891
|
-
src: 'backendOptions',
|
|
1892
|
-
input: ({ context })=>({
|
|
1893
|
-
cliContext: context.cliContext,
|
|
1894
|
-
backendURL: context.backendURL
|
|
1895
|
-
}),
|
|
1896
|
-
onDone: {
|
|
1897
|
-
target: 'frontendOptions',
|
|
1898
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
1899
|
-
useEnvFile: ({ event })=>event.output.useEnvFile,
|
|
1900
|
-
proxyNextjs: ({ event })=>event.output.proxyNextjs
|
|
1901
|
-
})
|
|
1902
|
-
},
|
|
1903
|
-
onError: {
|
|
1904
|
-
target: 'cancelling',
|
|
1905
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
1906
|
-
cancelReason: 'Backend options cancelled'
|
|
1907
|
-
})
|
|
1908
|
-
}
|
|
1909
|
-
}
|
|
1910
|
-
},
|
|
1911
|
-
frontendOptions: {
|
|
1912
|
-
invoke: {
|
|
1913
|
-
src: 'frontendOptions',
|
|
1914
|
-
input: ({ context })=>({
|
|
1915
|
-
cliContext: context.cliContext,
|
|
1916
|
-
hasBackend: 'c15t' === context.selectedMode || 'self-hosted' === context.selectedMode
|
|
1917
|
-
}),
|
|
1918
|
-
onDone: {
|
|
1919
|
-
target: "scriptsOptions",
|
|
1920
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
1921
|
-
enableSSR: ({ event, context })=>event.output.enableSSR ?? context.enableSSR,
|
|
1922
|
-
enableDevTools: ({ event, context })=>event.output.enableDevTools ?? context.enableDevTools,
|
|
1923
|
-
uiStyle: ({ event })=>event.output.uiStyle,
|
|
1924
|
-
expandedTheme: ({ event })=>event.output.expandedTheme ?? null
|
|
1925
|
-
})
|
|
1926
|
-
},
|
|
1927
|
-
onError: {
|
|
1928
|
-
target: 'cancelling',
|
|
1929
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
1930
|
-
cancelReason: 'Frontend options cancelled'
|
|
1931
|
-
})
|
|
1932
|
-
}
|
|
1933
|
-
}
|
|
1934
|
-
},
|
|
1935
|
-
scriptsOptions: {
|
|
1936
|
-
invoke: {
|
|
1937
|
-
src: "scriptsOption",
|
|
1938
|
-
input: ({ context })=>({
|
|
1939
|
-
cliContext: context.cliContext
|
|
1940
|
-
}),
|
|
1941
|
-
onDone: {
|
|
1942
|
-
target: 'fileGeneration',
|
|
1943
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
1944
|
-
addScripts: ({ event })=>event.output.addScripts,
|
|
1945
|
-
selectedScripts: ({ event })=>event.output.selectedScripts ?? [],
|
|
1946
|
-
dependenciesToAdd: ({ context, event })=>{
|
|
1947
|
-
const deps = [
|
|
1948
|
-
context.framework?.pkg ?? 'c15t'
|
|
1949
|
-
];
|
|
1950
|
-
if (event.output.addScripts) deps.push("@c15t/scripts");
|
|
1951
|
-
if (context.enableDevTools) deps.push('@c15t/dev-tools');
|
|
1952
|
-
return deps;
|
|
1953
|
-
}
|
|
1954
|
-
})
|
|
1955
|
-
},
|
|
1956
|
-
onError: {
|
|
1957
|
-
target: 'cancelling',
|
|
1958
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
1959
|
-
cancelReason: 'Scripts option cancelled'
|
|
1960
|
-
})
|
|
1961
|
-
}
|
|
1962
|
-
}
|
|
1963
|
-
},
|
|
1964
|
-
fileGeneration: {
|
|
1965
|
-
invoke: {
|
|
1966
|
-
src: 'fileGeneration',
|
|
1967
|
-
input: ({ context })=>({
|
|
1968
|
-
cliContext: context.cliContext,
|
|
1969
|
-
mode: context.selectedMode,
|
|
1970
|
-
backendURL: context.backendURL,
|
|
1971
|
-
useEnvFile: context.useEnvFile,
|
|
1972
|
-
proxyNextjs: context.proxyNextjs,
|
|
1973
|
-
enableSSR: context.enableSSR,
|
|
1974
|
-
enableDevTools: context.enableDevTools,
|
|
1975
|
-
uiStyle: context.uiStyle,
|
|
1976
|
-
expandedTheme: context.expandedTheme,
|
|
1977
|
-
selectedScripts: context.selectedScripts
|
|
1978
|
-
}),
|
|
1979
|
-
onDone: {
|
|
1980
|
-
target: 'dependencyCheck',
|
|
1981
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
1982
|
-
filesCreated: ({ event })=>event.output.filesCreated,
|
|
1983
|
-
filesModified: ({ event })=>event.output.filesModified
|
|
1984
|
-
})
|
|
1985
|
-
},
|
|
1986
|
-
onError: {
|
|
1987
|
-
target: 'error',
|
|
1988
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
1989
|
-
errors: ({ context, event })=>[
|
|
1990
|
-
...context.errors,
|
|
1991
|
-
{
|
|
1992
|
-
state: 'fileGeneration',
|
|
1993
|
-
error: event.error,
|
|
1994
|
-
timestamp: Date.now()
|
|
1995
|
-
}
|
|
1996
|
-
]
|
|
1997
|
-
})
|
|
1998
|
-
}
|
|
1999
|
-
}
|
|
2000
|
-
},
|
|
2001
|
-
dependencyCheck: {
|
|
2002
|
-
invoke: {
|
|
2003
|
-
src: 'checkDependencies',
|
|
2004
|
-
input: ({ context })=>({
|
|
2005
|
-
projectRoot: context.cliContext.projectRoot,
|
|
2006
|
-
dependencies: context.dependenciesToAdd
|
|
2007
|
-
}),
|
|
2008
|
-
onDone: {
|
|
2009
|
-
target: 'dependencyConfirm',
|
|
2010
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
2011
|
-
dependenciesToAdd: ({ event })=>event.output.missing
|
|
2012
|
-
})
|
|
2013
|
-
},
|
|
2014
|
-
onError: {
|
|
2015
|
-
target: 'dependencyConfirm'
|
|
2016
|
-
}
|
|
2017
|
-
}
|
|
2018
|
-
},
|
|
2019
|
-
dependencyConfirm: {
|
|
2020
|
-
always: [
|
|
2021
|
-
{
|
|
2022
|
-
guard: ({ context })=>0 === context.dependenciesToAdd.length,
|
|
2023
|
-
target: 'summary'
|
|
2024
|
-
}
|
|
2025
|
-
],
|
|
2026
|
-
invoke: {
|
|
2027
|
-
src: 'installConfirm',
|
|
2028
|
-
input: ({ context })=>({
|
|
2029
|
-
dependencies: context.dependenciesToAdd,
|
|
2030
|
-
packageManager: context.packageManager?.name ?? 'npm'
|
|
2031
|
-
}),
|
|
2032
|
-
onDone: [
|
|
2033
|
-
{
|
|
2034
|
-
guard: ({ event })=>event.output.confirmed,
|
|
2035
|
-
target: 'dependencyInstall',
|
|
2036
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
2037
|
-
installConfirmed: true
|
|
2038
|
-
})
|
|
2039
|
-
},
|
|
2040
|
-
{
|
|
2041
|
-
target: 'summary',
|
|
2042
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
2043
|
-
installConfirmed: false
|
|
2044
|
-
})
|
|
2045
|
-
}
|
|
2046
|
-
],
|
|
2047
|
-
onError: {
|
|
2048
|
-
target: 'summary',
|
|
2049
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
2050
|
-
installConfirmed: false
|
|
2051
|
-
})
|
|
2052
|
-
}
|
|
2053
|
-
}
|
|
2054
|
-
},
|
|
2055
|
-
dependencyInstall: {
|
|
2056
|
-
invoke: {
|
|
2057
|
-
src: 'dependencyInstall',
|
|
2058
|
-
input: ({ context })=>({
|
|
2059
|
-
cliContext: context.cliContext,
|
|
2060
|
-
dependencies: context.dependenciesToAdd
|
|
2061
|
-
}),
|
|
2062
|
-
onDone: {
|
|
2063
|
-
target: 'summary',
|
|
2064
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
2065
|
-
installAttempted: true,
|
|
2066
|
-
installSucceeded: ({ event })=>event.output.success
|
|
2067
|
-
})
|
|
2068
|
-
},
|
|
2069
|
-
onError: {
|
|
2070
|
-
target: 'summary',
|
|
2071
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
2072
|
-
installAttempted: true,
|
|
2073
|
-
installSucceeded: false
|
|
2074
|
-
})
|
|
2075
|
-
}
|
|
2076
|
-
}
|
|
2077
|
-
},
|
|
2078
|
-
summary: {
|
|
2079
|
-
entry: ({ context })=>{
|
|
2080
|
-
if (!context.cliContext) return;
|
|
2081
|
-
const { logger, packageManager } = context.cliContext;
|
|
2082
|
-
if ('self-hosted' === context.selectedMode) {
|
|
2083
|
-
logger.info('Setup your backend with the c15t docs:');
|
|
2084
|
-
logger.info('https://c15t.com/docs/self-host/v2');
|
|
2085
|
-
} else if ('custom' === context.selectedMode) logger.info('Configuration Complete! Implement your custom endpoint handlers.');
|
|
2086
|
-
if (context.installConfirmed && !context.installSucceeded) logger.warn('Dependency installation failed. Please check errors and install manually.');
|
|
2087
|
-
else if (!context.installConfirmed && context.dependenciesToAdd.length > 0) {
|
|
2088
|
-
const pmCommand = getManualInstallCommand(context.dependenciesToAdd, packageManager.name);
|
|
2089
|
-
logger.warn(`Run ${pmCommand} to install required dependencies.`);
|
|
2090
|
-
}
|
|
2091
|
-
},
|
|
2092
|
-
after: {
|
|
2093
|
-
100: 'skillsInstall'
|
|
2094
|
-
}
|
|
2095
|
-
},
|
|
2096
|
-
skillsInstall: {
|
|
2097
|
-
invoke: {
|
|
2098
|
-
src: 'skillsInstall',
|
|
2099
|
-
input: ({ context })=>({
|
|
2100
|
-
cliContext: context.cliContext
|
|
2101
|
-
}),
|
|
2102
|
-
onDone: {
|
|
2103
|
-
target: 'githubStar',
|
|
2104
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
2105
|
-
skillsInstalled: ({ event })=>event.output.installed
|
|
2106
|
-
})
|
|
2107
|
-
},
|
|
2108
|
-
onError: 'githubStar'
|
|
2109
|
-
}
|
|
2110
|
-
},
|
|
2111
|
-
githubStar: {
|
|
2112
|
-
invoke: {
|
|
2113
|
-
src: 'githubStar',
|
|
2114
|
-
input: ({ context })=>({
|
|
2115
|
-
cliContext: context.cliContext
|
|
2116
|
-
}),
|
|
2117
|
-
onDone: 'complete',
|
|
2118
|
-
onError: 'complete'
|
|
2119
|
-
}
|
|
2120
|
-
},
|
|
2121
|
-
complete: {
|
|
2122
|
-
entry: ({ context })=>{
|
|
2123
|
-
context.cliContext?.logger.success('Setup completed successfully!');
|
|
2124
|
-
},
|
|
2125
|
-
type: 'final'
|
|
2126
|
-
},
|
|
2127
|
-
error: {
|
|
2128
|
-
entry: ({ context })=>{
|
|
2129
|
-
const lastError = context.errors[context.errors.length - 1];
|
|
2130
|
-
context.cliContext?.logger.error(`Error: ${lastError?.error?.message ?? 'Unknown error'}`);
|
|
2131
|
-
},
|
|
2132
|
-
always: [
|
|
2133
|
-
{
|
|
2134
|
-
guard: 'hasFilesToRollback',
|
|
2135
|
-
target: 'rollback'
|
|
2136
|
-
},
|
|
2137
|
-
{
|
|
2138
|
-
target: 'exited'
|
|
2139
|
-
}
|
|
2140
|
-
]
|
|
2141
|
-
},
|
|
2142
|
-
cancelling: {
|
|
2143
|
-
entry: ({ context })=>{
|
|
2144
|
-
context.cliContext?.logger.info(context.cancelReason ?? 'Configuration cancelled.');
|
|
2145
|
-
},
|
|
2146
|
-
always: [
|
|
2147
|
-
{
|
|
2148
|
-
guard: 'hasFilesToRollback',
|
|
2149
|
-
target: 'rollback'
|
|
2150
|
-
},
|
|
2151
|
-
{
|
|
2152
|
-
target: 'exited'
|
|
2153
|
-
}
|
|
2154
|
-
]
|
|
2155
|
-
},
|
|
2156
|
-
rollback: {
|
|
2157
|
-
invoke: {
|
|
2158
|
-
src: 'rollback',
|
|
2159
|
-
input: ({ context })=>({
|
|
2160
|
-
filesCreated: context.filesCreated,
|
|
2161
|
-
filesModified: context.filesModified
|
|
2162
|
-
}),
|
|
2163
|
-
onDone: {
|
|
2164
|
-
target: 'exited',
|
|
2165
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
2166
|
-
filesCreated: [],
|
|
2167
|
-
filesModified: [],
|
|
2168
|
-
cleanupDone: true
|
|
2169
|
-
})
|
|
2170
|
-
},
|
|
2171
|
-
onError: {
|
|
2172
|
-
target: 'exited',
|
|
2173
|
-
actions: (0, __rspack_external_xstate.assign)({
|
|
2174
|
-
cleanupDone: true
|
|
2175
|
-
})
|
|
2176
|
-
}
|
|
2177
|
-
}
|
|
2178
|
-
},
|
|
2179
|
-
exited: {
|
|
2180
|
-
type: 'final'
|
|
2181
|
-
}
|
|
2182
|
-
}
|
|
2183
|
-
});
|
|
2184
|
-
async function runGenerateMachine(options) {
|
|
2185
|
-
const { context: cliContext, modeArg, resume = false, debug = false, persist = true } = options;
|
|
2186
|
-
const { logger, telemetry } = cliContext;
|
|
2187
|
-
const startTime = Date.now();
|
|
2188
|
-
const persistPath = getPersistPath(cliContext.projectRoot);
|
|
2189
|
-
const machineId = 'generate';
|
|
2190
|
-
let snapshot;
|
|
2191
|
-
if (resume) {
|
|
2192
|
-
const hasPersisted = await hasPersistedState(persistPath);
|
|
2193
|
-
if (hasPersisted) {
|
|
2194
|
-
snapshot = await loadSnapshot(persistPath, machineId);
|
|
2195
|
-
if (snapshot) logger.info('Resuming from previous state...');
|
|
2196
|
-
}
|
|
2197
|
-
}
|
|
2198
|
-
const actor = (0, __rspack_external_xstate.createActor)(generateMachine, {
|
|
2199
|
-
input: {
|
|
2200
|
-
cliContext,
|
|
2201
|
-
modeArg
|
|
2202
|
-
},
|
|
2203
|
-
...snapshot ? {
|
|
2204
|
-
snapshot: snapshot
|
|
2205
|
-
} : {}
|
|
2206
|
-
});
|
|
2207
|
-
const subscribers = [];
|
|
2208
|
-
subscribers.push(createTelemetrySubscriber({
|
|
2209
|
-
telemetry,
|
|
2210
|
-
machineId,
|
|
2211
|
-
skipStates: [
|
|
2212
|
-
'routeToMode'
|
|
2213
|
-
]
|
|
2214
|
-
}));
|
|
2215
|
-
if (debug) subscribers.push(createDebugSubscriber(machineId, logger));
|
|
2216
|
-
if (persist) subscribers.push(createPersistenceSubscriber(machineId, persistPath));
|
|
2217
|
-
const combinedSubscriber = combineSubscribers(...subscribers);
|
|
2218
|
-
actor.subscribe((snapshot)=>combinedSubscriber(snapshot));
|
|
2219
|
-
telemetry.trackEvent(TelemetryEventName.ONBOARDING_STARTED, {
|
|
2220
|
-
resumed: resume && void 0 !== snapshot
|
|
2221
|
-
});
|
|
2222
|
-
telemetry.flushSync();
|
|
2223
|
-
actor.start();
|
|
2224
|
-
if (!snapshot) actor.send({
|
|
2225
|
-
type: 'START'
|
|
2226
|
-
});
|
|
2227
|
-
return new Promise((resolve)=>{
|
|
2228
|
-
actor.subscribe({
|
|
2229
|
-
complete: ()=>{
|
|
2230
|
-
const finalSnapshot = actor.getSnapshot();
|
|
2231
|
-
const finalContext = finalSnapshot.context;
|
|
2232
|
-
const finalState = String(finalSnapshot.value);
|
|
2233
|
-
const duration = Date.now() - startTime;
|
|
2234
|
-
clearSnapshot(persistPath).catch(()=>{});
|
|
2235
|
-
const success = 'complete' === finalState || 'done' === finalSnapshot.status;
|
|
2236
|
-
telemetry.trackEvent(TelemetryEventName.ONBOARDING_COMPLETED, {
|
|
2237
|
-
success,
|
|
2238
|
-
selectedMode: finalContext.selectedMode ?? void 0,
|
|
2239
|
-
installDependencies: finalContext.installSucceeded,
|
|
2240
|
-
duration,
|
|
2241
|
-
finalState
|
|
2242
|
-
});
|
|
2243
|
-
resolve({
|
|
2244
|
-
success,
|
|
2245
|
-
context: finalContext,
|
|
2246
|
-
finalState,
|
|
2247
|
-
duration,
|
|
2248
|
-
errors: finalContext.errors
|
|
2249
|
-
});
|
|
2250
|
-
}
|
|
2251
|
-
});
|
|
2252
|
-
});
|
|
2253
|
-
}
|
|
2254
|
-
async function generateAction(context) {
|
|
2255
|
-
const { logger, commandArgs, flags } = context;
|
|
2256
|
-
const modeArg = commandArgs[0];
|
|
2257
|
-
const resume = true === flags.resume;
|
|
2258
|
-
const debug = true === flags.debug || 'debug' === flags.logger;
|
|
2259
|
-
logger.debug('Starting generate command with state machine...');
|
|
2260
|
-
logger.debug(`Mode arg: ${modeArg}`);
|
|
2261
|
-
logger.debug(`Resume: ${resume}`);
|
|
2262
|
-
try {
|
|
2263
|
-
const result = await runGenerateMachine({
|
|
2264
|
-
context,
|
|
2265
|
-
modeArg,
|
|
2266
|
-
resume,
|
|
2267
|
-
debug,
|
|
2268
|
-
persist: true
|
|
2269
|
-
});
|
|
2270
|
-
if (!result.success) {
|
|
2271
|
-
if (result.errors.length > 0) process.exitCode = 1;
|
|
2272
|
-
}
|
|
2273
|
-
} catch (error) {
|
|
2274
|
-
logger.error(`Generate command failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2275
|
-
process.exitCode = 1;
|
|
2276
|
-
}
|
|
2277
|
-
}
|
|
2278
|
-
async function generate(context, mode) {
|
|
2279
|
-
if (mode) context.commandArgs = [
|
|
2280
|
-
mode
|
|
2281
|
-
];
|
|
2282
|
-
return generateAction(context);
|
|
2283
|
-
}
|
|
2284
|
-
var utils_logger = __webpack_require__("./src/utils/logger.ts");
|
|
2285
|
-
async function addAndInstallDependenciesViaPM(projectRoot, dependencies, packageManager) {
|
|
2286
|
-
if (0 === dependencies.length) return;
|
|
2287
|
-
let command = '';
|
|
2288
|
-
let args = [];
|
|
2289
|
-
switch(packageManager){
|
|
2290
|
-
case 'npm':
|
|
2291
|
-
command = 'npm';
|
|
2292
|
-
args = [
|
|
2293
|
-
'install',
|
|
2294
|
-
...dependencies
|
|
2295
|
-
];
|
|
2296
|
-
break;
|
|
2297
|
-
case 'yarn':
|
|
2298
|
-
command = 'yarn';
|
|
2299
|
-
args = [
|
|
2300
|
-
'add',
|
|
2301
|
-
...dependencies
|
|
2302
|
-
];
|
|
2303
|
-
break;
|
|
2304
|
-
case 'pnpm':
|
|
2305
|
-
command = 'pnpm';
|
|
2306
|
-
args = [
|
|
2307
|
-
'add',
|
|
2308
|
-
...dependencies
|
|
2309
|
-
];
|
|
2310
|
-
break;
|
|
2311
|
-
case 'bun':
|
|
2312
|
-
command = 'bun';
|
|
2313
|
-
args = [
|
|
2314
|
-
'add',
|
|
2315
|
-
...dependencies
|
|
2316
|
-
];
|
|
2317
|
-
break;
|
|
2318
|
-
default:
|
|
2319
|
-
throw new Error(`Unsupported package manager for dependency addition: ${packageManager}`);
|
|
2320
|
-
}
|
|
2321
|
-
const child = (0, __rspack_external_node_child_process_27f17141.spawn)(command, args, {
|
|
2322
|
-
cwd: projectRoot,
|
|
2323
|
-
stdio: 'inherit'
|
|
2324
|
-
});
|
|
2325
|
-
await (0, __rspack_external_node_events_0a6aefe7.once)(child, 'exit');
|
|
2326
|
-
}
|
|
2327
|
-
function dependencies_getManualInstallCommand(dependencies, packageManager) {
|
|
2328
|
-
switch(packageManager){
|
|
2329
|
-
case 'npm':
|
|
2330
|
-
return `npm install ${dependencies.join(' ')}`;
|
|
2331
|
-
case 'yarn':
|
|
2332
|
-
return `yarn add ${dependencies.join(' ')}`;
|
|
2333
|
-
case 'pnpm':
|
|
2334
|
-
return `pnpm add ${dependencies.join(' ')}`;
|
|
2335
|
-
case 'bun':
|
|
2336
|
-
return `bun add ${dependencies.join(' ')}`;
|
|
2337
|
-
default:
|
|
2338
|
-
return `npm install ${dependencies.join(' ')}`;
|
|
2339
|
-
}
|
|
2340
|
-
}
|
|
2341
|
-
async function installDependencies({ context, dependenciesToAdd, handleCancel, autoInstall = false }) {
|
|
2342
|
-
const { telemetry, logger } = context;
|
|
2343
|
-
const s = prompts_.spinner();
|
|
2344
|
-
if (0 === dependenciesToAdd.length) return {
|
|
2345
|
-
installDepsConfirmed: false,
|
|
2346
|
-
ranInstall: false
|
|
2347
|
-
};
|
|
2348
|
-
const depsString = dependenciesToAdd.map((d)=>external_picocolors_["default"].cyan(d)).join(', ');
|
|
2349
|
-
if (!autoInstall) {
|
|
2350
|
-
const addDepsSelection = await prompts_.confirm({
|
|
2351
|
-
message: `Add required dependencies using ${external_picocolors_["default"].cyan(context.packageManager.name)}? (${depsString})`,
|
|
2352
|
-
initialValue: true
|
|
2353
|
-
});
|
|
2354
|
-
if (handleCancel?.(addDepsSelection)) return {
|
|
2355
|
-
installDepsConfirmed: false,
|
|
2356
|
-
ranInstall: false
|
|
2357
|
-
};
|
|
2358
|
-
if (!addDepsSelection) return {
|
|
2359
|
-
installDepsConfirmed: false,
|
|
2360
|
-
ranInstall: false
|
|
2361
|
-
};
|
|
2362
|
-
}
|
|
2363
|
-
s.start(`Running ${external_picocolors_["default"].cyan(context.packageManager.name)} to add and install dependencies... (this might take a moment)`);
|
|
2364
|
-
try {
|
|
2365
|
-
await addAndInstallDependenciesViaPM(context.projectRoot, dependenciesToAdd, context.packageManager.name);
|
|
2366
|
-
s.stop(`✅ Dependencies installed: ${dependenciesToAdd.map((d)=>external_picocolors_["default"].cyan(d)).join(', ')}`);
|
|
2367
|
-
telemetry.trackEvent(TelemetryEventName.ONBOARDING_DEPENDENCIES_INSTALLED, {
|
|
2368
|
-
success: true,
|
|
2369
|
-
dependencies: dependenciesToAdd.join(','),
|
|
2370
|
-
packageManager: context.packageManager.name
|
|
2371
|
-
});
|
|
2372
|
-
return {
|
|
2373
|
-
installDepsConfirmed: true,
|
|
2374
|
-
ranInstall: true
|
|
2375
|
-
};
|
|
2376
|
-
} catch (installError) {
|
|
2377
|
-
s.stop(external_picocolors_["default"].yellow('⚠️ Dependency installation failed.'));
|
|
2378
|
-
logger.error('Installation Error:', installError);
|
|
2379
|
-
telemetry.trackEvent(TelemetryEventName.ONBOARDING_DEPENDENCIES_INSTALLED, {
|
|
2380
|
-
success: false,
|
|
2381
|
-
error: installError instanceof Error ? installError.message : String(installError),
|
|
2382
|
-
dependencies: dependenciesToAdd.join(','),
|
|
2383
|
-
packageManager: context.packageManager.name
|
|
2384
|
-
});
|
|
2385
|
-
const pmCommand = dependencies_getManualInstallCommand(dependenciesToAdd, context.packageManager.name);
|
|
2386
|
-
logger.info(`Please try running '${pmCommand}' manually in ${external_picocolors_["default"].cyan(external_node_path_["default"].relative(context.cwd, context.projectRoot))}.`);
|
|
2387
|
-
return {
|
|
2388
|
-
installDepsConfirmed: true,
|
|
2389
|
-
ranInstall: false
|
|
2390
|
-
};
|
|
2391
|
-
}
|
|
2392
|
-
}
|
|
2393
|
-
var promises_ = __webpack_require__("node:fs/promises");
|
|
2394
|
-
const ADAPTER_LABELS = {
|
|
2395
|
-
kyselyAdapter: 'kysely',
|
|
2396
|
-
drizzleAdapter: 'drizzle',
|
|
2397
|
-
prismaAdapter: 'prisma',
|
|
2398
|
-
typeormAdapter: 'typeorm',
|
|
2399
|
-
mongoAdapter: 'mongo'
|
|
2400
|
-
};
|
|
2401
|
-
const PROVIDERS_BY_ADAPTER = {
|
|
2402
|
-
kyselyAdapter: [
|
|
2403
|
-
{
|
|
2404
|
-
label: 'PostgreSQL',
|
|
2405
|
-
value: 'postgresql'
|
|
2406
|
-
},
|
|
2407
|
-
{
|
|
2408
|
-
label: 'MySQL',
|
|
2409
|
-
value: 'mysql'
|
|
2410
|
-
},
|
|
2411
|
-
{
|
|
2412
|
-
label: 'SQLite',
|
|
2413
|
-
value: 'sqlite'
|
|
2414
|
-
},
|
|
2415
|
-
{
|
|
2416
|
-
label: 'CockroachDB',
|
|
2417
|
-
value: 'cockroachdb'
|
|
2418
|
-
},
|
|
2419
|
-
{
|
|
2420
|
-
label: 'Microsoft SQL Server',
|
|
2421
|
-
value: 'mssql'
|
|
2422
|
-
}
|
|
2423
|
-
],
|
|
2424
|
-
drizzleAdapter: [
|
|
2425
|
-
{
|
|
2426
|
-
label: 'PostgreSQL',
|
|
2427
|
-
value: 'postgresql'
|
|
2428
|
-
},
|
|
2429
|
-
{
|
|
2430
|
-
label: 'MySQL',
|
|
2431
|
-
value: 'mysql'
|
|
2432
|
-
},
|
|
2433
|
-
{
|
|
2434
|
-
label: 'SQLite',
|
|
2435
|
-
value: 'sqlite'
|
|
2436
|
-
}
|
|
2437
|
-
],
|
|
2438
|
-
prismaAdapter: [
|
|
2439
|
-
{
|
|
2440
|
-
label: 'PostgreSQL',
|
|
2441
|
-
value: 'postgresql'
|
|
2442
|
-
},
|
|
2443
|
-
{
|
|
2444
|
-
label: 'MySQL',
|
|
2445
|
-
value: 'mysql'
|
|
2446
|
-
},
|
|
2447
|
-
{
|
|
2448
|
-
label: 'SQLite',
|
|
2449
|
-
value: 'sqlite'
|
|
2450
|
-
},
|
|
2451
|
-
{
|
|
2452
|
-
label: 'MongoDB',
|
|
2453
|
-
value: 'mongodb'
|
|
2454
|
-
}
|
|
2455
|
-
],
|
|
2456
|
-
typeormAdapter: [
|
|
2457
|
-
{
|
|
2458
|
-
label: 'PostgreSQL',
|
|
2459
|
-
value: 'postgresql'
|
|
2460
|
-
},
|
|
2461
|
-
{
|
|
2462
|
-
label: 'MySQL',
|
|
2463
|
-
value: 'mysql'
|
|
2464
|
-
},
|
|
2465
|
-
{
|
|
2466
|
-
label: 'SQLite',
|
|
2467
|
-
value: 'sqlite'
|
|
2468
|
-
},
|
|
2469
|
-
{
|
|
2470
|
-
label: 'SQL Server',
|
|
2471
|
-
value: 'mssql'
|
|
2472
|
-
}
|
|
2473
|
-
],
|
|
2474
|
-
mongoAdapter: [
|
|
2475
|
-
{
|
|
2476
|
-
label: 'MongoDB',
|
|
2477
|
-
value: 'mongodb'
|
|
2478
|
-
}
|
|
2479
|
-
]
|
|
2480
|
-
};
|
|
2481
|
-
class Cancelled extends Error {
|
|
2482
|
-
stage;
|
|
2483
|
-
constructor(stage){
|
|
2484
|
-
super('Operation cancelled.');
|
|
2485
|
-
this.stage = stage;
|
|
2486
|
-
}
|
|
2487
|
-
}
|
|
2488
|
-
const CONFIG_BUILDERS = {
|
|
2489
|
-
kyselyAdapter: (provider)=>`kyselyAdapter({ provider: '${provider}', db })`,
|
|
2490
|
-
drizzleAdapter: (provider)=>`drizzleAdapter({ provider: '${provider}', db })`,
|
|
2491
|
-
prismaAdapter: (provider)=>`prismaAdapter({ provider: '${provider}', prisma })`,
|
|
2492
|
-
typeormAdapter: (provider)=>`typeormAdapter({ provider: '${provider}', source })`,
|
|
2493
|
-
mongoAdapter: ()=>'mongoAdapter({ client })'
|
|
2494
|
-
};
|
|
2495
|
-
async function pathExists(filePath) {
|
|
2496
|
-
try {
|
|
2497
|
-
await promises_["default"].access(filePath);
|
|
2498
|
-
return true;
|
|
2499
|
-
} catch {
|
|
2500
|
-
return false;
|
|
2501
|
-
}
|
|
2502
|
-
}
|
|
2503
|
-
function buildDatabaseConfig(adapter, provider, connection) {
|
|
2504
|
-
const builder = CONFIG_BUILDERS[adapter];
|
|
2505
|
-
return builder(provider, connection);
|
|
2506
|
-
}
|
|
2507
|
-
function buildKyselyPrelude(provider, connection) {
|
|
2508
|
-
const connExpr = connection.useEnv ? `process.env.${connection.envVar || 'DATABASE_URL'}!` : `"${connection.value || ''}"`;
|
|
2509
|
-
if ('postgresql' === provider || 'cockroachdb' === provider) return {
|
|
2510
|
-
imports: "import { Kysely, PostgresDialect } from 'kysely';\nimport { Pool } from 'pg';",
|
|
2511
|
-
prelude: `const db = new Kysely({\n\tdialect: new PostgresDialect({\n\t\tpool: new Pool({ connectionString: ${connExpr} }),\n\t}),\n});`
|
|
2512
|
-
};
|
|
2513
|
-
if ('mysql' === provider) return {
|
|
2514
|
-
imports: "import { Kysely, MysqlDialect } from 'kysely';\nimport mysql from 'mysql2/promise';",
|
|
2515
|
-
prelude: `const db = new Kysely({\n\tdialect: new MysqlDialect({\n\t\tpool: mysql.createPool(${connExpr}),\n\t}),\n});`
|
|
2516
|
-
};
|
|
2517
|
-
if ('mssql' === provider) return {
|
|
2518
|
-
imports: "import { Kysely, MssqlDialect } from 'kysely';\nimport mssql from 'mssql';",
|
|
2519
|
-
prelude: `const db = new Kysely({\n\tdialect: new MssqlDialect({\n\t\tpool: new mssql.ConnectionPool(${connExpr}),\n\t}),\n});`
|
|
2520
|
-
};
|
|
2521
|
-
return {
|
|
2522
|
-
imports: '',
|
|
2523
|
-
prelude: ''
|
|
2524
|
-
};
|
|
2525
|
-
}
|
|
2526
|
-
function buildSqliteKyselyPrelude(file) {
|
|
2527
|
-
return {
|
|
2528
|
-
imports: "import { Kysely, SqliteDialect } from 'kysely';\nimport Database from 'better-sqlite3';",
|
|
2529
|
-
prelude: `const db = new Kysely({\n\tdialect: new SqliteDialect({\n\t\tdatabase: new Database("${file}"),\n\t}),\n});`
|
|
2530
|
-
};
|
|
2531
|
-
}
|
|
2532
|
-
function buildDrizzlePrelude(provider, connection) {
|
|
2533
|
-
const connExpr = connection.useEnv ? `process.env.${connection.envVar || 'DATABASE_URL'}!` : `"${connection.value || ''}"`;
|
|
2534
|
-
if ('postgresql' === provider) return {
|
|
2535
|
-
imports: "import { drizzle } from 'drizzle-orm/node-postgres';\nimport { Pool } from 'pg';",
|
|
2536
|
-
prelude: `const db = drizzle(new Pool({ connectionString: ${connExpr} }));`
|
|
2537
|
-
};
|
|
2538
|
-
if ('mysql' === provider) return {
|
|
2539
|
-
imports: "import { drizzle } from 'drizzle-orm/mysql2';\nimport mysql from 'mysql2/promise';",
|
|
2540
|
-
prelude: `const db = drizzle(await mysql.createConnection(${connExpr}));`
|
|
2541
|
-
};
|
|
2542
|
-
if ('sqlite' === provider) {
|
|
2543
|
-
const file = connection.sqliteFile || './db.sqlite';
|
|
2544
|
-
return {
|
|
2545
|
-
imports: "import { drizzle } from 'drizzle-orm/better-sqlite3';\nimport Database from 'better-sqlite3';",
|
|
2546
|
-
prelude: `const db = drizzle(new Database("${file}"));`
|
|
2547
|
-
};
|
|
2548
|
-
}
|
|
2549
|
-
return {
|
|
2550
|
-
imports: '',
|
|
2551
|
-
prelude: ''
|
|
2552
|
-
};
|
|
2553
|
-
}
|
|
2554
|
-
function buildPrismaPrelude(_provider, _connection) {
|
|
2555
|
-
return {
|
|
2556
|
-
imports: "import { PrismaClient } from '@prisma/client';",
|
|
2557
|
-
prelude: 'const prisma = new PrismaClient();'
|
|
2558
|
-
};
|
|
2559
|
-
}
|
|
2560
|
-
function buildTypeormPrelude(provider, connection) {
|
|
2561
|
-
const connExpr = connection.useEnv ? `process.env.${connection.envVar || 'DATABASE_URL'}!` : `"${connection.value || ''}"`;
|
|
2562
|
-
if ('sqlite' === provider) {
|
|
2563
|
-
const file = connection.sqliteFile || './db.sqlite';
|
|
2564
|
-
return {
|
|
2565
|
-
imports: "import { DataSource } from 'typeorm';",
|
|
2566
|
-
prelude: `const source = new DataSource({ type: 'sqlite', database: "${file}" });`
|
|
2567
|
-
};
|
|
2568
|
-
}
|
|
2569
|
-
const typeMap = {
|
|
2570
|
-
postgresql: 'postgres',
|
|
2571
|
-
mysql: 'mysql',
|
|
2572
|
-
mssql: 'mssql'
|
|
2573
|
-
};
|
|
2574
|
-
return {
|
|
2575
|
-
imports: "import { DataSource } from 'typeorm';",
|
|
2576
|
-
prelude: `const source = new DataSource({ type: '${typeMap[String(provider)]}', url: ${connExpr} });`
|
|
2577
|
-
};
|
|
2578
|
-
}
|
|
2579
|
-
function buildMongoPrelude(connection) {
|
|
2580
|
-
const urlExpr = connection.useEnv ? `process.env.${connection.envVar || 'MONGODB_URI'}!` : `"${connection.value || ''}"`;
|
|
2581
|
-
return {
|
|
2582
|
-
imports: "import { MongoClient } from 'mongodb';",
|
|
2583
|
-
prelude: `const client = new MongoClient(${urlExpr});`
|
|
2584
|
-
};
|
|
2585
|
-
}
|
|
2586
|
-
function buildFileContent(adapter, provider, dbConfig, connection) {
|
|
2587
|
-
const adapterPath = 'mongoAdapter' === adapter ? 'mongo' : adapter.replace('Adapter', '');
|
|
2588
|
-
const importAdapter = `import { ${adapter} } from '@c15t/backend/db/adapters/${adapterPath}';`;
|
|
2589
|
-
let extras = {
|
|
2590
|
-
imports: '',
|
|
2591
|
-
prelude: ''
|
|
2592
|
-
};
|
|
2593
|
-
if ('kyselyAdapter' === adapter) if ('sqlite' === provider) {
|
|
2594
|
-
const file = connection.sqliteFile || './db.sqlite';
|
|
2595
|
-
extras = buildSqliteKyselyPrelude(file);
|
|
2596
|
-
} else extras = buildKyselyPrelude(provider, connection);
|
|
2597
|
-
else if ('drizzleAdapter' === adapter) extras = buildDrizzlePrelude(provider, connection);
|
|
2598
|
-
else if ('prismaAdapter' === adapter) extras = buildPrismaPrelude(provider, connection);
|
|
2599
|
-
else if ('typeormAdapter' === adapter) extras = buildTypeormPrelude(provider, connection);
|
|
2600
|
-
else if ('mongoAdapter' === adapter) extras = buildMongoPrelude(connection);
|
|
2601
|
-
return `import { defineConfig } from '@c15t/backend';
|
|
2602
|
-
${importAdapter}
|
|
2603
|
-
${extras.imports ? `${extras.imports}\n` : ''}
|
|
2604
|
-
${extras.prelude ? `${extras.prelude}\n` : ''}
|
|
2605
|
-
export default defineConfig({
|
|
2606
|
-
adapter: ${dbConfig},
|
|
2607
|
-
});
|
|
2608
|
-
`;
|
|
2609
|
-
}
|
|
2610
|
-
async function promptSelectAdapter() {
|
|
2611
|
-
const selection = await prompts_.select({
|
|
2612
|
-
message: 'Select database adapter:',
|
|
2613
|
-
options: Object.keys(ADAPTER_LABELS).map((key)=>({
|
|
2614
|
-
value: key,
|
|
2615
|
-
label: ADAPTER_LABELS[key]
|
|
2616
|
-
}))
|
|
2617
|
-
});
|
|
2618
|
-
if (prompts_.isCancel(selection)) throw new Cancelled('adapter_select');
|
|
2619
|
-
return selection;
|
|
2620
|
-
}
|
|
2621
|
-
async function promptSelectProvider(adapter) {
|
|
2622
|
-
const providers = PROVIDERS_BY_ADAPTER[adapter];
|
|
2623
|
-
if (0 === providers.length) throw new Error('No providers available for selected adapter');
|
|
2624
|
-
if (1 === providers.length) {
|
|
2625
|
-
const [first] = providers;
|
|
2626
|
-
return first.value;
|
|
2627
|
-
}
|
|
2628
|
-
const selection = await prompts_.select({
|
|
2629
|
-
message: 'Select database provider:',
|
|
2630
|
-
options: providers.map((opt)=>({
|
|
2631
|
-
value: opt.value,
|
|
2632
|
-
label: opt.label
|
|
2633
|
-
}))
|
|
2634
|
-
});
|
|
2635
|
-
if (prompts_.isCancel(selection)) throw new Cancelled('provider_select');
|
|
2636
|
-
return selection;
|
|
2637
|
-
}
|
|
2638
|
-
async function promptConnection(adapter, provider) {
|
|
2639
|
-
const connection = {
|
|
2640
|
-
useEnv: true
|
|
2641
|
-
};
|
|
2642
|
-
if ('sqlite' === provider) {
|
|
2643
|
-
const sqliteFile = await prompts_.text({
|
|
2644
|
-
message: 'SQLite file path:',
|
|
2645
|
-
initialValue: './db.sqlite'
|
|
2646
|
-
});
|
|
2647
|
-
if (prompts_.isCancel(sqliteFile)) throw new Cancelled('sqlite_path');
|
|
2648
|
-
connection.sqliteFile = String(sqliteFile);
|
|
2649
|
-
return connection;
|
|
2650
|
-
}
|
|
2651
|
-
const useEnv = await prompts_.confirm({
|
|
2652
|
-
message: 'Store connection string in an environment variable?',
|
|
2653
|
-
initialValue: true
|
|
2654
|
-
});
|
|
2655
|
-
if (prompts_.isCancel(useEnv)) throw new Cancelled('use_env_confirm');
|
|
2656
|
-
connection.useEnv = Boolean(useEnv);
|
|
2657
|
-
if (connection.useEnv) {
|
|
2658
|
-
const defaultVar = 'mongoAdapter' === adapter ? 'MONGODB_URI' : 'DATABASE_URL';
|
|
2659
|
-
const envVarName = await prompts_.text({
|
|
2660
|
-
message: 'Env var name for connection string:',
|
|
2661
|
-
initialValue: defaultVar
|
|
2662
|
-
});
|
|
2663
|
-
if (prompts_.isCancel(envVarName)) throw new Cancelled('env_var_name');
|
|
2664
|
-
connection.envVar = String(envVarName);
|
|
2665
|
-
return connection;
|
|
2666
|
-
}
|
|
2667
|
-
const placeholder = 'mongoAdapter' === adapter ? 'mongodb+srv://user:pass@host/db' : 'postgresql://user:pass@host:5432/db';
|
|
2668
|
-
const connectionString = await prompts_.text({
|
|
2669
|
-
message: 'Connection string:',
|
|
2670
|
-
placeholder
|
|
2671
|
-
});
|
|
2672
|
-
if (prompts_.isCancel(connectionString)) throw new Cancelled('connection_string');
|
|
2673
|
-
connection.value = String(connectionString);
|
|
2674
|
-
return connection;
|
|
2675
|
-
}
|
|
2676
|
-
async function ensureBackendConfig(context) {
|
|
2677
|
-
const { cwd, logger } = context;
|
|
2678
|
-
const targetPath = external_node_path_["default"].join(cwd, 'c15t-backend.config.ts');
|
|
2679
|
-
if (await pathExists(targetPath)) {
|
|
2680
|
-
logger.debug(`Backend config already exists at ${targetPath}`);
|
|
2681
|
-
return {
|
|
2682
|
-
path: targetPath,
|
|
2683
|
-
dependencies: []
|
|
2684
|
-
};
|
|
2685
|
-
}
|
|
2686
|
-
try {
|
|
2687
|
-
const adapter = await promptSelectAdapter();
|
|
2688
|
-
const provider = await promptSelectProvider(adapter);
|
|
2689
|
-
const connection = await promptConnection(adapter, provider);
|
|
2690
|
-
const dependencies = [];
|
|
2691
|
-
if ('kyselyAdapter' === adapter) {
|
|
2692
|
-
dependencies.push('kysely');
|
|
2693
|
-
if ('postgresql' === provider || 'cockroachdb' === provider) dependencies.push('pg');
|
|
2694
|
-
else if ('mysql' === provider) dependencies.push('mysql2');
|
|
2695
|
-
else if ('mssql' === provider) dependencies.push('mssql');
|
|
2696
|
-
else if ('sqlite' === provider) dependencies.push('better-sqlite3');
|
|
2697
|
-
} else if ('drizzleAdapter' === adapter) {
|
|
2698
|
-
dependencies.push('drizzle-orm');
|
|
2699
|
-
if ('postgresql' === provider) dependencies.push('pg');
|
|
2700
|
-
else if ('mysql' === provider) dependencies.push('mysql2');
|
|
2701
|
-
else if ('sqlite' === provider) dependencies.push('better-sqlite3');
|
|
2702
|
-
} else if ('prismaAdapter' === adapter) dependencies.push('@prisma/client');
|
|
2703
|
-
else if ('typeormAdapter' === adapter) dependencies.push('typeorm');
|
|
2704
|
-
else if ('mongoAdapter' === adapter) dependencies.push('mongodb');
|
|
2705
|
-
const dbConfig = buildDatabaseConfig(adapter, provider, connection);
|
|
2706
|
-
const fileContent = buildFileContent(adapter, String(provider), dbConfig, connection);
|
|
2707
|
-
await promises_["default"].writeFile(targetPath, fileContent, 'utf8');
|
|
2708
|
-
context.logger.success(`Created ${external_node_path_["default"].relative(cwd, targetPath)}`);
|
|
2709
|
-
if ('sqlite' !== provider && connection.useEnv && connection.envVar) context.logger.note(`Remember to set ${connection.envVar} in your environment or .env file.`, 'Environment');
|
|
2710
|
-
return {
|
|
2711
|
-
path: targetPath,
|
|
2712
|
-
dependencies
|
|
2713
|
-
};
|
|
2714
|
-
} catch (err) {
|
|
2715
|
-
if (err instanceof Cancelled) return context.error.handleCancel('Operation cancelled.', {
|
|
2716
|
-
command: 'ensure-backend-config',
|
|
2717
|
-
stage: err.stage
|
|
2718
|
-
});
|
|
2719
|
-
throw err;
|
|
2720
|
-
}
|
|
2721
|
-
}
|
|
2722
|
-
async function handleMigrationResult(context, result) {
|
|
2723
|
-
const { logger, telemetry } = context;
|
|
2724
|
-
telemetry.trackEvent(TelemetryEventName.MIGRATION_PLANNED, {
|
|
2725
|
-
success: true
|
|
2726
|
-
});
|
|
2727
|
-
const saveSQL = await prompts_.confirm({
|
|
2728
|
-
message: 'Save SQL to file?',
|
|
2729
|
-
initialValue: true
|
|
2730
|
-
});
|
|
2731
|
-
if (prompts_.isCancel(saveSQL)) return void telemetry.trackEvent(TelemetryEventName.MIGRATION_FAILED, {
|
|
2732
|
-
saveSql: false
|
|
2733
|
-
});
|
|
2734
|
-
if (saveSQL) {
|
|
2735
|
-
const sql = result.getSQL?.() ?? '';
|
|
2736
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
2737
|
-
const filename = `migration-${timestamp}.sql`;
|
|
2738
|
-
const filepath = (0, external_node_path_.join)(process.cwd(), filename);
|
|
2739
|
-
await (0, promises_.writeFile)(filepath, sql, 'utf-8');
|
|
2740
|
-
logger.success(`SQL saved to: ${filename}`);
|
|
2741
|
-
}
|
|
2742
|
-
const execute = await prompts_.confirm({
|
|
2743
|
-
message: 'Execute this migration?',
|
|
2744
|
-
initialValue: false
|
|
2745
|
-
});
|
|
2746
|
-
if (prompts_.isCancel(execute)) return void telemetry.trackEvent(TelemetryEventName.MIGRATION_FAILED, {
|
|
2747
|
-
execute: false
|
|
2748
|
-
});
|
|
2749
|
-
await result.execute();
|
|
2750
|
-
logger.success('Migration completed.');
|
|
2751
|
-
telemetry.trackEvent(TelemetryEventName.MIGRATION_COMPLETED, {
|
|
2752
|
-
success: true
|
|
2753
|
-
});
|
|
2754
|
-
}
|
|
2755
|
-
async function handleORMResult(context, result) {
|
|
2756
|
-
const { logger, telemetry, cwd } = context;
|
|
2757
|
-
const filePath = external_node_path_["default"].join(cwd, result.path);
|
|
2758
|
-
await promises_["default"].mkdir(external_node_path_["default"].dirname(filePath), {
|
|
2759
|
-
recursive: true
|
|
2760
|
-
});
|
|
2761
|
-
await promises_["default"].writeFile(filePath, result.code);
|
|
2762
|
-
logger.info(`Migration file created at ${filePath}`);
|
|
2763
|
-
telemetry.trackEvent(TelemetryEventName.MIGRATION_COMPLETED, {
|
|
2764
|
-
success: true,
|
|
2765
|
-
migrationFileCreated: true
|
|
2766
|
-
});
|
|
2767
|
-
}
|
|
2768
|
-
async function readConfigAndGetDb(context, absoluteConfigPath) {
|
|
2769
|
-
const { logger } = context;
|
|
2770
|
-
logger.info(`Loading backend config from ${absoluteConfigPath}`);
|
|
2771
|
-
const resolvedPath = external_node_path_["default"].resolve(absoluteConfigPath);
|
|
2772
|
-
try {
|
|
2773
|
-
await promises_["default"].access(resolvedPath);
|
|
2774
|
-
} catch {
|
|
2775
|
-
throw new Error(`Backend config not found at: ${resolvedPath}`);
|
|
2776
|
-
}
|
|
2777
|
-
try {
|
|
2778
|
-
const { config } = await (0, __rspack_external_c12.loadConfig)({
|
|
2779
|
-
configFile: absoluteConfigPath,
|
|
2780
|
-
jitiOptions: {
|
|
2781
|
-
extensions: [
|
|
2782
|
-
'.ts',
|
|
2783
|
-
'.tsx',
|
|
2784
|
-
'.js',
|
|
2785
|
-
'.jsx',
|
|
2786
|
-
'.mjs',
|
|
2787
|
-
'.cjs',
|
|
2788
|
-
'.mts',
|
|
2789
|
-
'.cts',
|
|
2790
|
-
'.cjs'
|
|
2791
|
-
]
|
|
2792
|
-
}
|
|
2793
|
-
});
|
|
2794
|
-
logger.debug('Imported Config');
|
|
2795
|
-
if (!config || 'object' != typeof config || !('adapter' in config)) throw new Error('Invalid backend config: missing required "adapter" property');
|
|
2796
|
-
return {
|
|
2797
|
-
db: __rspack_external__c15t_backend_db_schema_e7c5e6a0.DB.client(config.adapter)
|
|
2798
|
-
};
|
|
2799
|
-
} catch (error) {
|
|
2800
|
-
logger.error('Failed to load backend config', error);
|
|
2801
|
-
if (error instanceof Error) throw error;
|
|
2802
|
-
throw new Error(`Unknown error loading backend config: ${String(error)}`);
|
|
2803
|
-
}
|
|
2804
|
-
}
|
|
2805
|
-
async function migrate(context) {
|
|
2806
|
-
const { logger } = context;
|
|
2807
|
-
logger.info('Starting migration process...');
|
|
2808
|
-
const configResult = await ensureBackendConfig(context);
|
|
2809
|
-
if (!configResult || !configResult.path) return void logger.error('No backend config found.');
|
|
2810
|
-
const { path, dependencies } = configResult;
|
|
2811
|
-
if (dependencies.length > 0) await installDependencies({
|
|
2812
|
-
context,
|
|
2813
|
-
dependenciesToAdd: dependencies,
|
|
2814
|
-
autoInstall: true
|
|
2815
|
-
});
|
|
2816
|
-
const { db } = await readConfigAndGetDb(context, path);
|
|
2817
|
-
logger.info('Loaded c15t-backend.config.ts');
|
|
2818
|
-
const result = await (0, __rspack_external__c15t_backend_db_migrator_ebe6d5c7.migrator)({
|
|
2819
|
-
db,
|
|
2820
|
-
schema: 'latest'
|
|
2821
|
-
});
|
|
2822
|
-
if ('path' in result) await handleORMResult(context, result);
|
|
2823
|
-
else await handleMigrationResult(context, result);
|
|
2824
|
-
}
|
|
2825
|
-
const subcommands = [
|
|
2826
|
-
{
|
|
2827
|
-
name: 'generate',
|
|
2828
|
-
label: 'Generate',
|
|
2829
|
-
hint: 'Generate code for your c15t project',
|
|
2830
|
-
action: generate
|
|
2831
|
-
},
|
|
2832
|
-
{
|
|
2833
|
-
name: 'migrate',
|
|
2834
|
-
label: 'Migrate',
|
|
2835
|
-
hint: 'Run database migrations',
|
|
2836
|
-
action: migrate
|
|
2837
|
-
}
|
|
2838
|
-
];
|
|
2839
|
-
async function selfHost(context) {
|
|
2840
|
-
const { logger, telemetry, commandArgs, error } = context;
|
|
2841
|
-
logger.debug('Starting self-host command...');
|
|
2842
|
-
telemetry.trackEvent(TelemetryEventName.SELF_HOST_STARTED, {});
|
|
2843
|
-
const [subcommand] = commandArgs;
|
|
2844
|
-
if (subcommand) {
|
|
2845
|
-
switch(subcommand){
|
|
2846
|
-
case 'generate':
|
|
2847
|
-
await generate(context, 'self-hosted');
|
|
2848
|
-
break;
|
|
2849
|
-
case 'migrate':
|
|
2850
|
-
await migrate(context);
|
|
2851
|
-
break;
|
|
2852
|
-
default:
|
|
2853
|
-
logger.error(`Unknown self-host subcommand: ${subcommand}`);
|
|
2854
|
-
logger.info('Available subcommands: generate, migrate');
|
|
2855
|
-
telemetry.trackEvent(TelemetryEventName.SELF_HOST_COMPLETED, {
|
|
2856
|
-
success: false,
|
|
2857
|
-
reason: 'unknown_subcommand'
|
|
2858
|
-
});
|
|
2859
|
-
break;
|
|
2860
|
-
}
|
|
2861
|
-
return;
|
|
2862
|
-
}
|
|
2863
|
-
logger.debug('No subcommand specified, entering interactive selection.');
|
|
2864
|
-
telemetry.trackEvent(TelemetryEventName.INTERACTIVE_MENU_OPENED, {
|
|
2865
|
-
context: 'self-host'
|
|
2866
|
-
});
|
|
2867
|
-
const promptOptions = subcommands.map((cmd)=>({
|
|
2868
|
-
value: cmd.name,
|
|
2869
|
-
label: cmd.label,
|
|
2870
|
-
hint: cmd.hint
|
|
2871
|
-
}));
|
|
2872
|
-
promptOptions.push({
|
|
2873
|
-
value: 'exit',
|
|
2874
|
-
label: 'Exit',
|
|
2875
|
-
hint: 'Return to main menu'
|
|
2876
|
-
});
|
|
2877
|
-
const selectedSubcommandName = await prompts_.select({
|
|
2878
|
-
message: (0, utils_logger.$e)('info', 'Which self-host command would you like to run?'),
|
|
2879
|
-
options: promptOptions
|
|
2880
|
-
});
|
|
2881
|
-
if (prompts_.isCancel(selectedSubcommandName) || 'exit' === selectedSubcommandName) {
|
|
2882
|
-
logger.debug('Interactive selection cancelled or exit chosen.');
|
|
2883
|
-
telemetry.trackEvent(TelemetryEventName.INTERACTIVE_MENU_EXITED, {
|
|
2884
|
-
action: prompts_.isCancel(selectedSubcommandName) ? 'cancelled' : 'exit',
|
|
2885
|
-
context: 'self-host'
|
|
2886
|
-
});
|
|
2887
|
-
error.handleCancel('Operation cancelled.', {
|
|
2888
|
-
command: 'self-host',
|
|
2889
|
-
stage: 'menu_selection'
|
|
2890
|
-
});
|
|
2891
|
-
return;
|
|
2892
|
-
}
|
|
2893
|
-
const selectedSubcommand = subcommands.find((cmd)=>cmd.name === selectedSubcommandName);
|
|
2894
|
-
if (selectedSubcommand) {
|
|
2895
|
-
logger.debug(`User selected subcommand: ${selectedSubcommand.name}`);
|
|
2896
|
-
if ('generate' === selectedSubcommand.name) await generate(context, 'self-hosted');
|
|
2897
|
-
else await selectedSubcommand.action(context);
|
|
2898
|
-
} else {
|
|
2899
|
-
logger.error(`Unknown subcommand: ${selectedSubcommandName}`);
|
|
2900
|
-
telemetry.trackEvent(TelemetryEventName.SELF_HOST_COMPLETED, {
|
|
2901
|
-
success: false,
|
|
2902
|
-
reason: 'invalid_selection'
|
|
2903
|
-
});
|
|
2904
|
-
return;
|
|
2905
|
-
}
|
|
2906
|
-
telemetry.trackEvent(TelemetryEventName.SELF_HOST_COMPLETED, {
|
|
2907
|
-
success: true
|
|
2908
|
-
});
|
|
2909
|
-
}
|
|
2910
|
-
async function installSkills(context) {
|
|
2911
|
-
const { logger, packageManager, telemetry } = context;
|
|
2912
|
-
logger.info('c15t agent skills give AI coding assistants deep knowledge of c15t APIs, components, and configuration.');
|
|
2913
|
-
logger.info('Supported tools: Claude Code, Cursor, GitHub Copilot, and any agent that supports the skills format.');
|
|
2914
|
-
const execCommands = {
|
|
2915
|
-
bun: 'bunx',
|
|
2916
|
-
pnpm: 'pnpm dlx',
|
|
2917
|
-
yarn: 'yarn dlx',
|
|
2918
|
-
npm: 'npx'
|
|
2919
|
-
};
|
|
2920
|
-
const execCommand = execCommands[packageManager.name] ?? 'npx';
|
|
2921
|
-
const [cmd, ...baseArgs] = execCommand.split(' ');
|
|
2922
|
-
logger.info(`Running: ${execCommand} skills add c15t/skills`);
|
|
2923
|
-
try {
|
|
2924
|
-
const child = (0, __rspack_external_node_child_process_27f17141.spawn)(cmd, [
|
|
2925
|
-
...baseArgs,
|
|
2926
|
-
'skills',
|
|
2927
|
-
'add',
|
|
2928
|
-
'c15t/skills'
|
|
2929
|
-
], {
|
|
2930
|
-
cwd: context.projectRoot,
|
|
2931
|
-
stdio: 'inherit'
|
|
2932
|
-
});
|
|
2933
|
-
const [exitCode] = await (0, __rspack_external_node_events_0a6aefe7.once)(child, 'exit');
|
|
2934
|
-
if (0 === exitCode) {
|
|
2935
|
-
logger.success('Agent skills installed successfully!');
|
|
2936
|
-
telemetry.trackEvent(TelemetryEventName.ONBOARDING_COMPLETED, {
|
|
2937
|
-
action: 'skills_installed'
|
|
2938
|
-
});
|
|
2939
|
-
} else logger.error(`Skills installation failed (exit code ${exitCode}). Please try again or install manually with: npx skills add c15t/skills`);
|
|
2940
|
-
} catch (error) {
|
|
2941
|
-
logger.error(`Skills installation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2942
|
-
logger.info('You can install manually with: npx skills add c15t/skills');
|
|
2943
|
-
}
|
|
2944
|
-
}
|
|
2945
|
-
async function displayIntro(context, version) {
|
|
2946
|
-
const { logger } = context;
|
|
2947
|
-
logger.info(`${external_picocolors_["default"].bold('Welcome!')} Let's get you set up.`);
|
|
2948
|
-
logger.message('');
|
|
2949
|
-
let figletText = 'c15t';
|
|
2950
|
-
try {
|
|
2951
|
-
figletText = await new Promise((resolve)=>{
|
|
2952
|
-
__rspack_external_figlet["default"].text('c15t', {
|
|
2953
|
-
font: 'Nancyj-Improved',
|
|
2954
|
-
horizontalLayout: 'default',
|
|
2955
|
-
verticalLayout: 'default',
|
|
2956
|
-
width: 80,
|
|
2957
|
-
whitespaceBreak: true
|
|
2958
|
-
}, (err, data)=>{
|
|
2959
|
-
if (err) {
|
|
2960
|
-
logger.debug('Failed to generate figlet text');
|
|
2961
|
-
resolve('c15t');
|
|
2962
|
-
} else resolve(data || 'c15t');
|
|
2963
|
-
});
|
|
2964
|
-
});
|
|
2965
|
-
} catch (error) {
|
|
2966
|
-
logger.debug('Error generating figlet text', error);
|
|
2967
|
-
}
|
|
2968
|
-
const customColor = {
|
|
2969
|
-
teal10: (text)=>`\x1b[38;2;10;80;70m${text}\x1b[0m`,
|
|
2970
|
-
teal20: (text)=>`\x1b[38;2;15;100;90m${text}\x1b[0m`,
|
|
2971
|
-
teal30: (text)=>`\x1b[38;2;20;120;105m${text}\x1b[0m`,
|
|
2972
|
-
teal40: (text)=>`\x1b[38;2;25;150;130m${text}\x1b[0m`,
|
|
2973
|
-
teal50: (text)=>`\x1b[38;2;30;170;150m${text}\x1b[0m`,
|
|
2974
|
-
teal75: (text)=>`\x1b[38;2;34;211;187m${text}\x1b[0m`,
|
|
2975
|
-
teal90: (text)=>`\x1b[38;2;45;225;205m${text}\x1b[0m`,
|
|
2976
|
-
teal100: (text)=>`\x1b[38;2;65;235;220m${text}\x1b[0m`
|
|
2977
|
-
};
|
|
2978
|
-
const lines = figletText.split('\n');
|
|
2979
|
-
const coloredLines = lines.map((line, index)=>{
|
|
2980
|
-
const position = index / (lines.length - 1);
|
|
2981
|
-
if (position < 0.1) return customColor.teal10(line);
|
|
2982
|
-
if (position < 0.2) return customColor.teal20(line);
|
|
2983
|
-
if (position < 0.3) return customColor.teal30(line);
|
|
2984
|
-
if (position < 0.4) return customColor.teal40(line);
|
|
2985
|
-
if (position < 0.5) return customColor.teal50(line);
|
|
2986
|
-
if (position < 0.65) return customColor.teal75(line);
|
|
2987
|
-
if (position < 0.8) return customColor.teal90(line);
|
|
2988
|
-
return customColor.teal100(line);
|
|
2989
|
-
});
|
|
2990
|
-
logger.message(coloredLines.join('\n'));
|
|
2991
|
-
}
|
|
2992
|
-
var constants = __webpack_require__("./src/constants.ts");
|
|
2993
|
-
function createErrorHandlers(context) {
|
|
2994
|
-
const { logger, telemetry } = context;
|
|
2995
|
-
return {
|
|
2996
|
-
handleError: (error, message)=>{
|
|
2997
|
-
logger.error(message, error);
|
|
2998
|
-
if (error instanceof Error) logger.error(error.message);
|
|
2999
|
-
else logger.error(String(error));
|
|
3000
|
-
logger.failed(`${external_picocolors_["default"].red('Operation failed unexpectedly.')}`);
|
|
3001
|
-
process.exit(1);
|
|
3002
|
-
},
|
|
3003
|
-
handleCancel: (message = 'Operation cancelled.', context)=>{
|
|
3004
|
-
logger.debug(`Handling cancellation: ${message}`, context);
|
|
3005
|
-
telemetry.trackEvent(TelemetryEventName.ONBOARDING_EXITED, {
|
|
3006
|
-
reason: 'user_cancelled',
|
|
3007
|
-
command: context?.command || 'unknown',
|
|
3008
|
-
stage: context?.stage || 'unknown'
|
|
3009
|
-
});
|
|
3010
|
-
logger.failed(message);
|
|
3011
|
-
process.exit(0);
|
|
3012
|
-
}
|
|
3013
|
-
};
|
|
3014
|
-
}
|
|
3015
|
-
function createFileSystem(context) {
|
|
3016
|
-
const { logger, cwd } = context;
|
|
3017
|
-
return {
|
|
3018
|
-
getPackageInfo: ()=>{
|
|
3019
|
-
logger.debug('Reading package.json');
|
|
3020
|
-
const packageJsonPath = external_node_path_["default"].join(cwd, 'package.json');
|
|
3021
|
-
logger.debug(`package.json path: ${packageJsonPath}`);
|
|
3022
|
-
try {
|
|
3023
|
-
const packageInfo = __rspack_external_fs_extra_ce68a66b["default"].readJSONSync(packageJsonPath);
|
|
3024
|
-
logger.debug('Successfully read package.json');
|
|
3025
|
-
return {
|
|
3026
|
-
name: packageInfo?.name || 'unknown',
|
|
3027
|
-
version: packageInfo?.version || 'unknown',
|
|
3028
|
-
...packageInfo
|
|
3029
|
-
};
|
|
3030
|
-
} catch (error) {
|
|
3031
|
-
logger.error(`Error reading package.json at ${packageJsonPath}:`, error);
|
|
3032
|
-
return {
|
|
3033
|
-
name: 'unknown',
|
|
3034
|
-
version: 'unknown'
|
|
3035
|
-
};
|
|
3036
|
-
}
|
|
3037
|
-
}
|
|
3038
|
-
};
|
|
3039
|
-
}
|
|
3040
|
-
async function detectFramework(projectRoot, logger) {
|
|
3041
|
-
try {
|
|
3042
|
-
logger?.debug(`Detecting framework in ${projectRoot}`);
|
|
3043
|
-
const packageJsonPath = external_node_path_["default"].join(projectRoot, 'package.json');
|
|
3044
|
-
const packageJson = JSON.parse(await promises_["default"].readFile(packageJsonPath, 'utf-8'));
|
|
3045
|
-
const deps = {
|
|
3046
|
-
...packageJson.dependencies,
|
|
3047
|
-
...packageJson.devDependencies
|
|
3048
|
-
};
|
|
3049
|
-
const hasReact = 'react' in deps;
|
|
3050
|
-
const reactVersion = hasReact ? deps.react : null;
|
|
3051
|
-
logger?.debug(`React detected: ${hasReact}${reactVersion ? ` (version: ${reactVersion})` : ''}`);
|
|
3052
|
-
const tailwindVersion = deps.tailwindcss || null;
|
|
3053
|
-
logger?.debug(`Tailwind detected: ${!!tailwindVersion}${tailwindVersion ? ` (version: ${tailwindVersion})` : ''}`);
|
|
3054
|
-
let framework = null;
|
|
3055
|
-
let frameworkVersion = null;
|
|
3056
|
-
let pkg = hasReact ? '@c15t/react' : 'c15t';
|
|
3057
|
-
if ('next' in deps) {
|
|
3058
|
-
framework = 'Next.js';
|
|
3059
|
-
frameworkVersion = deps.next;
|
|
3060
|
-
pkg = '@c15t/nextjs';
|
|
3061
|
-
} else if ('@remix-run/react' in deps) {
|
|
3062
|
-
framework = 'Remix';
|
|
3063
|
-
frameworkVersion = deps['@remix-run/react'];
|
|
3064
|
-
} else if ('@vitejs/plugin-react' in deps || '@vitejs/plugin-react-swc' in deps) {
|
|
3065
|
-
framework = 'Vite + React';
|
|
3066
|
-
frameworkVersion = deps['@vitejs/plugin-react'] || deps['@vitejs/plugin-react-swc'];
|
|
3067
|
-
} else if ('gatsby' in deps) {
|
|
3068
|
-
framework = 'Gatsby';
|
|
3069
|
-
frameworkVersion = deps.gatsby;
|
|
3070
|
-
} else if (hasReact) {
|
|
3071
|
-
framework = 'React';
|
|
3072
|
-
frameworkVersion = reactVersion;
|
|
3073
|
-
}
|
|
3074
|
-
logger?.debug(`Detected framework: ${framework}${frameworkVersion ? ` (version: ${frameworkVersion})` : ''}, package: ${pkg}`);
|
|
3075
|
-
return {
|
|
3076
|
-
framework,
|
|
3077
|
-
frameworkVersion,
|
|
3078
|
-
pkg,
|
|
3079
|
-
hasReact,
|
|
3080
|
-
reactVersion,
|
|
3081
|
-
tailwindVersion
|
|
3082
|
-
};
|
|
3083
|
-
} catch (error) {
|
|
3084
|
-
logger?.debug(`Framework detection failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
3085
|
-
return {
|
|
3086
|
-
framework: null,
|
|
3087
|
-
frameworkVersion: null,
|
|
3088
|
-
pkg: 'c15t',
|
|
3089
|
-
hasReact: false,
|
|
3090
|
-
reactVersion: null,
|
|
3091
|
-
tailwindVersion: null
|
|
3092
|
-
};
|
|
3093
|
-
}
|
|
3094
|
-
}
|
|
3095
|
-
async function detectProjectRoot(cwd, logger) {
|
|
3096
|
-
let projectRoot = cwd;
|
|
3097
|
-
logger?.debug(`Starting project root detection from: ${cwd}`);
|
|
3098
|
-
try {
|
|
3099
|
-
let prevDir = '';
|
|
3100
|
-
let depth = 0;
|
|
3101
|
-
const maxDepth = 10;
|
|
3102
|
-
while(projectRoot !== prevDir && depth < maxDepth){
|
|
3103
|
-
logger?.debug(`Checking directory (depth ${depth}): ${projectRoot}`);
|
|
3104
|
-
try {
|
|
3105
|
-
const packageJsonPath = external_node_path_["default"].join(projectRoot, 'package.json');
|
|
3106
|
-
logger?.debug(`Looking for package.json at: ${packageJsonPath}`);
|
|
3107
|
-
await promises_["default"].access(packageJsonPath);
|
|
3108
|
-
logger?.debug(`Found package.json at: ${projectRoot}`);
|
|
3109
|
-
break;
|
|
3110
|
-
} catch (error) {
|
|
3111
|
-
logger?.debug(`No package.json found in ${projectRoot}: ${error instanceof Error ? error.message : String(error)}`);
|
|
3112
|
-
prevDir = projectRoot;
|
|
3113
|
-
projectRoot = external_node_path_["default"].dirname(projectRoot);
|
|
3114
|
-
depth++;
|
|
3115
|
-
}
|
|
3116
|
-
}
|
|
3117
|
-
if (projectRoot === prevDir) {
|
|
3118
|
-
logger?.debug('Reached root directory without finding package.json');
|
|
3119
|
-
logger?.failed('Could not find project root (no package.json found)');
|
|
3120
|
-
}
|
|
3121
|
-
if (depth >= maxDepth) {
|
|
3122
|
-
logger?.debug('Reached maximum directory depth without finding package.json');
|
|
3123
|
-
logger?.failed('Could not find project root (reached maximum directory depth)');
|
|
3124
|
-
}
|
|
3125
|
-
logger?.debug(`Project root detection complete. Found at: ${projectRoot}`);
|
|
3126
|
-
return projectRoot;
|
|
3127
|
-
} catch (error) {
|
|
3128
|
-
logger?.debug(`Project root detection failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
3129
|
-
logger?.debug(`Falling back to current directory: ${cwd}`);
|
|
3130
|
-
return cwd;
|
|
3131
|
-
}
|
|
3132
|
-
}
|
|
3133
|
-
const SUPPORTED_PACKAGE_MANAGERS = [
|
|
3134
|
-
'npm',
|
|
3135
|
-
'yarn',
|
|
3136
|
-
'pnpm',
|
|
3137
|
-
'bun'
|
|
3138
|
-
];
|
|
3139
|
-
async function getPackageManagerVersion(pm) {
|
|
3140
|
-
try {
|
|
3141
|
-
const { execSync } = await import("node:child_process");
|
|
3142
|
-
const version = execSync(`${pm} --version`).toString().trim();
|
|
3143
|
-
return version;
|
|
3144
|
-
} catch {
|
|
3145
|
-
return null;
|
|
3146
|
-
}
|
|
3147
|
-
}
|
|
3148
|
-
async function detectPackageManager(projectRoot, logger) {
|
|
3149
|
-
try {
|
|
3150
|
-
logger?.debug('Detecting package manager');
|
|
3151
|
-
const pm = await (0, __rspack_external_package_manager_detector_detect_94d6a9ae.detect)({
|
|
3152
|
-
cwd: projectRoot
|
|
3153
|
-
});
|
|
3154
|
-
if (!pm) throw new Error('No package manager detected');
|
|
3155
|
-
logger?.debug(`Detected package manager: ${pm.name}`);
|
|
3156
|
-
if (!SUPPORTED_PACKAGE_MANAGERS.includes(pm.name)) throw new Error(`Unsupported package manager: ${pm.name}`);
|
|
3157
|
-
return {
|
|
3158
|
-
name: pm.name,
|
|
3159
|
-
version: pm.version ?? null
|
|
3160
|
-
};
|
|
3161
|
-
} catch (error) {
|
|
3162
|
-
logger?.error(`Error detecting package manager: ${error instanceof Error ? error.message : String(error)}`);
|
|
3163
|
-
}
|
|
3164
|
-
const selectedPackageManager = await prompts_.select({
|
|
3165
|
-
message: 'Please select your package manager:',
|
|
3166
|
-
options: [
|
|
3167
|
-
{
|
|
3168
|
-
value: 'npm',
|
|
3169
|
-
label: 'npm'
|
|
3170
|
-
},
|
|
3171
|
-
{
|
|
3172
|
-
value: 'yarn',
|
|
3173
|
-
label: 'yarn'
|
|
3174
|
-
},
|
|
3175
|
-
{
|
|
3176
|
-
value: 'pnpm',
|
|
3177
|
-
label: 'pnpm'
|
|
3178
|
-
},
|
|
3179
|
-
{
|
|
3180
|
-
value: 'bun',
|
|
3181
|
-
label: 'bun'
|
|
3182
|
-
}
|
|
3183
|
-
],
|
|
3184
|
-
initialValue: 'npm'
|
|
3185
|
-
});
|
|
3186
|
-
if (prompts_.isCancel(selectedPackageManager)) {
|
|
3187
|
-
logger?.debug('Package manager selection cancelled by user');
|
|
3188
|
-
logger?.failed('Package manager selection cancelled. Exiting.');
|
|
3189
|
-
process.exit(0);
|
|
3190
|
-
}
|
|
3191
|
-
const version = await getPackageManagerVersion(selectedPackageManager);
|
|
3192
|
-
logger?.debug(`User selected package manager: ${selectedPackageManager} (version: ${version ?? 'unknown'})`);
|
|
3193
|
-
return {
|
|
3194
|
-
name: selectedPackageManager,
|
|
3195
|
-
version
|
|
3196
|
-
};
|
|
3197
|
-
}
|
|
3198
|
-
const globalFlags = [
|
|
3199
|
-
{
|
|
3200
|
-
names: [
|
|
3201
|
-
'--help',
|
|
3202
|
-
'-h'
|
|
3203
|
-
],
|
|
3204
|
-
description: 'Show this help message.',
|
|
3205
|
-
type: 'special',
|
|
3206
|
-
expectsValue: false
|
|
3207
|
-
},
|
|
3208
|
-
{
|
|
3209
|
-
names: [
|
|
3210
|
-
'--version',
|
|
3211
|
-
'-v'
|
|
3212
|
-
],
|
|
3213
|
-
description: 'Show the CLI version.',
|
|
3214
|
-
type: 'special',
|
|
3215
|
-
expectsValue: false
|
|
3216
|
-
},
|
|
3217
|
-
{
|
|
3218
|
-
names: [
|
|
3219
|
-
'--logger'
|
|
3220
|
-
],
|
|
3221
|
-
description: 'Set log level (fatal, error, warn, info, debug).',
|
|
3222
|
-
type: 'string',
|
|
3223
|
-
expectsValue: true
|
|
3224
|
-
},
|
|
3225
|
-
{
|
|
3226
|
-
names: [
|
|
3227
|
-
'--config'
|
|
3228
|
-
],
|
|
3229
|
-
description: 'Specify path to configuration file.',
|
|
3230
|
-
type: 'string',
|
|
3231
|
-
expectsValue: true
|
|
3232
|
-
},
|
|
3233
|
-
{
|
|
3234
|
-
names: [
|
|
3235
|
-
'-y'
|
|
3236
|
-
],
|
|
3237
|
-
description: 'Skip confirmation prompts (use with caution).',
|
|
3238
|
-
type: 'boolean',
|
|
3239
|
-
expectsValue: false
|
|
3240
|
-
},
|
|
3241
|
-
{
|
|
3242
|
-
names: [
|
|
3243
|
-
'--no-telemetry'
|
|
3244
|
-
],
|
|
3245
|
-
description: 'Disable telemetry data collection.',
|
|
3246
|
-
type: 'boolean',
|
|
3247
|
-
expectsValue: false
|
|
3248
|
-
},
|
|
3249
|
-
{
|
|
3250
|
-
names: [
|
|
3251
|
-
'--telemetry-debug'
|
|
3252
|
-
],
|
|
3253
|
-
description: 'Enable debug mode for telemetry (shows detailed telemetry logs).',
|
|
3254
|
-
type: 'boolean',
|
|
3255
|
-
expectsValue: false
|
|
3256
|
-
}
|
|
3257
|
-
];
|
|
3258
|
-
function parseCliArgs(rawArgs, commands) {
|
|
3259
|
-
const parsedFlags = {};
|
|
3260
|
-
const potentialCommandArgsAndUndefined = [];
|
|
3261
|
-
let commandName;
|
|
3262
|
-
const commandArgs = [];
|
|
3263
|
-
for (const flag of globalFlags){
|
|
3264
|
-
const primaryName = flag.names[0]?.replace(/^--/, '').replace(/^-/, '');
|
|
3265
|
-
if (primaryName) parsedFlags[primaryName] = 'boolean' === flag.type ? false : void 0;
|
|
3266
|
-
}
|
|
3267
|
-
for(let i = 0; i < rawArgs.length; i++){
|
|
3268
|
-
const arg = rawArgs[i];
|
|
3269
|
-
if ('string' != typeof arg) continue;
|
|
3270
|
-
let argIsFlagOrValue = false;
|
|
3271
|
-
for (const flag of globalFlags)if (flag.names.includes(arg)) {
|
|
3272
|
-
const primaryName = flag.names[0]?.replace(/^--/, '').replace(/^-/, '');
|
|
3273
|
-
if (primaryName) {
|
|
3274
|
-
argIsFlagOrValue = true;
|
|
3275
|
-
if ('boolean' === flag.type) parsedFlags[primaryName] = true;
|
|
3276
|
-
else if (flag.expectsValue) {
|
|
3277
|
-
const nextArg = rawArgs[i + 1];
|
|
3278
|
-
if (nextArg && !nextArg.startsWith('-')) {
|
|
3279
|
-
parsedFlags[primaryName] = nextArg;
|
|
3280
|
-
i++;
|
|
3281
|
-
} else prompts_.log.warn((0, utils_logger.$e)('warn', `Flag ${arg} expects a value, but none was found or the next item is a flag.`));
|
|
3282
|
-
} else parsedFlags[primaryName] = true;
|
|
3283
|
-
}
|
|
3284
|
-
break;
|
|
3285
|
-
}
|
|
3286
|
-
if (!argIsFlagOrValue) potentialCommandArgsAndUndefined.push(arg);
|
|
3287
|
-
}
|
|
3288
|
-
const potentialCommandArgs = potentialCommandArgsAndUndefined.filter((arg)=>'string' == typeof arg);
|
|
3289
|
-
commandName = potentialCommandArgs.find((arg)=>commands.some((cmd)=>cmd.name === arg));
|
|
3290
|
-
for (const arg of potentialCommandArgs)if (arg !== commandName) commandArgs.push(arg);
|
|
3291
|
-
return {
|
|
3292
|
-
commandName,
|
|
3293
|
-
commandArgs,
|
|
3294
|
-
parsedFlags
|
|
3295
|
-
};
|
|
3296
|
-
}
|
|
3297
|
-
function createUserInteraction(context) {
|
|
3298
|
-
const { logger, error } = context;
|
|
3299
|
-
return {
|
|
3300
|
-
confirm: async (message, initialValue)=>{
|
|
3301
|
-
logger.debug(`Confirm action: "${message}", Initial: ${initialValue}`);
|
|
3302
|
-
const confirmed = await prompts_.confirm({
|
|
3303
|
-
message,
|
|
3304
|
-
initialValue
|
|
3305
|
-
});
|
|
3306
|
-
if (prompts_.isCancel(confirmed)) {
|
|
3307
|
-
error.handleCancel();
|
|
3308
|
-
return false;
|
|
3309
|
-
}
|
|
3310
|
-
logger.debug(`Confirmation result: ${confirmed}`);
|
|
3311
|
-
return confirmed;
|
|
3312
|
-
}
|
|
3313
|
-
};
|
|
3314
|
-
}
|
|
3315
|
-
async function createCliContext(rawArgs, cwd, commands) {
|
|
3316
|
-
const { commandName, commandArgs, parsedFlags } = parseCliArgs(rawArgs, commands);
|
|
3317
|
-
let desiredLogLevel = 'info';
|
|
3318
|
-
const levelArg = parsedFlags.logger;
|
|
3319
|
-
if ('string' == typeof levelArg) if (utils_logger.U0.includes(levelArg)) desiredLogLevel = levelArg;
|
|
3320
|
-
else console.warn(`[CLI Setup] Invalid log level '${levelArg}' provided via --logger. Using default 'info'.`);
|
|
3321
|
-
else if (true === levelArg) console.warn("[CLI Setup] --logger flag found but no level specified. Using default 'info'.");
|
|
3322
|
-
const logger = (0, utils_logger.xw)(desiredLogLevel);
|
|
3323
|
-
logger.debug(`Logger initialized with level: ${desiredLogLevel}`);
|
|
3324
|
-
const baseContext = {
|
|
3325
|
-
logger,
|
|
3326
|
-
flags: parsedFlags,
|
|
3327
|
-
commandName,
|
|
3328
|
-
commandArgs,
|
|
3329
|
-
cwd
|
|
3330
|
-
};
|
|
3331
|
-
const context = baseContext;
|
|
3332
|
-
context.error = createErrorHandlers(context);
|
|
3333
|
-
const userInteraction = createUserInteraction(context);
|
|
3334
|
-
context.confirm = userInteraction.confirm;
|
|
3335
|
-
context.fs = createFileSystem(context);
|
|
3336
|
-
context.projectRoot = await detectProjectRoot(cwd, logger);
|
|
3337
|
-
context.framework = await detectFramework(context.projectRoot, logger);
|
|
3338
|
-
context.packageManager = await detectPackageManager(context.projectRoot, logger);
|
|
3339
|
-
const telemetryDisabled = true === parsedFlags['no-telemetry'];
|
|
3340
|
-
const telemetryDebug = true === parsedFlags['telemetry-debug'];
|
|
3341
|
-
try {
|
|
3342
|
-
context.telemetry = createTelemetry({
|
|
3343
|
-
disabled: telemetryDisabled,
|
|
3344
|
-
debug: telemetryDebug,
|
|
3345
|
-
defaultProperties: {
|
|
3346
|
-
cliVersion: context.fs.getPackageInfo().version,
|
|
3347
|
-
framework: context.framework.framework ?? 'unknown',
|
|
3348
|
-
frameworkVersion: context.framework.frameworkVersion ?? 'unknown',
|
|
3349
|
-
packageManager: context.packageManager.name,
|
|
3350
|
-
packageManagerVersion: context.packageManager.version ?? 'unknown',
|
|
3351
|
-
hasReact: context.framework.hasReact,
|
|
3352
|
-
reactVersion: context.framework.reactVersion ?? 'unknown',
|
|
3353
|
-
package: context.framework.pkg ?? 'unknown'
|
|
3354
|
-
},
|
|
3355
|
-
logger: context.logger
|
|
3356
|
-
});
|
|
3357
|
-
if (telemetryDisabled) logger.debug('Telemetry is disabled by user preference');
|
|
3358
|
-
else if (telemetryDebug) logger.debug('Telemetry initialized with debug mode enabled');
|
|
3359
|
-
else logger.debug('Telemetry initialized');
|
|
3360
|
-
} catch {
|
|
3361
|
-
logger.warn('Failed to initialize telemetry, continuing with telemetry disabled');
|
|
3362
|
-
context.telemetry = createTelemetry({
|
|
3363
|
-
disabled: true,
|
|
3364
|
-
logger: context.logger
|
|
3365
|
-
});
|
|
3366
|
-
}
|
|
3367
|
-
logger.debug('CLI context fully initialized with all utilities');
|
|
3368
|
-
return context;
|
|
3369
|
-
}
|
|
3370
|
-
const src_commands = [
|
|
3371
|
-
{
|
|
3372
|
-
name: 'generate',
|
|
3373
|
-
label: 'Generate (Recommended)',
|
|
3374
|
-
hint: 'Add c15t to your project',
|
|
3375
|
-
description: 'Setup your c15t project',
|
|
3376
|
-
action: (context)=>generate(context)
|
|
3377
|
-
},
|
|
3378
|
-
{
|
|
3379
|
-
name: 'self-host',
|
|
3380
|
-
label: 'Self Host',
|
|
3381
|
-
hint: 'Host c15t backend on your own infra',
|
|
3382
|
-
description: 'Commands for self-hosting c15t (generate, migrate).',
|
|
3383
|
-
action: (context)=>selfHost(context)
|
|
3384
|
-
},
|
|
3385
|
-
{
|
|
3386
|
-
name: 'skills',
|
|
3387
|
-
label: 'Skills',
|
|
3388
|
-
hint: 'Add c15t agent skills for AI tools',
|
|
3389
|
-
description: 'Install c15t skills for AI-assisted development (Claude, Cursor, etc.)',
|
|
3390
|
-
action: (context)=>installSkills(context)
|
|
3391
|
-
},
|
|
3392
|
-
{
|
|
3393
|
-
name: 'github',
|
|
3394
|
-
label: 'GitHub',
|
|
3395
|
-
hint: 'Star us on GitHub',
|
|
3396
|
-
description: 'Open our GitHub repository to give us a star.',
|
|
3397
|
-
action: async (context)=>{
|
|
3398
|
-
const { logger } = context;
|
|
3399
|
-
logger.note(`We're building c15t as an ${external_picocolors_["default"].bold('open source')} project to make consent management more accessible.\nIf you find this useful, we'd really appreciate a GitHub star - it helps others discover the project!`, 'Star Us on GitHub');
|
|
3400
|
-
await (0, __rspack_external_open["default"])(constants.tl.GITHUB);
|
|
3401
|
-
logger.success('Thank you for your support!');
|
|
3402
|
-
}
|
|
3403
|
-
},
|
|
3404
|
-
{
|
|
3405
|
-
name: 'docs',
|
|
3406
|
-
label: 'c15t docs',
|
|
3407
|
-
hint: 'Open documentation',
|
|
3408
|
-
description: 'Open the c15t documentation in your browser.',
|
|
3409
|
-
action: async (context)=>{
|
|
3410
|
-
const { logger } = context;
|
|
3411
|
-
await (0, __rspack_external_open["default"])(`${constants.tl.DOCS}?ref=cli`);
|
|
3412
|
-
logger.success('Documentation opened in your browser.');
|
|
3413
|
-
}
|
|
3414
|
-
}
|
|
3415
|
-
];
|
|
3416
|
-
async function main() {
|
|
3417
|
-
const rawArgs = process.argv.slice(2);
|
|
3418
|
-
const cwd = process.cwd();
|
|
3419
|
-
const context = await createCliContext(rawArgs, cwd, src_commands);
|
|
3420
|
-
const { logger, flags, commandName, commandArgs, error, telemetry } = context;
|
|
3421
|
-
const packageInfo = context.fs.getPackageInfo();
|
|
3422
|
-
const version = packageInfo.version;
|
|
3423
|
-
if (!telemetry.isDisabled()) logger.note(`c15t collects anonymous usage data to help improve the CLI.
|
|
3424
|
-
This data is not personally identifiable and helps us prioritize features.
|
|
3425
|
-
To disable telemetry, use the ${external_picocolors_["default"].cyan('--no-telemetry')}
|
|
3426
|
-
flag or set ${external_picocolors_["default"].cyan('C15T_TELEMETRY_DISABLED=1')} in your environment.`, `${(0, utils_logger.$e)('info', 'Telemetry Notice')}`);
|
|
3427
|
-
try {
|
|
3428
|
-
telemetry.trackEvent(TelemetryEventName.CLI_INVOKED, {
|
|
3429
|
-
version,
|
|
3430
|
-
nodeVersion: process.version,
|
|
3431
|
-
platform: process.platform
|
|
3432
|
-
});
|
|
3433
|
-
telemetry.flushSync();
|
|
3434
|
-
} catch (error) {
|
|
3435
|
-
logger.debug('Failed to track CLI invocation:', error);
|
|
3436
|
-
}
|
|
3437
|
-
if (flags.version) {
|
|
3438
|
-
logger.debug('Version flag detected');
|
|
3439
|
-
logger.message(`c15t CLI version ${version}`);
|
|
3440
|
-
telemetry.trackEvent(TelemetryEventName.VERSION_DISPLAYED, {
|
|
3441
|
-
version
|
|
3442
|
-
});
|
|
3443
|
-
telemetry.flushSync();
|
|
3444
|
-
await telemetry.shutdown();
|
|
3445
|
-
process.exit(0);
|
|
3446
|
-
}
|
|
3447
|
-
if (flags.help) {
|
|
3448
|
-
logger.debug('Help flag detected. Displaying help and exiting.');
|
|
3449
|
-
telemetry.trackEvent(TelemetryEventName.HELP_DISPLAYED, {
|
|
3450
|
-
version
|
|
3451
|
-
});
|
|
3452
|
-
telemetry.flushSync();
|
|
3453
|
-
showHelpMenu(context, version, src_commands, globalFlags);
|
|
3454
|
-
await telemetry.shutdown();
|
|
3455
|
-
process.exit(0);
|
|
3456
|
-
}
|
|
3457
|
-
logger.debug('Raw process arguments:', process.argv);
|
|
3458
|
-
logger.debug('Parsed command name:', commandName);
|
|
3459
|
-
logger.debug('Parsed command args:', commandArgs);
|
|
3460
|
-
logger.debug('Parsed global flags:', flags);
|
|
3461
|
-
await displayIntro(context, version);
|
|
3462
|
-
logger.debug(`Current working directory: ${cwd}`);
|
|
3463
|
-
logger.debug(`Config path flag: ${flags.config}`);
|
|
3464
|
-
try {
|
|
3465
|
-
if (commandName) {
|
|
3466
|
-
const command = src_commands.find((cmd)=>cmd.name === commandName);
|
|
3467
|
-
if (command) {
|
|
3468
|
-
logger.info(`Executing command: ${command.name}`);
|
|
3469
|
-
telemetry.trackCommand(command.name, commandArgs, flags);
|
|
3470
|
-
await command.action(context);
|
|
3471
|
-
telemetry.trackEvent(TelemetryEventName.COMMAND_SUCCEEDED, {
|
|
3472
|
-
command: command.name,
|
|
3473
|
-
executionTime: Date.now() - performance.now()
|
|
3474
|
-
});
|
|
3475
|
-
telemetry.flushSync();
|
|
3476
|
-
} else {
|
|
3477
|
-
logger.error(`Unknown command: ${commandName}`);
|
|
3478
|
-
telemetry.trackEvent(TelemetryEventName.COMMAND_UNKNOWN, {
|
|
3479
|
-
unknownCommand: commandName
|
|
3480
|
-
});
|
|
3481
|
-
telemetry.flushSync();
|
|
3482
|
-
logger.info('Run c15t --help to see available commands.');
|
|
3483
|
-
await telemetry.shutdown();
|
|
3484
|
-
process.exit(1);
|
|
3485
|
-
}
|
|
3486
|
-
} else {
|
|
3487
|
-
logger.debug('No command specified, entering interactive selection.');
|
|
3488
|
-
telemetry.trackEvent(TelemetryEventName.INTERACTIVE_MENU_OPENED, {});
|
|
3489
|
-
const promptOptions = src_commands.map((cmd)=>({
|
|
3490
|
-
value: cmd.name,
|
|
3491
|
-
label: cmd.label,
|
|
3492
|
-
hint: cmd.hint
|
|
3493
|
-
}));
|
|
3494
|
-
promptOptions.push({
|
|
3495
|
-
value: 'exit',
|
|
3496
|
-
label: 'exit',
|
|
3497
|
-
hint: 'Close the CLI'
|
|
3498
|
-
});
|
|
3499
|
-
const selectedCommandName = await prompts_.select({
|
|
3500
|
-
message: (0, utils_logger.$e)('info', 'Which command would you like to run?'),
|
|
3501
|
-
options: promptOptions
|
|
3502
|
-
});
|
|
3503
|
-
if (prompts_.isCancel(selectedCommandName) || 'exit' === selectedCommandName) {
|
|
3504
|
-
logger.debug('Interactive selection cancelled or exit chosen.');
|
|
3505
|
-
telemetry.trackEvent(TelemetryEventName.INTERACTIVE_MENU_EXITED, {
|
|
3506
|
-
action: prompts_.isCancel(selectedCommandName) ? 'cancelled' : 'exit'
|
|
3507
|
-
});
|
|
3508
|
-
context.error.handleCancel('Operation cancelled.', {
|
|
3509
|
-
command: 'interactive_menu',
|
|
3510
|
-
stage: 'exit'
|
|
3511
|
-
});
|
|
3512
|
-
} else {
|
|
3513
|
-
const selectedCommand = src_commands.find((cmd)=>cmd.name === selectedCommandName);
|
|
3514
|
-
if (selectedCommand) {
|
|
3515
|
-
logger.debug(`User selected command: ${selectedCommand.name}`);
|
|
3516
|
-
telemetry.trackCommand(selectedCommand.name, [], flags);
|
|
3517
|
-
await selectedCommand.action(context);
|
|
3518
|
-
telemetry.trackEvent(TelemetryEventName.COMMAND_SUCCEEDED, {
|
|
3519
|
-
command: selectedCommand.name,
|
|
3520
|
-
executionTime: Date.now() - performance.now()
|
|
3521
|
-
});
|
|
3522
|
-
telemetry.flushSync();
|
|
3523
|
-
} else {
|
|
3524
|
-
telemetry.trackEvent(TelemetryEventName.COMMAND_UNKNOWN, {
|
|
3525
|
-
unknownCommand: String(selectedCommandName)
|
|
3526
|
-
});
|
|
3527
|
-
telemetry.flushSync();
|
|
3528
|
-
error.handleError(new Error(`Command '${selectedCommandName}' not found`), 'An internal error occurred');
|
|
3529
|
-
}
|
|
3530
|
-
}
|
|
3531
|
-
}
|
|
3532
|
-
logger.debug('Command execution completed');
|
|
3533
|
-
telemetry.trackEvent(TelemetryEventName.CLI_COMPLETED, {
|
|
3534
|
-
success: true
|
|
3535
|
-
});
|
|
3536
|
-
telemetry.flushSync();
|
|
3537
|
-
} catch (executionError) {
|
|
3538
|
-
telemetry.trackEvent(TelemetryEventName.COMMAND_FAILED, {
|
|
3539
|
-
command: commandName,
|
|
3540
|
-
error: executionError instanceof Error ? executionError.message : String(executionError)
|
|
3541
|
-
});
|
|
3542
|
-
telemetry.flushSync();
|
|
3543
|
-
error.handleError(executionError, 'An unexpected error occurred during command execution');
|
|
3544
|
-
}
|
|
3545
|
-
await telemetry.shutdown();
|
|
3546
|
-
}
|
|
3547
|
-
main();
|
|
3548
|
-
export { main };
|
|
2
|
+
export { main } from "./145.mjs";
|