@kubb/studio 5.11.4 → 5.11.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/dist/index.cjs +112 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -4
- package/dist/index.d.ts +36 -4
- package/dist/index.js +112 -46
- package/dist/index.js.map +1 -1
- package/dist/{protocol-a_DcTFba.d.ts → protocol-dCzUP4dH.d.cts} +62 -34
- package/dist/{protocol-a_DcTFba.d.cts → protocol-dCzUP4dH.d.ts} +62 -34
- package/dist/protocol.cjs +1 -0
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.d.cts +2 -2
- package/dist/protocol.d.ts +2 -2
- package/dist/protocol.js +1 -0
- package/dist/protocol.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -220,7 +220,7 @@ function getElapsedMs(hrStart) {
|
|
|
220
220
|
}
|
|
221
221
|
//#endregion
|
|
222
222
|
//#region package.json
|
|
223
|
-
var version = "5.11.
|
|
223
|
+
var version = "5.11.6";
|
|
224
224
|
//#endregion
|
|
225
225
|
//#region src/resolveConfig.ts
|
|
226
226
|
/**
|
|
@@ -1082,13 +1082,17 @@ function applySet(source, call, path, value, quote) {
|
|
|
1082
1082
|
}
|
|
1083
1083
|
return { source: splice(source, rangeOf(target.value).start, rangeOf(target.value).end, printValue(value, quote)) };
|
|
1084
1084
|
}
|
|
1085
|
-
/**
|
|
1085
|
+
/**
|
|
1086
|
+
* Deletes the option at `path`, falling the plugin back to its default for it. An option the file
|
|
1087
|
+
* does not set already has its default, so removing it changes nothing.
|
|
1088
|
+
*/
|
|
1086
1089
|
function applyRemove(source, call, path) {
|
|
1087
1090
|
const options = call.arguments[0];
|
|
1088
|
-
if (options
|
|
1091
|
+
if (!options) return { source };
|
|
1092
|
+
if (options.type !== "ObjectExpression") return { reason: "the factory was not called with an object literal" };
|
|
1089
1093
|
const target = walk(options, path);
|
|
1090
1094
|
if ("reason" in target) return target;
|
|
1091
|
-
if ("missing" in target) return {
|
|
1095
|
+
if ("missing" in target) return { source };
|
|
1092
1096
|
return { source: removeMember(source, target.object, target.index) };
|
|
1093
1097
|
}
|
|
1094
1098
|
/**
|
|
@@ -1128,6 +1132,22 @@ function applyAddPlugin({ source, parsed, config, edit, quote, extensions }) {
|
|
|
1128
1132
|
const next = insertItem(source, plugins, `${importName}(${Object.keys(options).length ? printValue(options, quote) : ""})`);
|
|
1129
1133
|
return { source: taken ? next : insertImport(next, parsed, importName, edit.plugin) };
|
|
1130
1134
|
}
|
|
1135
|
+
/**
|
|
1136
|
+
* Rewrites the config's `plugins` array with one item per line, so a call can be commented out without
|
|
1137
|
+
* taking its neighbors with it. Not done when a comment sits between the items, which would have to move.
|
|
1138
|
+
*/
|
|
1139
|
+
function expandPluginsArray(source, config) {
|
|
1140
|
+
const array = property(config, "plugins");
|
|
1141
|
+
if (array?.type !== "ArrayExpression") return void 0;
|
|
1142
|
+
const items = array.elements.flatMap((element) => element ? [element] : []);
|
|
1143
|
+
const { start, end } = rangeOf(array);
|
|
1144
|
+
const ranges = items.map(rangeOf);
|
|
1145
|
+
const gaps = [source.slice(start + 1, ranges[0]?.start ?? end - 1), ...ranges.map((range, index) => source.slice(range.end, ranges[index + 1]?.start ?? end - 1))];
|
|
1146
|
+
if (!items.length || gaps.some((gap) => !/^[\s,]*$/.test(gap))) return void 0;
|
|
1147
|
+
const lineStart = source.lastIndexOf("\n", start - 1) + 1;
|
|
1148
|
+
const indent = source.slice(lineStart).match(/^[ \t]*/)?.[0] ?? "";
|
|
1149
|
+
return splice(source, start, end, `[\n${ranges.map((range) => `${indent} ${source.slice(range.start, range.end)},`).join("\n")}\n${indent}]`);
|
|
1150
|
+
}
|
|
1131
1151
|
/** Comments out a plugin call in place, keeping its options on disk so `enable-plugin` can restore them exactly. */
|
|
1132
1152
|
function disablePlugin(source, mod, config, plugin) {
|
|
1133
1153
|
const loc = factoryCalls(mod, config).find((entry) => entry.packageName === plugin)?.call.loc;
|
|
@@ -1155,9 +1175,17 @@ function applyEdit({ source, edit, quote, extensions }) {
|
|
|
1155
1175
|
const parsed = parseConfigs(source);
|
|
1156
1176
|
if ("reason" in parsed) return parsed;
|
|
1157
1177
|
const ref = edit.config;
|
|
1158
|
-
const
|
|
1178
|
+
const findConfig = (entries) => typeof ref === "string" ? entries.configs.find((entry) => configName(entry) === ref) : entries.configs[ref ?? 0];
|
|
1179
|
+
const config = findConfig(parsed);
|
|
1159
1180
|
if (!config) return { reason: `no config entry found for ${JSON.stringify(ref)}` };
|
|
1160
|
-
if (edit.operation === "disable-plugin")
|
|
1181
|
+
if (edit.operation === "disable-plugin") {
|
|
1182
|
+
const result = disablePlugin(source, parsed.mod, config, edit.plugin);
|
|
1183
|
+
if (!("reason" in result) || !result.reason.includes("shares a line")) return result;
|
|
1184
|
+
const expanded = expandPluginsArray(source, config);
|
|
1185
|
+
const reparsed = expanded === void 0 ? void 0 : parseConfigs(expanded);
|
|
1186
|
+
const reparsedConfig = reparsed && !("reason" in reparsed) ? findConfig(reparsed) : void 0;
|
|
1187
|
+
return expanded !== void 0 && reparsed && !("reason" in reparsed) && reparsedConfig ? disablePlugin(expanded, reparsed.mod, reparsedConfig, edit.plugin) : result;
|
|
1188
|
+
}
|
|
1161
1189
|
if (edit.operation === "enable-plugin") return enablePlugin(source, config, edit.plugin);
|
|
1162
1190
|
if (edit.operation === "add-plugin") return applyAddPlugin({
|
|
1163
1191
|
source,
|
|
@@ -1979,7 +2007,7 @@ var Agent = class extends capnweb.RpcTarget {
|
|
|
1979
2007
|
});
|
|
1980
2008
|
return this.#store;
|
|
1981
2009
|
}
|
|
1982
|
-
async
|
|
2010
|
+
async clear() {
|
|
1983
2011
|
if (this.#sandbox) await (0, node_fs_promises.rm)((0, _kubb_core.resolveCacheDir)(this.#sandboxCacheRoot), {
|
|
1984
2012
|
recursive: true,
|
|
1985
2013
|
force: true
|
|
@@ -2009,10 +2037,12 @@ var Agent = class extends capnweb.RpcTarget {
|
|
|
2009
2037
|
message: "Studio must call connect() before any other command"
|
|
2010
2038
|
});
|
|
2011
2039
|
}
|
|
2012
|
-
#logCommand(command, info) {
|
|
2040
|
+
#logCommand(command, info, requestedBy, failed) {
|
|
2013
2041
|
return emit(this.#options.hooks, "studio:command", {
|
|
2014
2042
|
command,
|
|
2015
|
-
info
|
|
2043
|
+
info,
|
|
2044
|
+
requestedBy,
|
|
2045
|
+
failed
|
|
2016
2046
|
});
|
|
2017
2047
|
}
|
|
2018
2048
|
async #readConfigFileView(source) {
|
|
@@ -2039,19 +2069,25 @@ var Agent = class extends capnweb.RpcTarget {
|
|
|
2039
2069
|
}
|
|
2040
2070
|
async connect(info) {
|
|
2041
2071
|
this.#session.info = info;
|
|
2042
|
-
const { configPath, root, version: version$1,
|
|
2072
|
+
const { configPath, root, version: version$1, loadConfigs, configFile } = this.#options;
|
|
2043
2073
|
const source = read(configFile);
|
|
2044
|
-
const [
|
|
2045
|
-
|
|
2074
|
+
const [configs, file, extensions] = await Promise.all([
|
|
2075
|
+
loadConfigs(),
|
|
2046
2076
|
this.#readConfigFileView(source),
|
|
2047
2077
|
this.#installedExtensions(source)
|
|
2048
2078
|
]);
|
|
2049
|
-
const
|
|
2050
|
-
|
|
2051
|
-
|
|
2079
|
+
const entries = [];
|
|
2080
|
+
for (const config of configs) {
|
|
2081
|
+
const disk = await this.#readDiskOutput(config).catch(async (error) => {
|
|
2082
|
+
await this.#warn({ message: `Could not read the output directory: ${getErrorMessage(error)}` });
|
|
2083
|
+
});
|
|
2084
|
+
entries.push({
|
|
2085
|
+
...toEntryView(config, extensions),
|
|
2086
|
+
...disk && { disk }
|
|
2087
|
+
});
|
|
2088
|
+
}
|
|
2052
2089
|
this.#session.connected.resolve(info);
|
|
2053
2090
|
return {
|
|
2054
|
-
output,
|
|
2055
2091
|
versions: {
|
|
2056
2092
|
kubb: version,
|
|
2057
2093
|
agent: version$1
|
|
@@ -2060,30 +2096,8 @@ var Agent = class extends capnweb.RpcTarget {
|
|
|
2060
2096
|
config: {
|
|
2061
2097
|
path: configPath,
|
|
2062
2098
|
file,
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
name: (0, _kubb_core.resolveMeta)(plugin).name,
|
|
2066
|
-
extensions
|
|
2067
|
-
}),
|
|
2068
|
-
options: toJSONOptions(plugin.options)
|
|
2069
|
-
})),
|
|
2070
|
-
adapter: config.adapter && {
|
|
2071
|
-
name: toStudioName({
|
|
2072
|
-
name: (0, _kubb_core.resolveMeta)(config.adapter).name,
|
|
2073
|
-
extensions,
|
|
2074
|
-
kind: "adapter"
|
|
2075
|
-
}),
|
|
2076
|
-
options: toJSONOptions(config.adapter.options)
|
|
2077
|
-
},
|
|
2078
|
-
parsers: config.parsers.map((parser) => ({
|
|
2079
|
-
name: toStudioName({
|
|
2080
|
-
name: (0, _kubb_core.resolveMeta)(parser).name,
|
|
2081
|
-
extensions,
|
|
2082
|
-
kind: "parser"
|
|
2083
|
-
}),
|
|
2084
|
-
options: toJSONOptions(parser.options)
|
|
2085
|
-
})),
|
|
2086
|
-
extensions: [...extensions.values()]
|
|
2099
|
+
extensions: [...extensions.values()],
|
|
2100
|
+
configs: entries
|
|
2087
2101
|
},
|
|
2088
2102
|
permissions: this.#permissions
|
|
2089
2103
|
};
|
|
@@ -2171,7 +2185,9 @@ var Agent = class extends capnweb.RpcTarget {
|
|
|
2171
2185
|
const { jobId, config: patch } = input;
|
|
2172
2186
|
const studioInput = this.#sandbox ? patch?.input : void 0;
|
|
2173
2187
|
if (this.#sandbox && (typeof studioInput !== "string" || !studioInput.trim() || (0, _kubb_core.getInputKind)(studioInput) !== "inline")) return this.#refuse({ message: require_protocol.AgentMessage.SANDBOX_INPUT_ONLY });
|
|
2174
|
-
const [
|
|
2188
|
+
const [configs, extensions] = await Promise.all([this.#options.loadConfigs(), this.#installedExtensions()]);
|
|
2189
|
+
const config = pickConfig(configs, patch?.config);
|
|
2190
|
+
if (!config) return this.#refuse({ message: require_protocol.AgentMessage.CONFIG_ENTRY_NOT_FOUND });
|
|
2175
2191
|
const [plugins, adapter, parsers] = await Promise.all([
|
|
2176
2192
|
mergePlugins({
|
|
2177
2193
|
diskPlugins: config.plugins,
|
|
@@ -2216,6 +2232,7 @@ var Agent = class extends capnweb.RpcTarget {
|
|
|
2216
2232
|
allowExec: this.#permissions.allowWrite && this.#permissions.allowExec
|
|
2217
2233
|
}).catch(async (error) => {
|
|
2218
2234
|
await this.#generations.drop(jobId);
|
|
2235
|
+
await this.#logCommand("generate", getErrorMessage(error), input.requestedBy, true);
|
|
2219
2236
|
throw error;
|
|
2220
2237
|
});
|
|
2221
2238
|
const output = await this.#generations.keep({
|
|
@@ -2234,7 +2251,7 @@ var Agent = class extends capnweb.RpcTarget {
|
|
|
2234
2251
|
output,
|
|
2235
2252
|
inputBytes
|
|
2236
2253
|
});
|
|
2237
|
-
await this.#logCommand("generate", `${activePlugins.length} plugin${activePlugins.length === 1 ? "" : "s"}, ${this.#permissions.allowWrite ? "written to disk" : "staged on disk"}${studioInput !== void 0 ? ", from a Studio spec" : ""}
|
|
2254
|
+
await this.#logCommand("generate", `${activePlugins.length} plugin${activePlugins.length === 1 ? "" : "s"}, ${this.#permissions.allowWrite ? "written to disk" : "staged on disk"}${studioInput !== void 0 ? ", from a Studio spec" : ""}`, input.requestedBy);
|
|
2238
2255
|
return {
|
|
2239
2256
|
status: "success",
|
|
2240
2257
|
files: [...files.paths],
|
|
@@ -2273,7 +2290,7 @@ var Agent = class extends capnweb.RpcTarget {
|
|
|
2273
2290
|
extensions: await this.#installedExtensions()
|
|
2274
2291
|
});
|
|
2275
2292
|
const applied = outcomes.filter((outcome) => outcome.applied).length;
|
|
2276
|
-
await this.#logCommand("saveConfig", `applied ${applied}/${outcomes.length} edits to ${configPath}
|
|
2293
|
+
await this.#logCommand("saveConfig", `applied ${applied}/${outcomes.length} edits to ${configPath}`, input.requestedBy);
|
|
2277
2294
|
return {
|
|
2278
2295
|
outcomes,
|
|
2279
2296
|
changed
|
|
@@ -2465,7 +2482,7 @@ async function runSession({ options, openRpc, url, instanceId }) {
|
|
|
2465
2482
|
await emit(hooks, "studio:warn", { message: "Canceled the running generation: the connection to Kubb Studio closed" });
|
|
2466
2483
|
}
|
|
2467
2484
|
await active?.settled;
|
|
2468
|
-
await agent
|
|
2485
|
+
await agent.clear();
|
|
2469
2486
|
return {
|
|
2470
2487
|
...close,
|
|
2471
2488
|
connected: session.info !== void 0
|
|
@@ -2474,6 +2491,55 @@ async function runSession({ options, openRpc, url, instanceId }) {
|
|
|
2474
2491
|
/**
|
|
2475
2492
|
* The connection loop with a swappable transport. {@link connectAgent} passes a real WebSocket.
|
|
2476
2493
|
*/
|
|
2494
|
+
/** The entry Studio named by position or `name`, else the first. `undefined` for one the file does not have. */
|
|
2495
|
+
function pickConfig(configs, ref) {
|
|
2496
|
+
if (typeof ref === "string") return configs.find((config) => config.name === ref);
|
|
2497
|
+
if (ref !== void 0 && !Number.isSafeInteger(ref)) return void 0;
|
|
2498
|
+
return configs[ref ?? 0];
|
|
2499
|
+
}
|
|
2500
|
+
/** The input path or URL Studio may show: no inline document, and no credentials from a URL. */
|
|
2501
|
+
function reportedInput(input) {
|
|
2502
|
+
if (typeof input !== "string") return void 0;
|
|
2503
|
+
const kind = (0, _kubb_core.getInputKind)(input);
|
|
2504
|
+
if (kind === "inline") return void 0;
|
|
2505
|
+
if (kind !== "url") return input;
|
|
2506
|
+
const url = new URL(input);
|
|
2507
|
+
url.username = "";
|
|
2508
|
+
url.password = "";
|
|
2509
|
+
return url.href;
|
|
2510
|
+
}
|
|
2511
|
+
/** A JSON copy of one resolved entry, each extension named by the package its manifest is in. */
|
|
2512
|
+
function toEntryView(config, extensions) {
|
|
2513
|
+
const input = reportedInput(config.input);
|
|
2514
|
+
return {
|
|
2515
|
+
...config.name !== void 0 && { name: config.name },
|
|
2516
|
+
...input !== void 0 && { input },
|
|
2517
|
+
output: config.output.path,
|
|
2518
|
+
plugins: config.plugins.map((plugin) => ({
|
|
2519
|
+
name: toStudioName({
|
|
2520
|
+
name: (0, _kubb_core.resolveMeta)(plugin).name,
|
|
2521
|
+
extensions
|
|
2522
|
+
}),
|
|
2523
|
+
options: toJSONOptions(plugin.options)
|
|
2524
|
+
})),
|
|
2525
|
+
adapter: config.adapter && {
|
|
2526
|
+
name: toStudioName({
|
|
2527
|
+
name: (0, _kubb_core.resolveMeta)(config.adapter).name,
|
|
2528
|
+
extensions,
|
|
2529
|
+
kind: "adapter"
|
|
2530
|
+
}),
|
|
2531
|
+
options: toJSONOptions(config.adapter.options)
|
|
2532
|
+
},
|
|
2533
|
+
parsers: config.parsers.map((parser) => ({
|
|
2534
|
+
name: toStudioName({
|
|
2535
|
+
name: (0, _kubb_core.resolveMeta)(parser).name,
|
|
2536
|
+
extensions,
|
|
2537
|
+
kind: "parser"
|
|
2538
|
+
}),
|
|
2539
|
+
options: toJSONOptions(parser.options)
|
|
2540
|
+
}))
|
|
2541
|
+
};
|
|
2542
|
+
}
|
|
2477
2543
|
async function runAgent({ options, openRpc }) {
|
|
2478
2544
|
const root = options.root ?? node_process.default.cwd();
|
|
2479
2545
|
const resolved = {
|
|
@@ -2535,7 +2601,7 @@ async function runAgent({ options, openRpc }) {
|
|
|
2535
2601
|
* const hooks = new Hookable<KubbHooks>()
|
|
2536
2602
|
* hooks.hook('studio:connected', ({ agentSlug }) => console.log(`Connected as ${agentSlug}`))
|
|
2537
2603
|
*
|
|
2538
|
-
* await connectAgent({ token, configPath: 'kubb.config.ts',
|
|
2604
|
+
* await connectAgent({ token, configPath: 'kubb.config.ts', loadConfigs, version: '1.0.0', hooks, signal })
|
|
2539
2605
|
* ```
|
|
2540
2606
|
*/
|
|
2541
2607
|
function connectAgent(options) {
|
|
@@ -2933,6 +2999,7 @@ exports.InvalidAgentTokenError = InvalidAgentTokenError;
|
|
|
2933
2999
|
exports.PairingCanceledError = PairingCanceledError;
|
|
2934
3000
|
exports.PairingDeniedError = PairingDeniedError;
|
|
2935
3001
|
exports.PairingExpiredError = PairingExpiredError;
|
|
3002
|
+
exports.applyConfigEdits = applyConfigEdits;
|
|
2936
3003
|
exports.connectAgent = connectAgent;
|
|
2937
3004
|
exports.createSnapshot = createSnapshot;
|
|
2938
3005
|
exports.defaultStudioUrl = defaultStudioUrl;
|