@kubb/studio 5.10.2 → 5.10.4
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/dist/index.cjs +158 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +260 -0
- package/dist/index.d.ts +1 -2
- package/dist/index.js +159 -32
- package/dist/index.js.map +1 -1
- package/dist/protocol-CrMJymjT.d.cts +778 -0
- package/dist/{protocol-DQfI1aLV.d.ts → protocol-CrMJymjT.d.ts} +23 -4
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.d.cts +2 -0
- package/dist/protocol.d.ts +2 -2
- package/dist/protocol.js.map +1 -1
- package/package.json +28 -11
- package/dist/rolldown-runtime-CRm0XQPb.js +0 -9
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { D as InstalledExtensions, P as PublishedSnapshot, W as SnapshotUploadMetadata, a as AgentConnectInfo, c as AgentPermissions, d as ConfigEditOutcome, s as AgentPermission, u as ConfigEdit } from "./protocol-CrMJymjT.cjs";
|
|
2
|
+
import { Config, Hookable, KubbHooks } from "@kubb/core";
|
|
3
|
+
//#region src/connect.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Studio closed with {@link AgentCloseCode.UNAUTHORIZED}. Hosts forget the token and pair again.
|
|
6
|
+
*/
|
|
7
|
+
export declare class InvalidAgentTokenError extends Error {
|
|
8
|
+
constructor(studioUrl: string);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Studio closed with {@link AgentCloseCode.INCOMPATIBLE}. Only an upgrade helps.
|
|
12
|
+
*/
|
|
13
|
+
export declare class IncompatibleAgentError extends Error {
|
|
14
|
+
constructor({ studioUrl, detail }: {
|
|
15
|
+
studioUrl: string;
|
|
16
|
+
detail?: string;
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
type StudioConnectedContext = AgentConnectInfo & {
|
|
20
|
+
url: string;
|
|
21
|
+
/**
|
|
22
|
+
* The Studio, runtime, and host versions, so a host can show a mismatch.
|
|
23
|
+
*/
|
|
24
|
+
versions: {
|
|
25
|
+
studio: string;
|
|
26
|
+
kubb: string;
|
|
27
|
+
agent: string;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
declare global {
|
|
31
|
+
namespace Kubb {
|
|
32
|
+
interface KubbHooksRegistry {
|
|
33
|
+
/**
|
|
34
|
+
* Fired after each handshake, including reconnects.
|
|
35
|
+
*/
|
|
36
|
+
'studio:connected': [ctx: StudioConnectedContext];
|
|
37
|
+
'studio:disconnected': [ctx: {
|
|
38
|
+
code: number;
|
|
39
|
+
reason: string;
|
|
40
|
+
}];
|
|
41
|
+
'studio:reconnecting': [ctx: {
|
|
42
|
+
delayMs: number;
|
|
43
|
+
}];
|
|
44
|
+
/**
|
|
45
|
+
* A finished command and what it did, such as `applied 2/3 edits to kubb.config.ts`.
|
|
46
|
+
*/
|
|
47
|
+
'studio:command': [ctx: {
|
|
48
|
+
command: 'generate' | 'saveConfig' | 'readFiles' | 'readInput' | 'readDiff';
|
|
49
|
+
info: string;
|
|
50
|
+
}];
|
|
51
|
+
/**
|
|
52
|
+
* A refused or ignored request, with the missing permission so the host can add a remedy.
|
|
53
|
+
*/
|
|
54
|
+
'studio:warn': [ctx: {
|
|
55
|
+
message: string;
|
|
56
|
+
permission?: AgentPermission;
|
|
57
|
+
}];
|
|
58
|
+
'studio:error': [ctx: {
|
|
59
|
+
error: Error;
|
|
60
|
+
}];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
type ConnectAgentOptions = {
|
|
65
|
+
/**
|
|
66
|
+
* The agent's bearer token, from {@link pairAgent}.
|
|
67
|
+
*/
|
|
68
|
+
token: string;
|
|
69
|
+
studioUrl?: string;
|
|
70
|
+
/**
|
|
71
|
+
* The config path shown in Studio, relative to `root` unless absolute.
|
|
72
|
+
*/
|
|
73
|
+
configPath: string;
|
|
74
|
+
/**
|
|
75
|
+
* Called for every handshake and every generation, so edits on disk show up.
|
|
76
|
+
*/
|
|
77
|
+
loadConfig: () => Promise<Config>;
|
|
78
|
+
/**
|
|
79
|
+
* The host's own version, reported to Studio next to the runtime's.
|
|
80
|
+
*/
|
|
81
|
+
version: string;
|
|
82
|
+
/**
|
|
83
|
+
* The project root generation runs against.
|
|
84
|
+
* @default process.cwd()
|
|
85
|
+
*/
|
|
86
|
+
root?: string;
|
|
87
|
+
/**
|
|
88
|
+
* What Studio may do in this project. Every permission is off unless granted.
|
|
89
|
+
*/
|
|
90
|
+
permissions?: Partial<AgentPermissions>;
|
|
91
|
+
/**
|
|
92
|
+
* Receives the `studio:*` hooks and the `kubb:*` hooks of every generation.
|
|
93
|
+
*/
|
|
94
|
+
hooks?: Hookable<KubbHooks>;
|
|
95
|
+
signal?: AbortSignal;
|
|
96
|
+
/**
|
|
97
|
+
* Longest wait between reconnect attempts, in milliseconds.
|
|
98
|
+
* @default 30000
|
|
99
|
+
*/
|
|
100
|
+
maxRetryDelay?: number;
|
|
101
|
+
/**
|
|
102
|
+
* Milliseconds between keep-alive pings, at most 60000.
|
|
103
|
+
* @default 30000
|
|
104
|
+
*/
|
|
105
|
+
heartbeatInterval?: number;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Connects this project to Kubb Studio and serves its commands until `signal` aborts. Reconnects
|
|
109
|
+
* with jittered backoff, and resolves when another process of the agent takes over. Rejects with
|
|
110
|
+
* {@link InvalidAgentTokenError} so the host can pair again, or {@link IncompatibleAgentError}.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```ts
|
|
114
|
+
* const hooks = new Hookable<KubbHooks>()
|
|
115
|
+
* hooks.hook('studio:connected', ({ agentSlug }) => console.log(`Connected as ${agentSlug}`))
|
|
116
|
+
*
|
|
117
|
+
* await connectAgent({ token, configPath: 'kubb.config.ts', loadConfig, version: '1.0.0', hooks, signal })
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
export declare function connectAgent(options: ConnectAgentOptions): Promise<void>;
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region src/pair.d.ts
|
|
123
|
+
/**
|
|
124
|
+
* RFC 8628 device-authorization response from Studio's `/api/auth/device/code` endpoint.
|
|
125
|
+
* Field names match the RFC; the CLI polls with `device_code` and shows `user_code` to the user.
|
|
126
|
+
*/
|
|
127
|
+
type PairingSession = {
|
|
128
|
+
device_code: string;
|
|
129
|
+
user_code: string;
|
|
130
|
+
verification_uri: string;
|
|
131
|
+
verification_uri_complete: string;
|
|
132
|
+
expires_in: number;
|
|
133
|
+
interval: number;
|
|
134
|
+
};
|
|
135
|
+
type PairingResult = {
|
|
136
|
+
/**
|
|
137
|
+
* Bearer token for this machine. Write credentials with mode 0600 and never log the value.
|
|
138
|
+
*/
|
|
139
|
+
token: string;
|
|
140
|
+
agent: {
|
|
141
|
+
/**
|
|
142
|
+
* Stable agent id in Studio.
|
|
143
|
+
*/
|
|
144
|
+
id: string;
|
|
145
|
+
/**
|
|
146
|
+
* Short slug used in logs and the UI (for example `brave-otter`).
|
|
147
|
+
*/
|
|
148
|
+
slug: string;
|
|
149
|
+
/**
|
|
150
|
+
* Display name chosen at pairing time.
|
|
151
|
+
*/
|
|
152
|
+
name: string;
|
|
153
|
+
/**
|
|
154
|
+
* This agent's organization slug, absent for a sandbox or global agent, which has none.
|
|
155
|
+
*/
|
|
156
|
+
organizationSlug?: string;
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* What this machine registers as. Any member may approve `cli` (`kubb studio`); only an admin may
|
|
161
|
+
* approve `user` and `sandbox` (the Docker image). A `ci` agent never pairs.
|
|
162
|
+
*/
|
|
163
|
+
type PairingAgentType = 'cli' | 'user' | 'sandbox';
|
|
164
|
+
/**
|
|
165
|
+
* Thrown when a caller aborts `startPairing` or `pollForPairingToken` through their `signal`, such
|
|
166
|
+
* as a `kubb studio` shutdown mid-pairing. Distinct from a denial or an expired code, so a host can
|
|
167
|
+
* exit quietly instead of reporting a pairing failure.
|
|
168
|
+
*/
|
|
169
|
+
export declare class PairingCanceledError extends Error {
|
|
170
|
+
constructor();
|
|
171
|
+
}
|
|
172
|
+
/** Thrown when the code expired unapproved. A fresh code can still succeed. */
|
|
173
|
+
export declare class PairingExpiredError extends Error {
|
|
174
|
+
constructor(message?: string);
|
|
175
|
+
}
|
|
176
|
+
/** Thrown when the pairing was denied in the browser, including by the organization's agent limit. */
|
|
177
|
+
export declare class PairingDeniedError extends Error {
|
|
178
|
+
constructor(message?: string);
|
|
179
|
+
}
|
|
180
|
+
type StartPairingOptions = {
|
|
181
|
+
studioUrl?: string;
|
|
182
|
+
type: PairingAgentType;
|
|
183
|
+
/**
|
|
184
|
+
* Display name for the agent, usually the project or machine name.
|
|
185
|
+
*/
|
|
186
|
+
name: string;
|
|
187
|
+
hostname: string;
|
|
188
|
+
/**
|
|
189
|
+
* A stable secret the host keeps for this machine. Studio stores its hash against the agent, so
|
|
190
|
+
* the same machine pairing again rotates one agent's token instead of creating a second agent.
|
|
191
|
+
*/
|
|
192
|
+
machineId: string;
|
|
193
|
+
/**
|
|
194
|
+
* Aborting this cancels the request in flight and rejects with {@link PairingCanceledError}.
|
|
195
|
+
*/
|
|
196
|
+
signal?: AbortSignal;
|
|
197
|
+
};
|
|
198
|
+
type PairAgentOptions = StartPairingOptions & {
|
|
199
|
+
/** Shows the code to whoever approves it. Called again for each fresh code. */
|
|
200
|
+
onCode: (session: PairingSession, attempt: number) => void | Promise<void>;
|
|
201
|
+
/** Called when a poll could not reach Studio. Polling carries on. */
|
|
202
|
+
onRetry?: (error: Error) => void;
|
|
203
|
+
/**
|
|
204
|
+
* Codes to ask for in total when one expires unapproved. A denial or abort ends it at once.
|
|
205
|
+
* @default 1
|
|
206
|
+
*/
|
|
207
|
+
maxAttempts?: number;
|
|
208
|
+
};
|
|
209
|
+
/**
|
|
210
|
+
* Pairs this machine with Studio: asks for a code, hands it to the host to show, and waits for approval.
|
|
211
|
+
*/
|
|
212
|
+
export declare function pairAgent({ onCode, onRetry, maxAttempts, ...options }: PairAgentOptions): Promise<PairingResult>;
|
|
213
|
+
//#endregion
|
|
214
|
+
//#region src/snapshot.d.ts
|
|
215
|
+
type CreateSnapshotOptions = Omit<SnapshotUploadMetadata, 'hashes' | 'peerDependencies'> & {
|
|
216
|
+
studioUrl?: string;
|
|
217
|
+
/**
|
|
218
|
+
* Organization CI API key, sent as `x-api-key`.
|
|
219
|
+
*/
|
|
220
|
+
apiKey: string;
|
|
221
|
+
/**
|
|
222
|
+
* The project's Kubb config, generated like `kubb generate`: formatter, linter, and `output.postGenerate` included.
|
|
223
|
+
*/
|
|
224
|
+
config: Config;
|
|
225
|
+
hooks?: Hookable<KubbHooks>;
|
|
226
|
+
signal?: AbortSignal;
|
|
227
|
+
};
|
|
228
|
+
/**
|
|
229
|
+
* Generates the project, packs it as an npm tarball, and publishes it to Studio in one `POST /api/snapshots` request.
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* ```ts
|
|
233
|
+
* const { url } = await createSnapshot({ apiKey: process.env.KUBB_TOKEN!, config, id: 'gh:123:pr-4', name: 'acme/api#4', packageName: '@acme/api', version: '1.0.0' })
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
export declare function createSnapshot({ studioUrl, apiKey, config, hooks, signal, ...metadata }: CreateSnapshotOptions): Promise<PublishedSnapshot>;
|
|
237
|
+
//#endregion
|
|
238
|
+
//#region src/url.d.ts
|
|
239
|
+
/**
|
|
240
|
+
* Hosted Kubb Studio URL, used when a host passes none.
|
|
241
|
+
*/
|
|
242
|
+
export declare const defaultStudioUrl = "https://kubb.studio";
|
|
243
|
+
//#endregion
|
|
244
|
+
//#region src/configFile.d.ts
|
|
245
|
+
/**
|
|
246
|
+
* Applies `edits` to the config file at `filePath`, writing it only when something changed.
|
|
247
|
+
* `add-plugin` accepts `@kubb/plugin-*` packages and the plugins in `extensions`.
|
|
248
|
+
*/
|
|
249
|
+
export declare function writeConfigEdits({ filePath, edits, extensions }: {
|
|
250
|
+
filePath: string;
|
|
251
|
+
edits: Array<ConfigEdit>;
|
|
252
|
+
extensions?: InstalledExtensions;
|
|
253
|
+
}): Promise<{
|
|
254
|
+
source: string;
|
|
255
|
+
outcomes: Array<ConfigEditOutcome>;
|
|
256
|
+
changed: boolean;
|
|
257
|
+
}>;
|
|
258
|
+
//#endregion
|
|
259
|
+
export type { ConnectAgentOptions, StudioConnectedContext };
|
|
260
|
+
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { E as InstalledExtensions, N as PublishedSnapshot, U as SnapshotUploadMetadata, a as AgentConnectInfo, c as AgentPermissions, d as ConfigEditOutcome, s as AgentPermission, u as ConfigEdit } from "./protocol-DQfI1aLV.js";
|
|
1
|
+
import { D as InstalledExtensions, P as PublishedSnapshot, W as SnapshotUploadMetadata, a as AgentConnectInfo, c as AgentPermissions, d as ConfigEditOutcome, s as AgentPermission, u as ConfigEdit } from "./protocol-CrMJymjT.js";
|
|
3
2
|
import { Config, Hookable, KubbHooks } from "@kubb/core";
|
|
4
3
|
//#region src/connect.d.ts
|
|
5
4
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import "./rolldown-runtime-CRm0XQPb.js";
|
|
2
1
|
import { AGENT_INSTANCE_HEADER, AGENT_SOCKET_PATH, AgentCloseCode, AgentMessage, AgentPermission, FileSource, MAX_PAGE_LINES, MAX_SNAPSHOT_BYTES, generationEventTypes } from "./protocol.js";
|
|
3
2
|
import { createRequire } from "node:module";
|
|
4
3
|
import { createHash, hash, randomUUID } from "node:crypto";
|
|
@@ -17,6 +16,7 @@ import { stripVTControlCharacters } from "node:util";
|
|
|
17
16
|
import { ast } from "@kubb/ast";
|
|
18
17
|
import { ofetch } from "ofetch";
|
|
19
18
|
import { gzipSync } from "node:zlib";
|
|
19
|
+
//#endregion
|
|
20
20
|
//#region ../../internals/utils/src/casing.ts
|
|
21
21
|
/**
|
|
22
22
|
* Shared implementation for camelCase and PascalCase conversion.
|
|
@@ -154,7 +154,7 @@ function getElapsedMs(hrStart) {
|
|
|
154
154
|
}
|
|
155
155
|
//#endregion
|
|
156
156
|
//#region package.json
|
|
157
|
-
var version = "5.10.
|
|
157
|
+
var version = "5.10.4";
|
|
158
158
|
//#endregion
|
|
159
159
|
//#region src/resolveConfig.ts
|
|
160
160
|
/**
|
|
@@ -1155,33 +1155,154 @@ async function writeConfigEdits({ filePath, edits, extensions }) {
|
|
|
1155
1155
|
//#endregion
|
|
1156
1156
|
//#region src/diff.ts
|
|
1157
1157
|
const CONTEXT_LINES = 3;
|
|
1158
|
-
const DIFF_TIMEOUT_MS =
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1158
|
+
const DIFF_TIMEOUT_MS = 1e3;
|
|
1159
|
+
const splitLines = (text) => text === "" ? [] : text.split(/(?<=\n)/);
|
|
1160
|
+
function longestIncreasing(values) {
|
|
1161
|
+
const tails = [];
|
|
1162
|
+
const prev = [];
|
|
1163
|
+
for (const [index, value] of values.entries()) {
|
|
1164
|
+
let low = 0;
|
|
1165
|
+
let high = tails.length;
|
|
1166
|
+
while (low < high) {
|
|
1167
|
+
const mid = low + high >> 1;
|
|
1168
|
+
if (values[tails[mid]] < value) low = mid + 1;
|
|
1169
|
+
else high = mid;
|
|
1170
|
+
}
|
|
1171
|
+
prev[index] = low > 0 ? tails[low - 1] : -1;
|
|
1172
|
+
tails[low] = index;
|
|
1173
|
+
}
|
|
1174
|
+
const result = [];
|
|
1175
|
+
for (let index = tails.at(-1) ?? -1; index !== -1; index = prev[index]) result.push(index);
|
|
1176
|
+
return result.reverse();
|
|
1177
|
+
}
|
|
1178
|
+
function cutPoints(before, after) {
|
|
1179
|
+
const counts = /* @__PURE__ */ new Map();
|
|
1180
|
+
for (const [index, line] of before.entries()) {
|
|
1181
|
+
const count = counts.get(line);
|
|
1182
|
+
if (count) count.before++;
|
|
1183
|
+
else counts.set(line, {
|
|
1184
|
+
before: 1,
|
|
1185
|
+
after: 0,
|
|
1186
|
+
index
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
1189
|
+
const afterIndex = /* @__PURE__ */ new Map();
|
|
1190
|
+
for (const [index, line] of after.entries()) {
|
|
1191
|
+
const count = counts.get(line);
|
|
1192
|
+
if (!count) continue;
|
|
1193
|
+
count.after++;
|
|
1194
|
+
afterIndex.set(line, index);
|
|
1195
|
+
}
|
|
1196
|
+
const unique = [...counts].filter(([, count]) => count.before === 1 && count.after === 1).map(([line, count]) => [count.index, afterIndex.get(line)]);
|
|
1197
|
+
const anchors = longestIncreasing(unique.map(([, index]) => index)).map((index) => unique[index]);
|
|
1198
|
+
const cuts = [[0, 0]];
|
|
1199
|
+
let run = {
|
|
1200
|
+
before: 0,
|
|
1201
|
+
after: 0,
|
|
1202
|
+
length: 0
|
|
1203
|
+
};
|
|
1204
|
+
const closeRun = () => {
|
|
1205
|
+
if (run.length > 6) cuts.push([run.before + CONTEXT_LINES, run.after + CONTEXT_LINES]);
|
|
1206
|
+
};
|
|
1207
|
+
let i = 0;
|
|
1208
|
+
let j = 0;
|
|
1209
|
+
for (const [anchorBefore, anchorAfter] of anchors) {
|
|
1210
|
+
const unchanged = anchorBefore - i === anchorAfter - j && before.slice(i, anchorBefore).every((line, offset) => line === after[j + offset]);
|
|
1211
|
+
if (unchanged && run.length && run.before + run.length === i) run.length += anchorBefore - i + 1;
|
|
1212
|
+
else {
|
|
1213
|
+
closeRun();
|
|
1214
|
+
run = unchanged ? {
|
|
1215
|
+
before: i,
|
|
1216
|
+
after: j,
|
|
1217
|
+
length: anchorBefore - i + 1
|
|
1218
|
+
} : {
|
|
1219
|
+
before: anchorBefore,
|
|
1220
|
+
after: anchorAfter,
|
|
1221
|
+
length: 1
|
|
1222
|
+
};
|
|
1223
|
+
}
|
|
1224
|
+
i = anchorBefore + 1;
|
|
1225
|
+
j = anchorAfter + 1;
|
|
1226
|
+
}
|
|
1227
|
+
closeRun();
|
|
1228
|
+
cuts.push([before.length, after.length]);
|
|
1229
|
+
return cuts;
|
|
1230
|
+
}
|
|
1231
|
+
function replaceHunk(before, after) {
|
|
1232
|
+
let start = 0;
|
|
1233
|
+
while (start < before.length && start < after.length && before[start] === after[start]) start++;
|
|
1234
|
+
let end = 0;
|
|
1235
|
+
while (end < before.length - start && end < after.length - start && before[before.length - 1 - end] === after[after.length - 1 - end]) end++;
|
|
1236
|
+
const removed = before.slice(start, before.length - end);
|
|
1237
|
+
const added = after.slice(start, after.length - end);
|
|
1238
|
+
if (!removed.length && !added.length) return [];
|
|
1239
|
+
const lines = (prefix, rows) => rows.flatMap((row) => row.endsWith("\n") ? [`${prefix}${row.slice(0, -1)}`] : [`${prefix}${row}`, "\"]);
|
|
1240
|
+
return [{
|
|
1241
|
+
oldStart: start + 1,
|
|
1242
|
+
oldLines: removed.length,
|
|
1243
|
+
newStart: start + 1,
|
|
1244
|
+
newLines: added.length,
|
|
1245
|
+
lines: [...lines("-", removed), ...lines("+", added)]
|
|
1246
|
+
}];
|
|
1247
|
+
}
|
|
1248
|
+
function diffHunks(before, after, timeout = DIFF_TIMEOUT_MS) {
|
|
1249
|
+
const beforeLines = splitLines(before);
|
|
1250
|
+
const afterLines = splitLines(after);
|
|
1251
|
+
const cuts = cutPoints(beforeLines, afterLines);
|
|
1252
|
+
const deadline = Date.now() + timeout;
|
|
1253
|
+
const hunks = [];
|
|
1254
|
+
let coarse = false;
|
|
1255
|
+
for (const [index, [beforeStart, afterStart]] of cuts.slice(0, -1).entries()) {
|
|
1256
|
+
const [beforeEnd, afterEnd] = cuts[index + 1];
|
|
1257
|
+
const segmentBefore = beforeLines.slice(beforeStart, beforeEnd);
|
|
1258
|
+
const segmentAfter = afterLines.slice(afterStart, afterEnd);
|
|
1259
|
+
const patch = structuredPatch("", "", segmentBefore.join(""), segmentAfter.join(""), void 0, void 0, {
|
|
1162
1260
|
context: CONTEXT_LINES,
|
|
1163
|
-
timeout:
|
|
1164
|
-
callback: (patch) => resolve(patch?.hunks)
|
|
1261
|
+
timeout: Math.max(0, deadline - Date.now())
|
|
1165
1262
|
});
|
|
1166
|
-
|
|
1263
|
+
if (!patch) coarse = true;
|
|
1264
|
+
for (const hunk of patch?.hunks ?? replaceHunk(segmentBefore, segmentAfter)) hunks.push({
|
|
1265
|
+
...hunk,
|
|
1266
|
+
oldStart: hunk.oldStart + beforeStart,
|
|
1267
|
+
newStart: hunk.newStart + afterStart
|
|
1268
|
+
});
|
|
1269
|
+
}
|
|
1270
|
+
const lines = hunks.flatMap((hunk) => hunk.lines);
|
|
1271
|
+
return {
|
|
1272
|
+
hunks,
|
|
1273
|
+
stats: {
|
|
1274
|
+
additions: lines.filter((line) => line[0] === "+").length,
|
|
1275
|
+
deletions: lines.filter((line) => line[0] === "-").length,
|
|
1276
|
+
hunks: hunks.length,
|
|
1277
|
+
lines: lines.length,
|
|
1278
|
+
coarse
|
|
1279
|
+
}
|
|
1280
|
+
};
|
|
1167
1281
|
}
|
|
1168
1282
|
function pageHunks({ hunks, cursor, limit }) {
|
|
1169
1283
|
const page = [];
|
|
1170
|
-
|
|
1284
|
+
let used = 0;
|
|
1171
1285
|
let start = 0;
|
|
1172
1286
|
for (const [index, hunk] of hunks.entries()) {
|
|
1173
|
-
const
|
|
1174
|
-
|
|
1287
|
+
const offset = Math.max(0, cursor - start);
|
|
1288
|
+
start += hunk.lines.length;
|
|
1289
|
+
const remaining = hunk.lines.length - offset;
|
|
1290
|
+
if (remaining <= 0) continue;
|
|
1291
|
+
if (used > 0 && remaining > limit - used) break;
|
|
1292
|
+
let take = Math.min(remaining, limit - used);
|
|
1293
|
+
if (hunk.lines[offset + take]?.startsWith("\\")) take++;
|
|
1294
|
+
page.push({
|
|
1175
1295
|
index,
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
lines: hunk.lines.slice(Math.max(0, cursor - start), end - start)
|
|
1296
|
+
...hunk,
|
|
1297
|
+
lines: hunk.lines.slice(offset, offset + take)
|
|
1179
1298
|
});
|
|
1180
|
-
|
|
1299
|
+
used += take;
|
|
1300
|
+
if (used >= limit) break;
|
|
1181
1301
|
}
|
|
1302
|
+
const total = hunks.reduce((sum, hunk) => sum + hunk.lines.length, 0);
|
|
1182
1303
|
return {
|
|
1183
1304
|
hunks: page,
|
|
1184
|
-
nextCursor:
|
|
1305
|
+
nextCursor: cursor + used < total ? cursor + used : null
|
|
1185
1306
|
};
|
|
1186
1307
|
}
|
|
1187
1308
|
//#endregion
|
|
@@ -1417,7 +1538,7 @@ function createGenerationStore({ storage, maxCount, maxMb, ttlMs, now = Date.now
|
|
|
1417
1538
|
//#region src/generationEvents.ts
|
|
1418
1539
|
const MAX_QUEUED_EVENTS = 1024;
|
|
1419
1540
|
const RESERVED_EVENTS = 64;
|
|
1420
|
-
const isDiscardable = (
|
|
1541
|
+
const isDiscardable = (type) => type === "kubb:files:processing:update" || type === "kubb:info" || type === "kubb:success";
|
|
1421
1542
|
/** Forwards selected Kubb lifecycle events to a native Cap'n Web stream. */
|
|
1422
1543
|
function createGenerationStream(hooks, jobId) {
|
|
1423
1544
|
const unhooks = [];
|
|
@@ -1449,7 +1570,7 @@ function createGenerationStream(hooks, jobId) {
|
|
|
1449
1570
|
version: 1,
|
|
1450
1571
|
timestamp: Date.now()
|
|
1451
1572
|
};
|
|
1452
|
-
if (controller.desiredSize <= RESERVED_EVENTS && isDiscardable(
|
|
1573
|
+
if (controller.desiredSize <= RESERVED_EVENTS && isDiscardable(type)) return;
|
|
1453
1574
|
if (controller.desiredSize <= 0) {
|
|
1454
1575
|
fail(/* @__PURE__ */ new Error(`Generation event stream exceeded ${MAX_QUEUED_EVENTS} queued events`));
|
|
1455
1576
|
return;
|
|
@@ -1553,7 +1674,10 @@ function createGenerationStream(hooks, jobId) {
|
|
|
1553
1674
|
}]
|
|
1554
1675
|
};
|
|
1555
1676
|
function forward(type) {
|
|
1556
|
-
on(type, (...args) =>
|
|
1677
|
+
on(type, (...args) => {
|
|
1678
|
+
emitEvent(type, projections[type](...args));
|
|
1679
|
+
if (!isDiscardable(type)) return new Promise((resolve) => setImmediate(resolve));
|
|
1680
|
+
});
|
|
1557
1681
|
}
|
|
1558
1682
|
on("kubb:build:start", ({ config }) => {
|
|
1559
1683
|
root = config.root;
|
|
@@ -2063,7 +2187,14 @@ var Agent = class extends RpcTarget {
|
|
|
2063
2187
|
if (beforeContent === void 0) return {
|
|
2064
2188
|
hunks: [],
|
|
2065
2189
|
nextCursor: null,
|
|
2066
|
-
hasBase: false
|
|
2190
|
+
hasBase: false,
|
|
2191
|
+
stats: {
|
|
2192
|
+
additions: 0,
|
|
2193
|
+
deletions: 0,
|
|
2194
|
+
hunks: 0,
|
|
2195
|
+
lines: 0,
|
|
2196
|
+
coarse: false
|
|
2197
|
+
}
|
|
2067
2198
|
};
|
|
2068
2199
|
const key = JSON.stringify([
|
|
2069
2200
|
jobId,
|
|
@@ -2071,25 +2202,21 @@ var Agent = class extends RpcTarget {
|
|
|
2071
2202
|
baseSource,
|
|
2072
2203
|
path
|
|
2073
2204
|
]);
|
|
2074
|
-
let
|
|
2075
|
-
if (!
|
|
2076
|
-
|
|
2077
|
-
this.#diffs.set(key,
|
|
2205
|
+
let diff = this.#diffs.get(key);
|
|
2206
|
+
if (!diff) {
|
|
2207
|
+
diff = diffHunks(beforeContent, afterContent ?? "");
|
|
2208
|
+
this.#diffs.set(key, diff);
|
|
2078
2209
|
if (this.#diffs.size > 4) this.#diffs.delete(this.#diffs.keys().next().value);
|
|
2079
2210
|
}
|
|
2080
|
-
const all = await hunks;
|
|
2081
|
-
if (!all) {
|
|
2082
|
-
this.#diffs.delete(key);
|
|
2083
|
-
return this.#refuse({ message: "The two versions differ too much to diff" });
|
|
2084
|
-
}
|
|
2085
2211
|
await this.#logCommand("readDiff", `read the diff of ${path}`);
|
|
2086
2212
|
return {
|
|
2087
2213
|
...pageHunks({
|
|
2088
|
-
hunks:
|
|
2214
|
+
hunks: diff.hunks,
|
|
2089
2215
|
cursor,
|
|
2090
2216
|
limit
|
|
2091
2217
|
}),
|
|
2092
|
-
hasBase: true
|
|
2218
|
+
hasBase: true,
|
|
2219
|
+
stats: diff.stats
|
|
2093
2220
|
};
|
|
2094
2221
|
}
|
|
2095
2222
|
};
|