@zhipu/zp-cli 0.0.1 → 0.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.
@@ -0,0 +1,191 @@
1
+ import { t as runCommandCaptured } from "./cli.mjs";
2
+ import { reactive } from "vue";
3
+ //#region src/utils/terminal-output.ts
4
+ function clearCurrentLine(output) {
5
+ const lastNewline = output.lastIndexOf("\n");
6
+ return lastNewline === -1 ? "" : output.slice(0, lastNewline + 1);
7
+ }
8
+ const ESC = "\x1B";
9
+ function startsWithClearLine(rest) {
10
+ if (rest.startsWith(`${ESC}[2K`)) return 4;
11
+ if (rest.startsWith(`${ESC}[K`)) return 3;
12
+ return null;
13
+ }
14
+ function startsWithCursorColumn(rest) {
15
+ if (!rest.startsWith(`${ESC}[`)) return null;
16
+ let index = 2;
17
+ while (index < rest.length && rest[index] >= "0" && rest[index] <= "9") index += 1;
18
+ if (rest[index] !== "G") return null;
19
+ return index + 1;
20
+ }
21
+ function startsWithCursorPosition(rest) {
22
+ if (!rest.startsWith(`${ESC}[`)) return null;
23
+ let index = 2;
24
+ while (index < rest.length && rest[index] >= "0" && rest[index] <= "9") index += 1;
25
+ if (rest[index] !== ";") return null;
26
+ index += 1;
27
+ while (index < rest.length && rest[index] >= "0" && rest[index] <= "9") index += 1;
28
+ if (rest[index] !== "H") return null;
29
+ return index + 1;
30
+ }
31
+ function consumeAnsiSequence(text, index) {
32
+ if (text[index] !== ESC) return null;
33
+ const rest = text.slice(index);
34
+ const clearLength = startsWithClearLine(rest);
35
+ if (clearLength !== null) return {
36
+ length: clearLength,
37
+ clearLine: true
38
+ };
39
+ const cursorLength = startsWithCursorColumn(rest);
40
+ if (cursorLength !== null) return {
41
+ length: cursorLength,
42
+ clearLine: true
43
+ };
44
+ const positionLength = startsWithCursorPosition(rest);
45
+ if (positionLength !== null) return {
46
+ length: positionLength,
47
+ clearLine: false
48
+ };
49
+ return null;
50
+ }
51
+ function holdIncompleteEscape(text) {
52
+ const escIndex = text.lastIndexOf(ESC);
53
+ if (escIndex === -1) return {
54
+ processable: text,
55
+ pending: ""
56
+ };
57
+ const tail = text.slice(escIndex);
58
+ if (tail.length === 1) return {
59
+ processable: text.slice(0, escIndex),
60
+ pending: tail
61
+ };
62
+ if (tail.startsWith(`${ESC}[`)) {
63
+ if (!(startsWithClearLine(tail) !== null || startsWithCursorColumn(tail) !== null || startsWithCursorPosition(tail) !== null)) return {
64
+ processable: text.slice(0, escIndex),
65
+ pending: tail
66
+ };
67
+ }
68
+ return {
69
+ processable: text,
70
+ pending: ""
71
+ };
72
+ }
73
+ function appendProcessable(output, text) {
74
+ let index = 0;
75
+ while (index < text.length) {
76
+ const ansi = consumeAnsiSequence(text, index);
77
+ if (ansi) {
78
+ if (ansi.clearLine) output = clearCurrentLine(output);
79
+ index += ansi.length;
80
+ continue;
81
+ }
82
+ const char = text[index];
83
+ if (char === "\r") {
84
+ output = clearCurrentLine(output);
85
+ index += 1;
86
+ continue;
87
+ }
88
+ if (char === "\b") {
89
+ output = output.slice(0, -1);
90
+ index += 1;
91
+ continue;
92
+ }
93
+ output += char;
94
+ index += 1;
95
+ }
96
+ return output;
97
+ }
98
+ /** 可跨 chunk 拼接的终端输出缓冲,避免 ANSI 转义被截断。 */
99
+ function createTerminalOutputBuffer() {
100
+ let output = "";
101
+ let pending = "";
102
+ return {
103
+ append(chunk) {
104
+ const { processable, pending: nextPending } = holdIncompleteEscape(pending + chunk);
105
+ pending = nextPending;
106
+ output = appendProcessable(output, processable);
107
+ return output;
108
+ },
109
+ get value() {
110
+ return output;
111
+ }
112
+ };
113
+ }
114
+ //#endregion
115
+ //#region src/tui/pack/build-jobs.ts
116
+ function createBuildJobsContext() {
117
+ const kills = [];
118
+ let aborted = false;
119
+ return {
120
+ registerKill: (kill) => kills.push(kill),
121
+ isAborted: () => aborted,
122
+ abort: () => {
123
+ aborted = true;
124
+ for (const kill of kills) kill();
125
+ }
126
+ };
127
+ }
128
+ function createBuildJobs(specs) {
129
+ return specs.map((spec) => reactive({
130
+ ...spec,
131
+ status: "waiting",
132
+ output: "",
133
+ exitCode: null
134
+ }));
135
+ }
136
+ async function runOneBuildJob(job, ctx) {
137
+ if (ctx.isAborted()) {
138
+ job.status = "failed";
139
+ job.exitCode = 1;
140
+ return;
141
+ }
142
+ job.status = "running";
143
+ const outputBuffer = createTerminalOutputBuffer();
144
+ const appendOutput = (chunk) => {
145
+ job.output = outputBuffer.append(chunk);
146
+ };
147
+ const handle = runCommandCaptured("npm", ["run", "build"], {
148
+ cwd: job.cwd,
149
+ env: job.env,
150
+ windowsCmd: true,
151
+ fakeTty: true,
152
+ onStdout: appendOutput,
153
+ onStderr: appendOutput
154
+ });
155
+ ctx.registerKill(() => handle.kill());
156
+ const { exitCode } = await handle.promise;
157
+ if (ctx.isAborted()) {
158
+ job.exitCode = exitCode ?? 1;
159
+ job.status = "failed";
160
+ return;
161
+ }
162
+ job.exitCode = exitCode;
163
+ job.status = exitCode === 0 ? "success" : "failed";
164
+ }
165
+ async function runWithConcurrency(items, concurrency, worker) {
166
+ if (items.length === 0) return;
167
+ const limit = Number.isFinite(concurrency) && concurrency > 0 ? Math.min(concurrency, items.length) : items.length;
168
+ let nextIndex = 0;
169
+ async function runWorker() {
170
+ while (true) {
171
+ const index = nextIndex;
172
+ nextIndex += 1;
173
+ if (index >= items.length) return;
174
+ await worker(items[index], index);
175
+ }
176
+ }
177
+ await Promise.all(Array.from({ length: limit }, () => runWorker()));
178
+ }
179
+ async function runBuildJobs(jobs, ctx, options = {}) {
180
+ await runWithConcurrency(jobs, options.concurrency ?? 0, async (job) => {
181
+ await runOneBuildJob(job, ctx);
182
+ });
183
+ return jobs;
184
+ }
185
+ function summarizeBuildFailures(jobs) {
186
+ const failed = jobs.filter((job) => job.exitCode !== 0);
187
+ if (failed.length === 0) return "";
188
+ return `[pack] 构建失败:\n${failed.map((job) => `${job.label} (退出码 ${job.exitCode ?? "?"})`).map((line) => ` - ${line}`).join("\n")}`;
189
+ }
190
+ //#endregion
191
+ export { createBuildJobs, createBuildJobsContext, runBuildJobs, runWithConcurrency, summarizeBuildFailures };