catalyst-core 1.0.2-canary.1 → 1.0.2
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/bin/catalyst.js +105 -1
- package/changelog.md +34 -0
- package/dist/cli/README.md +119 -0
- package/dist/cli/appConfig.js +51 -0
- package/dist/cli/buildErrors.js +170 -0
- package/dist/cli/buildWarnings.js +28 -0
- package/dist/cli/devOutput.js +524 -0
- package/dist/cli/diagnostic.js +388 -0
- package/dist/cli/hints.js +69 -0
- package/dist/cli/package.json +3 -0
- package/dist/cli/spinner.js +141 -0
- package/dist/cli/theme.js +155 -0
- package/dist/errors/index.js +7 -3
- package/dist/logger.js +61 -6
- package/dist/native/androidProject/app/build.gradle.kts +2 -1
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/CustomWebview.kt +2 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/MainActivity.kt +9 -0
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/SplashActivity.kt +65 -34
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/SplashOverlay.kt +109 -0
- package/dist/native/androidSetup.js +46 -57
- package/dist/native/buildAndroid/assets.js +22 -13
- package/dist/native/buildAndroid/build.js +98 -26
- package/dist/native/buildAndroid/config.js +43 -12
- package/dist/native/buildAndroid/index.js +49 -191
- package/dist/native/buildAppAndroid.js +19 -8
- package/dist/native/buildAppIos.js +35 -16
- package/dist/native/buildIos/assets.js +1 -6
- package/dist/native/buildIos/build.js +66 -95
- package/dist/native/buildIos/config.js +26 -8
- package/dist/native/buildIos/index.js +143 -64
- package/dist/native/buildIos/plugins.js +12 -15
- package/dist/native/internalPluginUtils.js +0 -1
- package/dist/native/iosnativeWebView/CoreLogic/Sources/CatalystCoreLogic/Constants/ConfigConstants.swift +2 -0
- package/dist/native/iosnativeWebView/Sources/Core/WebView/SplashHTMLView.swift +31 -0
- package/dist/native/iosnativeWebView/Sources/Core/WebView/SplashView.swift +17 -1
- package/dist/native/iosnativeWebView/Sources/Core/WebView/SplashViewModel.swift +41 -1
- package/dist/native/iosnativeWebView/Sources/Core/WebView/WebViewModel.swift +2 -0
- package/dist/native/iosnativeWebView/Sources/Core/WebView/WebViewNavigationDelegate.swift +3 -0
- package/dist/native/pluginComposerAndroid.js +2 -3
- package/dist/native/renameAndroidProject.js +42 -20
- package/dist/native/setupEmulatorIos.js +28 -49
- package/dist/native/setupServer.js +12 -15
- package/dist/native/terminalProgress.js +186 -147
- package/dist/native/utils.js +340 -54
- package/dist/otel.js +15 -9
- package/dist/scripts/build.js +313 -42
- package/dist/scripts/generateOfflineManifest.js +11 -1
- package/dist/scripts/loadEnvironmentVariables.js +24 -2
- package/dist/scripts/preServerInit.js +32 -10
- package/dist/scripts/preflight.js +35 -11
- package/dist/scripts/scriptUtils.js +34 -0
- package/dist/scripts/serve.js +64 -15
- package/dist/scripts/start.js +58 -21
- package/dist/server/expressServer.js +167 -32
- package/dist/server/renderer/handler.jsx +87 -11
- package/dist/server/utils/validator.js +14 -11
- package/dist/vite/manifest-categorization-plugin.js +7 -5
- package/dist/vite/resolveDevServerConfig.js +9 -2
- package/dist/vite/vite.config.client.js +18 -0
- package/dist/vite/vite.config.js +73 -13
- package/dist/vite/vite.config.server.js +21 -0
- package/dist/web-router/components/MetaTag.jsx +15 -2
- package/dist/web-router/components/MetaTag.test.jsx +71 -2
- package/dist/webmcp/WebMcpProvider.jsx +3 -2
- package/dist/webmcp/useTool.js +4 -1
- package/mcp_v2/conversion-tasks.json +6 -5
- package/mcp_v2/knowledge-base.json +124 -7
- package/mcp_v2/test/config.test.ts +59 -0
- package/mcp_v2/tools/build.js +6 -6
- package/mcp_v2/tools/config.js +35 -18
- package/mcp_v2/tools/conversion.js +7 -13
- package/package.json +5 -5
- package/test/cli/buildErrors.test.ts +173 -0
- package/test/cli/buildWarnings.test.cjs +62 -0
- package/test/cli/devOutput.test.ts +549 -0
- package/test/cli/diagnostic.test.ts +434 -0
- package/test/cli/output.test.cjs +90 -0
- package/test/cli/spinner.test.ts +177 -0
- package/test/cli/theme.test.ts +163 -0
- package/test/native/redactSecrets.test.ts +72 -0
- package/test/native/utils.test.ts +532 -0
- package/test/scripts/build.test.ts +275 -0
- package/test/scripts/serve.test.ts +102 -0
- package/test/server/fixtures/template/src/js/routes/index.jsx +8 -0
- package/test/server/handler.test.ts +17 -0
- package/test/server/logger.test.ts +185 -0
- package/test/server/otel.test.ts +556 -0
- package/test/server/validator.test.ts +19 -8
- package/dist/scripts/checkVersion.js +0 -3
- package/dist/scripts/cleanCache.js +0 -30
|
@@ -4,196 +4,235 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
-
var
|
|
7
|
+
var _theme = _interopRequireDefault(require("../cli/theme.js"));
|
|
8
|
+
var _spinner = _interopRequireDefault(require("../cli/spinner.js"));
|
|
8
9
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
// Plain ESM imports of a CommonJS module: this file is authored as ESM but
|
|
11
|
+
// babel-compiled to CJS by `npm run prepare` (src/native/package.json pins
|
|
12
|
+
// "type": "commonjs"), so these become require() calls and the interop is
|
|
13
|
+
// babel's. import.meta is unavailable after that transform, hence no
|
|
14
|
+
// createRequire here.
|
|
15
|
+
|
|
16
|
+
const {
|
|
17
|
+
GUTTER,
|
|
18
|
+
glyph,
|
|
19
|
+
t,
|
|
20
|
+
header,
|
|
21
|
+
duration,
|
|
22
|
+
isInteractive,
|
|
23
|
+
isVerbose,
|
|
24
|
+
step: stepLine
|
|
25
|
+
} = _theme.default;
|
|
26
|
+
const {
|
|
27
|
+
Spinner
|
|
28
|
+
} = _spinner.default;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Step-by-step progress for the native builds.
|
|
32
|
+
*
|
|
33
|
+
* Append-only by design. An earlier version redrew the whole step tree in
|
|
34
|
+
* place on every change, which meant the renderer had to own a multi-line
|
|
35
|
+
* region of the screen -- and every interleaving with child output (gradle,
|
|
36
|
+
* xcodebuild) became a cursor-math bug. Here each step settles into a single
|
|
37
|
+
* permanent line as it finishes, and the only live thing is a one-line spinner
|
|
38
|
+
* that owns nothing but its own row. Streamed output can therefore appear
|
|
39
|
+
* between steps with nothing to corrupt.
|
|
40
|
+
*
|
|
41
|
+
* The public API (start/complete/fail/log/pause/resume/printTreeContent) is
|
|
42
|
+
* unchanged, because the native build code calls it from ~400 places.
|
|
43
|
+
*/
|
|
9
44
|
class TerminalProgress {
|
|
45
|
+
/**
|
|
46
|
+
* @param {object} steps - id -> description
|
|
47
|
+
* @param {string} title - the invocation, e.g. "catalyst buildApp"
|
|
48
|
+
* @param {object} [options]
|
|
49
|
+
* @param {string} [options.subject] - the target, e.g. "android"
|
|
50
|
+
*/
|
|
10
51
|
constructor(steps, title = "Setup Progress", options = {}) {
|
|
11
52
|
this.steps = new Map(Object.entries(steps).map(([id, description]) => [id, {
|
|
12
53
|
id,
|
|
13
54
|
description,
|
|
14
55
|
status: "pending",
|
|
15
|
-
error: null
|
|
56
|
+
error: null,
|
|
57
|
+
startedAt: 0
|
|
16
58
|
}]));
|
|
17
59
|
this.title = title;
|
|
60
|
+
this.subject = options.subject;
|
|
61
|
+
this.startedAt = Date.now();
|
|
18
62
|
this.currentStep = null;
|
|
19
|
-
this.
|
|
20
|
-
this.
|
|
21
|
-
this.
|
|
22
|
-
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
stepSpacing: options.stepSpacing ?? 0,
|
|
29
|
-
errorPaddingLeft: options.errorPaddingLeft ?? 4,
|
|
30
|
-
bottomMargin: options.bottomMargin ?? 1
|
|
31
|
-
};
|
|
63
|
+
this.isInteractive = options.isInteractive ?? isInteractive();
|
|
64
|
+
this.spinner = new Spinner(process.stdout);
|
|
65
|
+
this.headerPrinted = false;
|
|
66
|
+
this.pauseDepth = 0;
|
|
67
|
+
// The native build narrates every internal decision ("Package.swift
|
|
68
|
+
// already up to date", "Copied 0 plugin files"). Useful when debugging
|
|
69
|
+
// the build itself, noise otherwise -- so by default those notes ride on
|
|
70
|
+
// the spinner's row and vanish, and --verbose prints them as lines.
|
|
71
|
+
this.verbose = options.verbose ?? isVerbose();
|
|
32
72
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
error: "✗",
|
|
38
|
-
info: "ℹ",
|
|
39
|
-
warning: "⚠",
|
|
40
|
-
prompt: "?"
|
|
41
|
-
};
|
|
42
|
-
printTreeContent(title, content) {
|
|
43
|
-
// Add top padding
|
|
44
|
-
console.log("\n".repeat(this.options.titlePaddingTop));
|
|
45
|
-
|
|
46
|
-
// Print the title
|
|
47
|
-
console.log(`${_ansis.default.cyan(_ansis.default.bold(title))}`);
|
|
48
|
-
|
|
49
|
-
// Process and print each line of content
|
|
50
|
-
for (const line of content) {
|
|
51
|
-
if (typeof line === "string") {
|
|
52
|
-
console.log(`${" ".repeat(this.options.stepPaddingLeft)}${line}`);
|
|
53
|
-
} else if (typeof line === "object") {
|
|
54
|
-
const {
|
|
55
|
-
text,
|
|
56
|
-
indent = 0,
|
|
57
|
-
prefix = "",
|
|
58
|
-
color = "white"
|
|
59
|
-
} = line;
|
|
60
|
-
const indentation = " ".repeat(this.options.stepPaddingLeft + indent * 3);
|
|
61
|
-
const coloredText = _ansis.default[color] ? _ansis.default[color](text) : text;
|
|
62
|
-
console.log(`${indentation}${prefix}${coloredText}`);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
73
|
+
ensureHeader() {
|
|
74
|
+
if (this.headerPrinted) return;
|
|
75
|
+
this.headerPrinted = true;
|
|
76
|
+
process.stdout.write(header(this.title, this.subject));
|
|
65
77
|
}
|
|
66
78
|
start(id) {
|
|
67
79
|
const step = this.steps.get(id);
|
|
68
80
|
if (!step) throw new Error(`Step ${id} not found`);
|
|
81
|
+
this.ensureHeader();
|
|
69
82
|
this.currentStep = step;
|
|
70
83
|
step.status = "running";
|
|
71
|
-
|
|
84
|
+
step.startedAt = Date.now();
|
|
85
|
+
this.spinner.start(step.description);
|
|
72
86
|
}
|
|
73
87
|
complete(id) {
|
|
74
88
|
const step = this.steps.get(id);
|
|
75
89
|
if (!step) throw new Error(`Step ${id} not found`);
|
|
76
90
|
step.status = "completed";
|
|
77
|
-
|
|
78
|
-
this.currentStep = null;
|
|
79
|
-
}
|
|
80
|
-
this.render();
|
|
91
|
+
this.settle(step, "done");
|
|
81
92
|
}
|
|
82
93
|
fail(id, error) {
|
|
83
94
|
const step = this.steps.get(id);
|
|
84
95
|
if (!step) throw new Error(`Step ${id} not found`);
|
|
85
96
|
step.status = "error";
|
|
86
97
|
step.error = error;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
this.render();
|
|
95
|
-
console.log("");
|
|
96
|
-
}
|
|
97
|
-
resume() {
|
|
98
|
-
this.isPaused = false;
|
|
99
|
-
console.log("");
|
|
100
|
-
this.render();
|
|
101
|
-
}
|
|
102
|
-
getStepIcon(step) {
|
|
103
|
-
const icon = TerminalProgress.icons[step.status] || TerminalProgress.icons.pending;
|
|
104
|
-
switch (step.status) {
|
|
105
|
-
case "completed":
|
|
106
|
-
return _ansis.default.green(icon);
|
|
107
|
-
case "error":
|
|
108
|
-
return _ansis.default.red(icon);
|
|
109
|
-
case "running":
|
|
110
|
-
return _ansis.default.blue(icon);
|
|
111
|
-
default:
|
|
112
|
-
return _ansis.default.gray(icon);
|
|
98
|
+
this.settle(step, "fail");
|
|
99
|
+
|
|
100
|
+
// A bare exit-code message says nothing the ✗ line has not already
|
|
101
|
+
// said, and the diagnostic that follows repeats it verbatim as its
|
|
102
|
+
// headline. Only print detail that adds something.
|
|
103
|
+
if (error && !/^Command failed with exit code \d+$/.test(String(error).trim())) {
|
|
104
|
+
console.log(`${GUTTER}${t.dim(glyph.last)} ${t.bad(error)}`);
|
|
113
105
|
}
|
|
114
106
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
107
|
+
settle(step, state) {
|
|
108
|
+
this.ensureHeader();
|
|
109
|
+
if (this.currentStep === step) this.currentStep = null;
|
|
110
|
+
if (this.spinner.active) {
|
|
111
|
+
this.spinner.stop(state, step.description);
|
|
112
|
+
} else {
|
|
113
|
+
console.log(stepLine(step.description, step.startedAt ? Date.now() - step.startedAt : null, state));
|
|
120
114
|
}
|
|
121
115
|
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* A note that belongs with the current step rather than being a step.
|
|
119
|
+
*
|
|
120
|
+
* Warnings, errors, prompts and `note` always print, beneath the running
|
|
121
|
+
* line and marked as subordinate. `info` and `success` are narration: by
|
|
122
|
+
* default they replace the spinner's detail text and leave no line behind,
|
|
123
|
+
* and only --verbose keeps them. Use `note` for the rare line a user must
|
|
124
|
+
* act on or keep (a manual launch step, where a keystore was written).
|
|
125
|
+
*/
|
|
122
126
|
log(message, type = "info") {
|
|
123
|
-
this.
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
switch (type) {
|
|
127
|
-
case "success":
|
|
128
|
-
icon = TerminalProgress.icons.completed;
|
|
129
|
-
color = _ansis.default.green;
|
|
130
|
-
break;
|
|
131
|
-
case "error":
|
|
132
|
-
icon = TerminalProgress.icons.error;
|
|
133
|
-
color = _ansis.default.red;
|
|
134
|
-
break;
|
|
135
|
-
case "warning":
|
|
136
|
-
icon = TerminalProgress.icons.warning;
|
|
137
|
-
color = _ansis.default.yellow;
|
|
138
|
-
break;
|
|
139
|
-
case "prompt":
|
|
140
|
-
icon = TerminalProgress.icons.prompt;
|
|
141
|
-
color = _ansis.default.yellow;
|
|
142
|
-
break;
|
|
143
|
-
default:
|
|
144
|
-
icon = TerminalProgress.icons.info;
|
|
145
|
-
color = _ansis.default.blue;
|
|
127
|
+
if (!this.verbose && (type === "info" || type === "success")) {
|
|
128
|
+
if (message && this.currentStep) this.status(String(message).trim());
|
|
129
|
+
return;
|
|
146
130
|
}
|
|
147
|
-
|
|
148
|
-
|
|
131
|
+
this.ensureHeader();
|
|
132
|
+
const mark = type === "success" ? t.ok(glyph.done) : type === "error" ? t.bad(glyph.fail) : type === "warning" ? t.warn(glyph.warn) : type === "prompt" ? t.warn("?") : type === "note" ? t.accent(glyph.arrow) : t.dim(glyph.info);
|
|
133
|
+
|
|
134
|
+
// Stand the spinner down for exactly one line, then bring it back, so
|
|
135
|
+
// the message lands above the live row instead of fighting it.
|
|
136
|
+
const wasSpinning = this.spinner.active;
|
|
137
|
+
if (wasSpinning) this.spinner.pause();
|
|
138
|
+
console.log(`${GUTTER}${t.dim(glyph.pipe)} ${mark} ${message}`);
|
|
139
|
+
if (wasSpinning) this.spinner.resume();
|
|
149
140
|
}
|
|
150
|
-
render() {
|
|
151
|
-
if (this.isPaused) return;
|
|
152
|
-
this.clearLines();
|
|
153
|
-
let output = "";
|
|
154
|
-
let currentLineCount = 0;
|
|
155
141
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
142
|
+
/** The one action that fixes a failure, under the ✗ line. */
|
|
143
|
+
hint(text) {
|
|
144
|
+
if (!text) return;
|
|
145
|
+
this.ensureHeader();
|
|
146
|
+
if (this.spinner.active) this.spinner.pause();
|
|
147
|
+
console.log(`\n${GUTTER}${t.accent("hint")} ${text}\n`);
|
|
148
|
+
}
|
|
159
149
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
150
|
+
/**
|
|
151
|
+
* Stand the renderer down so a child process can write to the terminal.
|
|
152
|
+
* Nestable: only the outermost resume restarts the animation.
|
|
153
|
+
*/
|
|
154
|
+
pause() {
|
|
155
|
+
this.pauseDepth++;
|
|
156
|
+
if (this.pauseDepth > 1) return;
|
|
157
|
+
this.spinner.pause();
|
|
158
|
+
}
|
|
159
|
+
resume() {
|
|
160
|
+
if (this.pauseDepth === 0) return;
|
|
161
|
+
this.pauseDepth--;
|
|
162
|
+
if (this.pauseDepth > 0) return;
|
|
163
|
+
this.spinner.resume();
|
|
164
|
+
}
|
|
164
165
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
166
|
+
/**
|
|
167
|
+
* Show what the running step is doing right now, on the spinner's own row.
|
|
168
|
+
*
|
|
169
|
+
* This replaces streaming a child's output: the row is rewritten, never
|
|
170
|
+
* appended to, so a build that emits hundreds of lines costs one line of
|
|
171
|
+
* screen. Ignored when there is no live spinner, and a null detail leaves
|
|
172
|
+
* the label alone.
|
|
173
|
+
*/
|
|
174
|
+
status(detail) {
|
|
175
|
+
if (!detail || !this.currentStep) return;
|
|
176
|
+
this.spinner.update(`${this.currentStep.description} ${t.dim(detail)}`);
|
|
177
|
+
}
|
|
168
178
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
179
|
+
/**
|
|
180
|
+
* The closing line every command ends on: what happened, how long it took,
|
|
181
|
+
* and the one command to run next.
|
|
182
|
+
*/
|
|
183
|
+
summary(result, nextStep) {
|
|
184
|
+
this.ensureHeader();
|
|
185
|
+
const elapsed = duration(Date.now() - this.startedAt);
|
|
186
|
+
console.log(`${GUTTER}${t.ok(glyph.done)} ${t.bold(`${result} in ${elapsed}`)}`);
|
|
187
|
+
if (nextStep) {
|
|
188
|
+
// Name exactly one command in the accent. Colour each fragment
|
|
189
|
+
// separately -- wrapping dim() around text that already contains a
|
|
190
|
+
// reset would end the dim early and leave the tail uncoloured.
|
|
191
|
+
const parts = nextStep.split(/(catalyst [\w:]+)/);
|
|
192
|
+
const line = parts.map((part, index) => index % 2 === 1 ? t.accent(part) : t.dim(part)).join("");
|
|
193
|
+
console.log(`${GUTTER} ${line}`);
|
|
194
|
+
}
|
|
195
|
+
console.log("");
|
|
196
|
+
}
|
|
181
197
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
198
|
+
/** A titled block of key/value detail, used for build summaries. */
|
|
199
|
+
printTreeContent(title, content) {
|
|
200
|
+
this.ensureHeader();
|
|
201
|
+
// A block is a settled thing; the spinner must be off its row first, or
|
|
202
|
+
// the live line eats the blank separator above the title.
|
|
203
|
+
this.spinner.stop();
|
|
204
|
+
console.log(`\n${GUTTER}${t.bold(title)}`);
|
|
205
|
+
for (const [index, line] of content.entries()) {
|
|
206
|
+
const isLast = index === content.length - 1;
|
|
207
|
+
if (typeof line === "string") {
|
|
208
|
+
// A bare string is a section label rather than a leaf.
|
|
209
|
+
console.log(line.startsWith("\n") ? `${GUTTER}${t.dim(line.trim())}` : `${GUTTER}${line}`);
|
|
210
|
+
continue;
|
|
186
211
|
}
|
|
212
|
+
const {
|
|
213
|
+
text,
|
|
214
|
+
color = "white"
|
|
215
|
+
} = line;
|
|
216
|
+
const paint = color === "white" ? s => s : t[colorAlias(color)] || (s => s);
|
|
217
|
+
console.log(`${GUTTER}${t.dim(isLast ? glyph.last : glyph.branch)} ${paint(text)}`);
|
|
187
218
|
}
|
|
219
|
+
console.log("");
|
|
220
|
+
}
|
|
221
|
+
}
|
|
188
222
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
223
|
+
/** Map the legacy colour names used across the native build to the theme. */
|
|
224
|
+
function colorAlias(name) {
|
|
225
|
+
switch (name) {
|
|
226
|
+
case "green":
|
|
227
|
+
return "ok";
|
|
228
|
+
case "red":
|
|
229
|
+
return "bad";
|
|
230
|
+
case "yellow":
|
|
231
|
+
return "warn";
|
|
232
|
+
case "cyan":
|
|
233
|
+
return "accent";
|
|
234
|
+
default:
|
|
235
|
+
return "dim";
|
|
197
236
|
}
|
|
198
237
|
}
|
|
199
238
|
var _default = exports.default = TerminalProgress;
|