dsh-loop-engine-allinone 0.4.1 → 0.7.0
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/CHANGELOG.md +88 -0
- package/README.md +171 -197
- package/README.zh.md +175 -157
- package/lib/client.js +28 -0
- package/lib/index.js +251 -108
- package/lib/invariant.js +28 -0
- package/lib/types/driver-acp/client.d.ts +20 -0
- package/lib/types/engine-registry.d.ts +35 -0
- package/lib/types/model-discovery.d.ts +98 -0
- package/lib/types/model-registry.d.ts +78 -0
- package/lib/types/provider-route.d.ts +8 -4
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -89,10 +89,10 @@ var __callDispose = (stack, error, hasError) => {
|
|
|
89
89
|
};
|
|
90
90
|
|
|
91
91
|
// src/index.ts
|
|
92
|
-
import { readFileSync as
|
|
92
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
93
93
|
import { mkdir as mkdir2, readFile as readFile6, rename as rename2, writeFile as writeFile2 } from "node:fs/promises";
|
|
94
94
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
95
|
-
import { dirname as dirname7, join as
|
|
95
|
+
import { dirname as dirname7, join as join21 } from "node:path";
|
|
96
96
|
import z12 from "@deepseek-ai/schemastery";
|
|
97
97
|
import { resolveDshHome as resolveDshHome2 } from "@deepseek-ai/dsh-home-paths";
|
|
98
98
|
|
|
@@ -145,6 +145,20 @@ var ENGINE_REGISTRY = {
|
|
|
145
145
|
loginHint: "run `codex login`, or set CODEX_API_KEY, or point `codexBin` at a signed-in install",
|
|
146
146
|
authPaths: [".codex/auth.json"],
|
|
147
147
|
localeKey: "engineCodex",
|
|
148
|
+
// Read out of the bundled CLI binary (0.149.1), which carries the ids its
|
|
149
|
+
// `thread/start` accepts; the driver passes the picked id straight through as
|
|
150
|
+
// `model`. Only the codex-family ids are listed: the binary also mentions
|
|
151
|
+
// `gpt-4.1`/`gpt-5.6` in contexts this build did not verify, and a wrong id
|
|
152
|
+
// fails loudly at the engine rather than silently falling back.
|
|
153
|
+
models: [
|
|
154
|
+
{ id: "gpt-5.3-codex", label: "GPT-5.3 Codex" },
|
|
155
|
+
{ id: "gpt-5.2-codex", label: "GPT-5.2 Codex" },
|
|
156
|
+
{ id: "gpt-5.1-codex-max", label: "GPT-5.1 Codex Max" },
|
|
157
|
+
{ id: "gpt-5.1-codex", label: "GPT-5.1 Codex" },
|
|
158
|
+
{ id: "gpt-5.4", label: "GPT-5.4" },
|
|
159
|
+
{ id: "gpt-5.2", label: "GPT-5.2" },
|
|
160
|
+
{ id: "gpt-5.1", label: "GPT-5.1" }
|
|
161
|
+
],
|
|
148
162
|
capabilities: {
|
|
149
163
|
streaming: true,
|
|
150
164
|
protocol: "jsonrpc",
|
|
@@ -188,6 +202,20 @@ var ENGINE_REGISTRY = {
|
|
|
188
202
|
loginHint: "run `kimi` once and sign in (or `kimi login`)",
|
|
189
203
|
authPaths: [".kimi-code/credentials.json", ".kimi-code/auth.json"],
|
|
190
204
|
localeKey: "engineKimi",
|
|
205
|
+
// Read out of `~/.kimi-code/config.toml`, which the Kimi Code app writes for
|
|
206
|
+
// the signed-in account: one `[models."kimi-code/<id>"]` block per model the
|
|
207
|
+
// account is provisioned for, with the vendor's own display name. The ids are
|
|
208
|
+
// what the app passes as `model`, so they are the right vocabulary for this
|
|
209
|
+
// driver's `session/set_model`. The catalog was NOT read off the ACP surface
|
|
210
|
+
// itself, because the `kimi` CLI is not installed on the machine this was
|
|
211
|
+
// measured on (only the desktop app is) — a stale id fails loudly at the
|
|
212
|
+
// engine rather than silently falling back.
|
|
213
|
+
models: [
|
|
214
|
+
{ id: "k3", label: "K3" },
|
|
215
|
+
{ id: "k3-256k", label: "K3-256k" },
|
|
216
|
+
{ id: "kimi-for-coding", label: "K2.8 Preview" },
|
|
217
|
+
{ id: "kimi-for-coding-highspeed", label: "K2.7 Code Highspeed" }
|
|
218
|
+
],
|
|
191
219
|
capabilities: {
|
|
192
220
|
streaming: true,
|
|
193
221
|
protocol: "acp",
|
|
@@ -1029,10 +1057,14 @@ var HostedEngineRouteAdapter = class extends LlmAdapter {
|
|
|
1029
1057
|
/**
|
|
1030
1058
|
* The engine-native models this route advertises, beyond `default`.
|
|
1031
1059
|
*
|
|
1032
|
-
*
|
|
1033
|
-
*
|
|
1060
|
+
* A THUNK rather than a fixed list, because the catalog can change after the
|
|
1061
|
+
* route is registered: an ACP engine publishes its models in `session/new`, and a
|
|
1062
|
+
* config file can gain a model when the vendor ships one. Reading it per catalog
|
|
1063
|
+
* build is what makes a discovered model appear without a plugin restart (see
|
|
1064
|
+
* `model-registry.ts`). A route with nothing to add returns an empty list, which
|
|
1065
|
+
* is the shared `external` route's state.
|
|
1034
1066
|
*/
|
|
1035
|
-
|
|
1067
|
+
modelsOf;
|
|
1036
1068
|
/**
|
|
1037
1069
|
* The name this route's group shows in the model menu.
|
|
1038
1070
|
*
|
|
@@ -1052,7 +1084,7 @@ var HostedEngineRouteAdapter = class extends LlmAdapter {
|
|
|
1052
1084
|
super();
|
|
1053
1085
|
this.contextWindow = contextWindow !== void 0 && Number.isInteger(contextWindow) && contextWindow > 0 ? contextWindow : DEFAULT_ENGINE_CONTEXT_WINDOW;
|
|
1054
1086
|
this.label = label;
|
|
1055
|
-
this.
|
|
1087
|
+
this.modelsOf = typeof models === "function" ? models : () => models;
|
|
1056
1088
|
this.displayName = displayName;
|
|
1057
1089
|
}
|
|
1058
1090
|
/**
|
|
@@ -1102,7 +1134,7 @@ var HostedEngineRouteAdapter = class extends LlmAdapter {
|
|
|
1102
1134
|
},
|
|
1103
1135
|
// The engine's own models, from its own subscription. Selecting one hands
|
|
1104
1136
|
// its id to the engine; the plugin still serves no model on this route.
|
|
1105
|
-
...this.
|
|
1137
|
+
...this.modelsOf().map((model) => ({
|
|
1106
1138
|
provider,
|
|
1107
1139
|
id: model.id,
|
|
1108
1140
|
name: model.label,
|
|
@@ -5698,6 +5730,138 @@ function createTerminalBridge(shell, defaultCwd) {
|
|
|
5698
5730
|
};
|
|
5699
5731
|
}
|
|
5700
5732
|
|
|
5733
|
+
// src/model-registry.ts
|
|
5734
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
5735
|
+
import { join as join5 } from "node:path";
|
|
5736
|
+
|
|
5737
|
+
// src/engine-kimi/process.ts
|
|
5738
|
+
import { existsSync } from "node:fs";
|
|
5739
|
+
import { homedir } from "node:os";
|
|
5740
|
+
import { join as join4 } from "node:path";
|
|
5741
|
+
|
|
5742
|
+
// src/driver-acp/subprocess.ts
|
|
5743
|
+
function acpSubprocessSpec(spec, graceMs) {
|
|
5744
|
+
return {
|
|
5745
|
+
argv: [...spec.argv],
|
|
5746
|
+
cwd: spec.cwd,
|
|
5747
|
+
stdio: { stdin: "pipe", stdout: "pipe", stderr: "pipe" },
|
|
5748
|
+
graceMs,
|
|
5749
|
+
env: spec.env,
|
|
5750
|
+
...spec.signal === void 0 ? {} : { signal: spec.signal }
|
|
5751
|
+
};
|
|
5752
|
+
}
|
|
5753
|
+
function fromSubprocess2(handle) {
|
|
5754
|
+
const { stdin, stdout, stderr } = handle;
|
|
5755
|
+
if (stdin === void 0 || stdout === void 0 || stderr === void 0) {
|
|
5756
|
+
throw new Error("driver-acp: spawned child must pipe stdin/stdout/stderr");
|
|
5757
|
+
}
|
|
5758
|
+
return {
|
|
5759
|
+
stdin,
|
|
5760
|
+
stdout,
|
|
5761
|
+
stderr,
|
|
5762
|
+
done: handle.done,
|
|
5763
|
+
terminate: () => handle.terminate()
|
|
5764
|
+
};
|
|
5765
|
+
}
|
|
5766
|
+
|
|
5767
|
+
// src/engine-kimi/process.ts
|
|
5768
|
+
function kimiHomeDir() {
|
|
5769
|
+
const envHome = process.env.KIMI_CODE_HOME;
|
|
5770
|
+
return envHome !== void 0 && envHome !== "" ? envHome : join4(homedir(), ".kimi-code");
|
|
5771
|
+
}
|
|
5772
|
+
function kimiBinResolver(configBin) {
|
|
5773
|
+
if (configBin !== void 0 && configBin !== "") return configBin;
|
|
5774
|
+
const executable = process.platform === "win32" ? "kimi.exe" : "kimi";
|
|
5775
|
+
const candidate = join4(kimiHomeDir(), "bin", executable);
|
|
5776
|
+
return existsSync(candidate) ? candidate : "kimi";
|
|
5777
|
+
}
|
|
5778
|
+
function kimiAcpArgv(bin) {
|
|
5779
|
+
return [bin, "acp"];
|
|
5780
|
+
}
|
|
5781
|
+
|
|
5782
|
+
// src/model-discovery.ts
|
|
5783
|
+
function parseKimiConfigModels(text) {
|
|
5784
|
+
const models = [];
|
|
5785
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5786
|
+
let currentId;
|
|
5787
|
+
let currentLabel;
|
|
5788
|
+
const flush = () => {
|
|
5789
|
+
if (currentId !== void 0 && !seen.has(currentId)) {
|
|
5790
|
+
seen.add(currentId);
|
|
5791
|
+
models.push({ id: currentId, label: currentLabel ?? currentId });
|
|
5792
|
+
}
|
|
5793
|
+
currentId = void 0;
|
|
5794
|
+
currentLabel = void 0;
|
|
5795
|
+
};
|
|
5796
|
+
for (const rawLine of text.split(/\r?\n/u)) {
|
|
5797
|
+
const line = rawLine.trim();
|
|
5798
|
+
if (line.startsWith("[")) {
|
|
5799
|
+
flush();
|
|
5800
|
+
const header = /^\[models\."([^"]+)"\]$/u.exec(line);
|
|
5801
|
+
if (header !== null) {
|
|
5802
|
+
const key = header[1];
|
|
5803
|
+
const slash = key.indexOf("/");
|
|
5804
|
+
currentId = slash === -1 ? key : key.slice(slash + 1);
|
|
5805
|
+
}
|
|
5806
|
+
continue;
|
|
5807
|
+
}
|
|
5808
|
+
if (currentId === void 0) continue;
|
|
5809
|
+
const label = /^display_name\s*=\s*"([^"]*)"/u.exec(line);
|
|
5810
|
+
if (label !== null) currentLabel = label[1];
|
|
5811
|
+
}
|
|
5812
|
+
flush();
|
|
5813
|
+
return models;
|
|
5814
|
+
}
|
|
5815
|
+
function modelsFromAcpConfigOptions(configOptions) {
|
|
5816
|
+
if (!Array.isArray(configOptions)) return void 0;
|
|
5817
|
+
for (const option of configOptions) {
|
|
5818
|
+
const entry = option;
|
|
5819
|
+
if (entry?.id !== "model" || !Array.isArray(entry.options)) continue;
|
|
5820
|
+
const models = [];
|
|
5821
|
+
for (const candidate of entry.options) {
|
|
5822
|
+
const value = candidate?.value;
|
|
5823
|
+
if (typeof value !== "string" || value === "") continue;
|
|
5824
|
+
const name2 = candidate?.name;
|
|
5825
|
+
models.push({ id: value, label: typeof name2 === "string" && name2 !== "" ? name2 : value });
|
|
5826
|
+
}
|
|
5827
|
+
return models.length === 0 ? void 0 : models;
|
|
5828
|
+
}
|
|
5829
|
+
return void 0;
|
|
5830
|
+
}
|
|
5831
|
+
|
|
5832
|
+
// src/model-registry.ts
|
|
5833
|
+
var discovered = /* @__PURE__ */ new Map();
|
|
5834
|
+
function discoverKimiCatalog() {
|
|
5835
|
+
try {
|
|
5836
|
+
const text = readFileSync2(join5(kimiHomeDir(), "config.toml"), "utf8");
|
|
5837
|
+
const models = parseKimiConfigModels(text);
|
|
5838
|
+
return models.length === 0 ? void 0 : { models, source: "kimi-config" };
|
|
5839
|
+
} catch {
|
|
5840
|
+
return void 0;
|
|
5841
|
+
}
|
|
5842
|
+
}
|
|
5843
|
+
function recordDiscoveredCatalog(engine, models) {
|
|
5844
|
+
if (models.length === 0) return;
|
|
5845
|
+
discovered.set(engine, { models, source: "acp-session" });
|
|
5846
|
+
}
|
|
5847
|
+
function bootCatalog(engine) {
|
|
5848
|
+
const free = engine === "kimi" ? discoverKimiCatalog() : void 0;
|
|
5849
|
+
if (free !== void 0) discovered.set(engine, free);
|
|
5850
|
+
const declared = declaredModels(engine);
|
|
5851
|
+
if (free !== void 0) return { models: free.models, origin: "discovered" };
|
|
5852
|
+
if (declared !== void 0 && declared.length > 0) return { models: declared, origin: "declared" };
|
|
5853
|
+
return { models: [], origin: "none" };
|
|
5854
|
+
}
|
|
5855
|
+
function liveCatalog(engine) {
|
|
5856
|
+
const found = discovered.get(engine);
|
|
5857
|
+
if (found !== void 0 && found.models.length > 0) return found.models;
|
|
5858
|
+
return declaredModels(engine) ?? [];
|
|
5859
|
+
}
|
|
5860
|
+
function declaredModels(engine) {
|
|
5861
|
+
const descriptor = ENGINE_REGISTRY[engine];
|
|
5862
|
+
return descriptor.models;
|
|
5863
|
+
}
|
|
5864
|
+
|
|
5701
5865
|
// src/driver-acp/approval.ts
|
|
5702
5866
|
function acpDefaultApproval(session) {
|
|
5703
5867
|
return sessionApprovalPolicy(session.snapshotEvents()) !== "ask";
|
|
@@ -5814,6 +5978,15 @@ var AcpClient = class _AcpClient {
|
|
|
5814
5978
|
handlers;
|
|
5815
5979
|
/** Every terminal this client owns, so a disposed client cannot leak a process. */
|
|
5816
5980
|
terminals = /* @__PURE__ */ new Map();
|
|
5981
|
+
/**
|
|
5982
|
+
* The model catalog the agent published on its last `session/new`.
|
|
5983
|
+
*
|
|
5984
|
+
* Free discovery: the frame was already paid for by a session the user opened, so
|
|
5985
|
+
* keeping it costs nothing and spares the maintainer from re-declaring the list
|
|
5986
|
+
* every time the vendor ships a model. `undefined` means the agent published no
|
|
5987
|
+
* model option (every engine except the ACP ones that do).
|
|
5988
|
+
*/
|
|
5989
|
+
lastCatalog;
|
|
5817
5990
|
/** Monotonic id source for the terminals the agent creates. */
|
|
5818
5991
|
nextTerminalId = 1;
|
|
5819
5992
|
/** Whether this client was sealed or its process exited. */
|
|
@@ -5919,8 +6092,20 @@ var AcpClient = class _AcpClient {
|
|
|
5919
6092
|
if (typeof sessionId !== "string" || sessionId.length === 0) {
|
|
5920
6093
|
throw new Error(`${this.label} acp session/new returned no session id`);
|
|
5921
6094
|
}
|
|
6095
|
+
const discovered2 = modelsFromAcpConfigOptions(result.configOptions);
|
|
6096
|
+
if (discovered2 !== void 0) this.lastCatalog = discovered2;
|
|
5922
6097
|
return sessionId;
|
|
5923
6098
|
}
|
|
6099
|
+
/**
|
|
6100
|
+
* The model catalog this agent published on its last `session/new`, if any.
|
|
6101
|
+
*
|
|
6102
|
+
* Empty until the first session is opened, which is the honest state: the plugin
|
|
6103
|
+
* does not know the catalog before an engine has been asked.
|
|
6104
|
+
* @returns the discovered models, or undefined when the agent published none.
|
|
6105
|
+
*/
|
|
6106
|
+
discoveredModels() {
|
|
6107
|
+
return this.lastCatalog;
|
|
6108
|
+
}
|
|
5924
6109
|
/**
|
|
5925
6110
|
* Load (resume) an existing ACP session by id.
|
|
5926
6111
|
*
|
|
@@ -6761,6 +6946,8 @@ var AcpEngineAgent = class {
|
|
|
6761
6946
|
signal.throwIfAborted();
|
|
6762
6947
|
client.onPermission(() => (this.profile.approve ?? acpDefaultApproval)(this.session));
|
|
6763
6948
|
const acpSessionId = await this.openSession(client, cwd);
|
|
6949
|
+
const discovered2 = client.discoveredModels();
|
|
6950
|
+
if (discovered2 !== void 0) recordDiscoveredCatalog(this.profile.engine, discovered2);
|
|
6764
6951
|
signal.throwIfAborted();
|
|
6765
6952
|
const model = override?.model ?? this.config.model;
|
|
6766
6953
|
if (!handedOver && model !== void 0 && this.profile.selectModel !== void 0) {
|
|
@@ -7039,51 +7226,6 @@ function kimiModelEnv(handover) {
|
|
|
7039
7226
|
};
|
|
7040
7227
|
}
|
|
7041
7228
|
|
|
7042
|
-
// src/engine-kimi/process.ts
|
|
7043
|
-
import { existsSync } from "node:fs";
|
|
7044
|
-
import { homedir } from "node:os";
|
|
7045
|
-
import { join as join4 } from "node:path";
|
|
7046
|
-
|
|
7047
|
-
// src/driver-acp/subprocess.ts
|
|
7048
|
-
function acpSubprocessSpec(spec, graceMs) {
|
|
7049
|
-
return {
|
|
7050
|
-
argv: [...spec.argv],
|
|
7051
|
-
cwd: spec.cwd,
|
|
7052
|
-
stdio: { stdin: "pipe", stdout: "pipe", stderr: "pipe" },
|
|
7053
|
-
graceMs,
|
|
7054
|
-
env: spec.env,
|
|
7055
|
-
...spec.signal === void 0 ? {} : { signal: spec.signal }
|
|
7056
|
-
};
|
|
7057
|
-
}
|
|
7058
|
-
function fromSubprocess2(handle) {
|
|
7059
|
-
const { stdin, stdout, stderr } = handle;
|
|
7060
|
-
if (stdin === void 0 || stdout === void 0 || stderr === void 0) {
|
|
7061
|
-
throw new Error("driver-acp: spawned child must pipe stdin/stdout/stderr");
|
|
7062
|
-
}
|
|
7063
|
-
return {
|
|
7064
|
-
stdin,
|
|
7065
|
-
stdout,
|
|
7066
|
-
stderr,
|
|
7067
|
-
done: handle.done,
|
|
7068
|
-
terminate: () => handle.terminate()
|
|
7069
|
-
};
|
|
7070
|
-
}
|
|
7071
|
-
|
|
7072
|
-
// src/engine-kimi/process.ts
|
|
7073
|
-
function kimiHomeDir() {
|
|
7074
|
-
const envHome = process.env.KIMI_CODE_HOME;
|
|
7075
|
-
return envHome !== void 0 && envHome !== "" ? envHome : join4(homedir(), ".kimi-code");
|
|
7076
|
-
}
|
|
7077
|
-
function kimiBinResolver(configBin) {
|
|
7078
|
-
if (configBin !== void 0 && configBin !== "") return configBin;
|
|
7079
|
-
const executable = process.platform === "win32" ? "kimi.exe" : "kimi";
|
|
7080
|
-
const candidate = join4(kimiHomeDir(), "bin", executable);
|
|
7081
|
-
return existsSync(candidate) ? candidate : "kimi";
|
|
7082
|
-
}
|
|
7083
|
-
function kimiAcpArgv(bin) {
|
|
7084
|
-
return [bin, "acp"];
|
|
7085
|
-
}
|
|
7086
|
-
|
|
7087
7229
|
// src/engine-kimi/permission.ts
|
|
7088
7230
|
function resolveToolApproval(events) {
|
|
7089
7231
|
return sessionApprovalPolicy(events) !== "ask";
|
|
@@ -8177,7 +8319,7 @@ function unsupportedImagesRefusal(messages, descriptor) {
|
|
|
8177
8319
|
|
|
8178
8320
|
// src/engine-agy/process.ts
|
|
8179
8321
|
import { existsSync as existsSync2 } from "node:fs";
|
|
8180
|
-
import { join as
|
|
8322
|
+
import { join as join6 } from "node:path";
|
|
8181
8323
|
var AGY_DISPOSE_GRACE_MS = 3e3;
|
|
8182
8324
|
var AGY_MODES = ["accept-edits", "auto", "plan"];
|
|
8183
8325
|
var AGY_EFFORTS = ["low", "medium", "high", "xhigh", "max"];
|
|
@@ -8186,7 +8328,7 @@ function agyBinResolver(configBin) {
|
|
|
8186
8328
|
const local = process.env.LOCALAPPDATA;
|
|
8187
8329
|
if (local !== void 0 && local !== "") {
|
|
8188
8330
|
const executable = process.platform === "win32" ? "agy.EXE" : "agy";
|
|
8189
|
-
const candidate =
|
|
8331
|
+
const candidate = join6(local, "agy", "bin", executable);
|
|
8190
8332
|
if (existsSync2(candidate)) return candidate;
|
|
8191
8333
|
}
|
|
8192
8334
|
return "agy";
|
|
@@ -8741,16 +8883,16 @@ function mapStreamJsonDocument(document, accept, run) {
|
|
|
8741
8883
|
// src/engine-qoderclicn/process.ts
|
|
8742
8884
|
import { existsSync as existsSync4 } from "node:fs";
|
|
8743
8885
|
import { homedir as homedir2 } from "node:os";
|
|
8744
|
-
import { join as
|
|
8886
|
+
import { join as join7 } from "node:path";
|
|
8745
8887
|
var QODERCLICN_DISPOSE_GRACE_MS = 3e3;
|
|
8746
8888
|
function qoderclicnHomeDir() {
|
|
8747
8889
|
const envHome = process.env.QODER_HOME;
|
|
8748
|
-
return envHome !== void 0 && envHome !== "" ? envHome :
|
|
8890
|
+
return envHome !== void 0 && envHome !== "" ? envHome : join7(homedir2(), ".qoder-cn");
|
|
8749
8891
|
}
|
|
8750
8892
|
function qoderclicnBinResolver(configBin) {
|
|
8751
8893
|
if (configBin !== void 0 && configBin !== "") return configBin;
|
|
8752
8894
|
const executable = process.platform === "win32" ? "qoderclicn.exe" : "qoderclicn";
|
|
8753
|
-
const candidate =
|
|
8895
|
+
const candidate = join7(qoderclicnHomeDir(), "bin", "qoderclicn", executable);
|
|
8754
8896
|
return existsSync4(candidate) ? candidate : "qoderclicn";
|
|
8755
8897
|
}
|
|
8756
8898
|
function qoderclicnPermissionMode(sandbox, approval) {
|
|
@@ -8879,14 +9021,14 @@ import z8 from "@deepseek-ai/schemastery";
|
|
|
8879
9021
|
|
|
8880
9022
|
// src/engine-hermes/process.ts
|
|
8881
9023
|
import { existsSync as existsSync5 } from "node:fs";
|
|
8882
|
-
import { delimiter, join as
|
|
9024
|
+
import { delimiter, join as join8 } from "node:path";
|
|
8883
9025
|
var HERMES_DISPOSE_GRACE_MS = 3e3;
|
|
8884
9026
|
var HERMES_PROMPT_FLAG = "-z";
|
|
8885
9027
|
function wellKnownHermes() {
|
|
8886
9028
|
if (process.platform !== "win32") return void 0;
|
|
8887
9029
|
const local = process.env.LOCALAPPDATA;
|
|
8888
9030
|
if (local === void 0 || local === "") return void 0;
|
|
8889
|
-
const candidate =
|
|
9031
|
+
const candidate = join8(local, "hermes", "hermes-agent", "venv", "Scripts", "hermes.exe");
|
|
8890
9032
|
return existsSync5(candidate) ? candidate : void 0;
|
|
8891
9033
|
}
|
|
8892
9034
|
function hermesBinResolver(configBin) {
|
|
@@ -8984,11 +9126,11 @@ import z9 from "@deepseek-ai/schemastery";
|
|
|
8984
9126
|
// src/engine-grok/process.ts
|
|
8985
9127
|
import { existsSync as existsSync7 } from "node:fs";
|
|
8986
9128
|
import { homedir as homedir3 } from "node:os";
|
|
8987
|
-
import { join as
|
|
9129
|
+
import { join as join10 } from "node:path";
|
|
8988
9130
|
|
|
8989
9131
|
// src/driver-acp/executable.ts
|
|
8990
9132
|
import { existsSync as existsSync6 } from "node:fs";
|
|
8991
|
-
import { join as
|
|
9133
|
+
import { join as join9 } from "node:path";
|
|
8992
9134
|
function execArgvPrefix(bin) {
|
|
8993
9135
|
if (/\.(?:c|m)?js$/i.test(bin)) return [process.execPath, bin];
|
|
8994
9136
|
if (/\.(?:cmd|bat)$/i.test(bin)) return [process.env.ComSpec ?? "cmd.exe", "/c", bin];
|
|
@@ -9002,7 +9144,7 @@ function resolveOnPath(name2, env = process.env) {
|
|
|
9002
9144
|
for (const directory of path.split(separator)) {
|
|
9003
9145
|
if (directory === "") continue;
|
|
9004
9146
|
for (const extension of extensions) {
|
|
9005
|
-
const candidate =
|
|
9147
|
+
const candidate = join9(directory, `${name2}${extension}`);
|
|
9006
9148
|
if (existsSync6(candidate)) return candidate;
|
|
9007
9149
|
}
|
|
9008
9150
|
}
|
|
@@ -9013,8 +9155,8 @@ function npmPackageEntry(prefix, pkg, entry) {
|
|
|
9013
9155
|
const scope = scoped ? pkg.slice(0, pkg.indexOf("/")) : "";
|
|
9014
9156
|
const name2 = scoped ? pkg.slice(pkg.indexOf("/") + 1) : pkg;
|
|
9015
9157
|
if (name2 === "" || scoped && scope === "") return void 0;
|
|
9016
|
-
const relative = scoped ?
|
|
9017
|
-
for (const candidate of [
|
|
9158
|
+
const relative = scoped ? join9("node_modules", scope, name2, entry) : join9("node_modules", name2, entry);
|
|
9159
|
+
for (const candidate of [join9(prefix, relative), join9(prefix, "lib", relative)]) {
|
|
9018
9160
|
if (existsSync6(candidate)) return candidate;
|
|
9019
9161
|
}
|
|
9020
9162
|
return void 0;
|
|
@@ -9024,12 +9166,12 @@ function npmPackageEntry(prefix, pkg, entry) {
|
|
|
9024
9166
|
var GROK_DISPOSE_GRACE_MS = 3e3;
|
|
9025
9167
|
function grokHomeDir() {
|
|
9026
9168
|
const envHome = process.env.GROK_HOME;
|
|
9027
|
-
return envHome !== void 0 && envHome !== "" ? envHome :
|
|
9169
|
+
return envHome !== void 0 && envHome !== "" ? envHome : join10(homedir3(), ".grok");
|
|
9028
9170
|
}
|
|
9029
9171
|
function grokBinResolver(configBin) {
|
|
9030
9172
|
if (configBin !== void 0 && configBin !== "") return configBin;
|
|
9031
9173
|
const executable = process.platform === "win32" ? "grok.exe" : "grok";
|
|
9032
|
-
const candidate =
|
|
9174
|
+
const candidate = join10(grokHomeDir(), "bin", executable);
|
|
9033
9175
|
if (existsSync7(candidate)) return candidate;
|
|
9034
9176
|
return resolveOnPath("grok") ?? "grok";
|
|
9035
9177
|
}
|
|
@@ -9134,7 +9276,7 @@ import z10 from "@deepseek-ai/schemastery";
|
|
|
9134
9276
|
|
|
9135
9277
|
// src/engine-minimaxcode/process.ts
|
|
9136
9278
|
import { homedir as homedir4 } from "node:os";
|
|
9137
|
-
import { dirname as dirname3, join as
|
|
9279
|
+
import { dirname as dirname3, join as join11 } from "node:path";
|
|
9138
9280
|
var MINIMAXCODE_DISPOSE_GRACE_MS = 3e3;
|
|
9139
9281
|
var MINIMAXCODE_NPM_PACKAGE = "@minimax-ai/code";
|
|
9140
9282
|
var MINIMAXCODE_ENTRYPOINT = "cli.js";
|
|
@@ -9142,7 +9284,7 @@ function mcodeBinResolver(configBin, env = process.env) {
|
|
|
9142
9284
|
if (configBin !== void 0 && configBin !== "") return configBin;
|
|
9143
9285
|
const prefixes = [
|
|
9144
9286
|
env.MCODE_INSTALL_ROOT,
|
|
9145
|
-
env.APPDATA === void 0 ? void 0 :
|
|
9287
|
+
env.APPDATA === void 0 ? void 0 : join11(env.APPDATA, "npm"),
|
|
9146
9288
|
// A standard Windows node install puts the global prefix beside node.exe.
|
|
9147
9289
|
dirname3(process.execPath),
|
|
9148
9290
|
dirname3(dirname3(process.execPath)),
|
|
@@ -9151,7 +9293,7 @@ function mcodeBinResolver(configBin, env = process.env) {
|
|
|
9151
9293
|
// `HOME`, and the whole point of this resolver is to find an install the
|
|
9152
9294
|
// inherited environment may not describe.
|
|
9153
9295
|
"/usr/local",
|
|
9154
|
-
|
|
9296
|
+
join11(homedir4(), ".npm-global")
|
|
9155
9297
|
];
|
|
9156
9298
|
for (const prefix of prefixes) {
|
|
9157
9299
|
if (prefix === void 0 || prefix === "") continue;
|
|
@@ -9451,7 +9593,7 @@ ${block}`);
|
|
|
9451
9593
|
// src/preset.ts
|
|
9452
9594
|
import { mkdir, readFile as readFile2, rename, writeFile } from "node:fs/promises";
|
|
9453
9595
|
import { randomUUID } from "node:crypto";
|
|
9454
|
-
import { dirname as dirname4, join as
|
|
9596
|
+
import { dirname as dirname4, join as join12 } from "node:path";
|
|
9455
9597
|
var USER_PRESET_DIR = ".agent-presets";
|
|
9456
9598
|
var COMPOSITION_FILE = "agent.cordis.yml";
|
|
9457
9599
|
var METADATA_FILE = "preset.yml";
|
|
@@ -9651,9 +9793,9 @@ async function ensureEnginePresets(dshHome, source, target) {
|
|
|
9651
9793
|
${applySummarizerTarget(stripPresetRows(composition), target)}`;
|
|
9652
9794
|
let changed = false;
|
|
9653
9795
|
for (const engine of HOSTED_ENGINE_IDS) {
|
|
9654
|
-
const dir =
|
|
9655
|
-
const compositionChanged = await writeIfDifferent(
|
|
9656
|
-
const metadataChanged = await writeIfDifferent(
|
|
9796
|
+
const dir = join12(dshHome, USER_PRESET_DIR, enginePresetId(engine));
|
|
9797
|
+
const compositionChanged = await writeIfDifferent(join12(dir, COMPOSITION_FILE), stripped);
|
|
9798
|
+
const metadataChanged = await writeIfDifferent(join12(dir, METADATA_FILE), managedMetadata(engine));
|
|
9657
9799
|
changed = changed || compositionChanged || metadataChanged;
|
|
9658
9800
|
}
|
|
9659
9801
|
return changed;
|
|
@@ -9907,9 +10049,9 @@ function usableSelection(answered) {
|
|
|
9907
10049
|
}
|
|
9908
10050
|
|
|
9909
10051
|
// src/commands.ts
|
|
9910
|
-
import { readdirSync, readFileSync as
|
|
10052
|
+
import { readdirSync, readFileSync as readFileSync3 } from "node:fs";
|
|
9911
10053
|
import { homedir as homedir5 } from "node:os";
|
|
9912
|
-
import { join as
|
|
10054
|
+
import { join as join13 } from "node:path";
|
|
9913
10055
|
import { createUserMessage as createUserMessage6 } from "@deepseek-ai/dsh-llm";
|
|
9914
10056
|
var COMMAND_NAME = /^[a-z][a-z0-9_-]*$/;
|
|
9915
10057
|
function forwardClaudeCodeCommand(name2) {
|
|
@@ -9943,10 +10085,10 @@ function discoverUserSlashCommands() {
|
|
|
9943
10085
|
if (!entry.endsWith(".md")) continue;
|
|
9944
10086
|
const name2 = entry.slice(0, -".md".length);
|
|
9945
10087
|
if (!COMMAND_NAME.test(name2) || seen.has(name2)) continue;
|
|
9946
|
-
const path =
|
|
10088
|
+
const path = join13(userCommandsDir(), entry);
|
|
9947
10089
|
let raw;
|
|
9948
10090
|
try {
|
|
9949
|
-
raw =
|
|
10091
|
+
raw = readFileSync3(path, "utf8");
|
|
9950
10092
|
} catch {
|
|
9951
10093
|
continue;
|
|
9952
10094
|
}
|
|
@@ -9958,7 +10100,7 @@ function discoverUserSlashCommands() {
|
|
|
9958
10100
|
return definitions;
|
|
9959
10101
|
}
|
|
9960
10102
|
function userCommandsDir() {
|
|
9961
|
-
return
|
|
10103
|
+
return join13(homedir5(), ".claude", "commands");
|
|
9962
10104
|
}
|
|
9963
10105
|
function commandDescription(raw) {
|
|
9964
10106
|
const trimmed = raw.trim();
|
|
@@ -10009,7 +10151,7 @@ var KIMI_COMMANDS = [
|
|
|
10009
10151
|
// src/skills.ts
|
|
10010
10152
|
import { readFile as readFile3, readdir, stat } from "node:fs/promises";
|
|
10011
10153
|
import { homedir as homedir6 } from "node:os";
|
|
10012
|
-
import { join as
|
|
10154
|
+
import { join as join14, resolve } from "node:path";
|
|
10013
10155
|
var SKILL_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
10014
10156
|
var PROVIDER_NAME = "claude-code";
|
|
10015
10157
|
var CLAUDE_CODE_RANK = 150;
|
|
@@ -10119,10 +10261,10 @@ var ClaudeCodeSkillProvider = class {
|
|
|
10119
10261
|
const cwd = options.cwd;
|
|
10120
10262
|
if (cwd !== void 0) {
|
|
10121
10263
|
const projectRoot = await findProjectRoot(resolve(cwd));
|
|
10122
|
-
await collectSkillsDir(
|
|
10264
|
+
await collectSkillsDir(join14(projectRoot, ".claude", "skills"), CLAUDE_CODE_RANK, candidates);
|
|
10123
10265
|
await collectClaudeMd(projectRoot, candidates);
|
|
10124
10266
|
}
|
|
10125
|
-
await collectSkillsDir(
|
|
10267
|
+
await collectSkillsDir(join14(homedir6(), ".claude", "skills"), CLAUDE_CODE_USER_RANK, candidates);
|
|
10126
10268
|
if (this.control.signal.aborted) return [];
|
|
10127
10269
|
return candidates;
|
|
10128
10270
|
}
|
|
@@ -10156,11 +10298,11 @@ async function collectSkillsDir(skillsDir, rank, candidates) {
|
|
|
10156
10298
|
return;
|
|
10157
10299
|
}
|
|
10158
10300
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
10159
|
-
const entryPath =
|
|
10301
|
+
const entryPath = join14(skillsDir, entry.name);
|
|
10160
10302
|
const info = await stat(entryPath).catch(() => void 0);
|
|
10161
10303
|
if (info === void 0) continue;
|
|
10162
10304
|
if (info.isDirectory()) {
|
|
10163
|
-
const path =
|
|
10305
|
+
const path = join14(entryPath, "SKILL.md");
|
|
10164
10306
|
const skill2 = await tryParseSkill(path);
|
|
10165
10307
|
if (skill2 === void 0) continue;
|
|
10166
10308
|
candidates.push(toCandidate(skill2, path, rank, entryPath));
|
|
@@ -10173,7 +10315,7 @@ async function collectSkillsDir(skillsDir, rank, candidates) {
|
|
|
10173
10315
|
}
|
|
10174
10316
|
}
|
|
10175
10317
|
async function collectClaudeMd(projectRoot, candidates) {
|
|
10176
|
-
const claudeMd =
|
|
10318
|
+
const claudeMd = join14(projectRoot, "CLAUDE.md");
|
|
10177
10319
|
try {
|
|
10178
10320
|
const info = await stat(claudeMd);
|
|
10179
10321
|
if (!info.isFile()) return;
|
|
@@ -10210,7 +10352,7 @@ async function findProjectRoot(cwd) {
|
|
|
10210
10352
|
let current = cwd;
|
|
10211
10353
|
while (true) {
|
|
10212
10354
|
try {
|
|
10213
|
-
await stat(
|
|
10355
|
+
await stat(join14(current, ".git"));
|
|
10214
10356
|
return current;
|
|
10215
10357
|
} catch {
|
|
10216
10358
|
}
|
|
@@ -10222,15 +10364,15 @@ async function findProjectRoot(cwd) {
|
|
|
10222
10364
|
|
|
10223
10365
|
// src/engine-codex/skills.ts
|
|
10224
10366
|
import { homedir as homedir7 } from "node:os";
|
|
10225
|
-
import { join as
|
|
10367
|
+
import { join as join17 } from "node:path";
|
|
10226
10368
|
|
|
10227
10369
|
// src/driver-core/agents-md-skill-provider.ts
|
|
10228
10370
|
import { readdir as readdir2, readFile as readFile5, stat as stat3 } from "node:fs/promises";
|
|
10229
|
-
import { dirname as dirname5, join as
|
|
10371
|
+
import { dirname as dirname5, join as join16 } from "node:path";
|
|
10230
10372
|
|
|
10231
10373
|
// src/driver-core/context-files.ts
|
|
10232
10374
|
import { readFile as readFile4, stat as stat2 } from "node:fs/promises";
|
|
10233
|
-
import { join as
|
|
10375
|
+
import { join as join15, resolve as resolve2 } from "node:path";
|
|
10234
10376
|
async function projectAncestors(cwd) {
|
|
10235
10377
|
const root = await findProjectRoot(resolve2(cwd));
|
|
10236
10378
|
const dirs = [];
|
|
@@ -10251,11 +10393,11 @@ async function collectProjectContextFiles(cwd, policy) {
|
|
|
10251
10393
|
}
|
|
10252
10394
|
async function dirContextFile(dir, policy) {
|
|
10253
10395
|
if (policy.override !== void 0) {
|
|
10254
|
-
const override =
|
|
10396
|
+
const override = join15(dir, policy.override);
|
|
10255
10397
|
if (await pathExists(override)) return override;
|
|
10256
10398
|
}
|
|
10257
10399
|
for (const name2 of policy.primary) {
|
|
10258
|
-
const candidate =
|
|
10400
|
+
const candidate = join15(dir, name2);
|
|
10259
10401
|
if (await pathExists(candidate)) return candidate;
|
|
10260
10402
|
}
|
|
10261
10403
|
return void 0;
|
|
@@ -10315,18 +10457,18 @@ var AgentsMdSkillProvider = class {
|
|
|
10315
10457
|
if (this.spec.skills !== void 0) {
|
|
10316
10458
|
const catalog = this.spec.skills;
|
|
10317
10459
|
for (const dir of await projectAncestors(cwd)) {
|
|
10318
|
-
await this.collectSkillsDir(
|
|
10460
|
+
await this.collectSkillsDir(join16(dir, ...catalog.project), catalog.projectRank, candidates);
|
|
10319
10461
|
}
|
|
10320
10462
|
}
|
|
10321
10463
|
}
|
|
10322
10464
|
const userDir = this.spec.userDir();
|
|
10323
10465
|
const userContext = this.spec.userContext;
|
|
10324
10466
|
if (userContext !== void 0) {
|
|
10325
|
-
const userFile =
|
|
10467
|
+
const userFile = join16(userDir, userContext.file);
|
|
10326
10468
|
if (await fileNonEmpty(userFile)) candidates.push(this.agentsCandidate([userFile], userContext.rank));
|
|
10327
10469
|
}
|
|
10328
10470
|
if (this.spec.skills !== void 0) {
|
|
10329
|
-
await this.collectSkillsDir(
|
|
10471
|
+
await this.collectSkillsDir(join16(userDir, this.spec.skills.userDir), this.spec.skills.userRank, candidates);
|
|
10330
10472
|
}
|
|
10331
10473
|
if (this.control.signal.aborted) return [];
|
|
10332
10474
|
return candidates;
|
|
@@ -10386,11 +10528,11 @@ var AgentsMdSkillProvider = class {
|
|
|
10386
10528
|
return;
|
|
10387
10529
|
}
|
|
10388
10530
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
10389
|
-
const entryPath =
|
|
10531
|
+
const entryPath = join16(skillsDir, entry.name);
|
|
10390
10532
|
const info = await stat3(entryPath).catch(() => void 0);
|
|
10391
10533
|
if (info === void 0) continue;
|
|
10392
10534
|
if (info.isDirectory()) {
|
|
10393
|
-
const path =
|
|
10535
|
+
const path = join16(entryPath, "SKILL.md");
|
|
10394
10536
|
const parsed2 = await this.tryParse(path);
|
|
10395
10537
|
if (parsed2 === void 0) continue;
|
|
10396
10538
|
candidates.push(this.skillCandidate(parsed2, path, rank, entryPath));
|
|
@@ -10436,7 +10578,7 @@ var CODEX_SPEC = {
|
|
|
10436
10578
|
name: "codex",
|
|
10437
10579
|
agentsMdDescription: "Codex project/user instructions (AGENTS.md)",
|
|
10438
10580
|
contextPolicy: CODEX_CONTEXT_POLICY,
|
|
10439
|
-
userDir: () =>
|
|
10581
|
+
userDir: () => join17(homedir7(), ".codex"),
|
|
10440
10582
|
projectRank: CODEX_PROJECT_RANK,
|
|
10441
10583
|
userContext: { file: "AGENTS.md", rank: CODEX_USER_RANK }
|
|
10442
10584
|
};
|
|
@@ -10448,7 +10590,7 @@ var CodexSkillProvider = class extends AgentsMdSkillProvider {
|
|
|
10448
10590
|
|
|
10449
10591
|
// src/engine-pi/skills.ts
|
|
10450
10592
|
import { homedir as homedir8 } from "node:os";
|
|
10451
|
-
import { join as
|
|
10593
|
+
import { join as join18, resolve as resolve3 } from "node:path";
|
|
10452
10594
|
var PI_AGENTS_PROJECT_RANK = 140;
|
|
10453
10595
|
var PI_SKILL_PROJECT_RANK = 150;
|
|
10454
10596
|
var PI_AGENTS_USER_RANK = 160;
|
|
@@ -10460,7 +10602,7 @@ var PI_CONTEXT_POLICY = {
|
|
|
10460
10602
|
function piAgentDir2() {
|
|
10461
10603
|
const override = process.env.PI_CODING_AGENT_DIR;
|
|
10462
10604
|
if (override !== void 0 && override.length > 0) return resolve3(override);
|
|
10463
|
-
return
|
|
10605
|
+
return join18(homedir8(), ".pi", "agent");
|
|
10464
10606
|
}
|
|
10465
10607
|
var PI_SPEC = {
|
|
10466
10608
|
name: "pi",
|
|
@@ -10484,7 +10626,7 @@ var PiSkillProvider = class extends AgentsMdSkillProvider {
|
|
|
10484
10626
|
|
|
10485
10627
|
// src/engine-kimi/skills.ts
|
|
10486
10628
|
import { homedir as homedir9 } from "node:os";
|
|
10487
|
-
import { join as
|
|
10629
|
+
import { join as join19, resolve as resolve4 } from "node:path";
|
|
10488
10630
|
var KIMI_AGENTS_PROJECT_RANK = 140;
|
|
10489
10631
|
var KIMI_SKILL_PROJECT_RANK = 150;
|
|
10490
10632
|
var KIMI_SKILL_USER_RANK = 160;
|
|
@@ -10494,7 +10636,7 @@ var KIMI_CONTEXT_POLICY = {
|
|
|
10494
10636
|
function kimiAgentDir() {
|
|
10495
10637
|
const override = process.env.KIMI_CODE_HOME;
|
|
10496
10638
|
if (override !== void 0 && override.length > 0) return resolve4(override);
|
|
10497
|
-
return
|
|
10639
|
+
return join19(homedir9(), ".kimi-code");
|
|
10498
10640
|
}
|
|
10499
10641
|
var KIMI_SPEC = {
|
|
10500
10642
|
name: "kimi",
|
|
@@ -11113,15 +11255,15 @@ function handoverOf(handle) {
|
|
|
11113
11255
|
}
|
|
11114
11256
|
|
|
11115
11257
|
// src/session-engine-store.ts
|
|
11116
|
-
import { mkdirSync as mkdirSync2, readFileSync as
|
|
11258
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync4, renameSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
11117
11259
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
11118
|
-
import { dirname as dirname6, join as
|
|
11260
|
+
import { dirname as dirname6, join as join20 } from "node:path";
|
|
11119
11261
|
import { resolveDshHome } from "@deepseek-ai/dsh-home-paths";
|
|
11120
11262
|
var ENGINE_RECORD_DIR = ".loop-engine";
|
|
11121
11263
|
var ENGINE_RECORD_FILE = "engines.json";
|
|
11122
11264
|
var ENGINE_RECORD_VERSION = 1;
|
|
11123
11265
|
function resolveEngineRecordPath() {
|
|
11124
|
-
return
|
|
11266
|
+
return join20(resolveDshHome(), ENGINE_RECORD_DIR, ENGINE_RECORD_FILE);
|
|
11125
11267
|
}
|
|
11126
11268
|
function isMissing(error) {
|
|
11127
11269
|
return error?.code === "ENOENT";
|
|
@@ -11195,7 +11337,7 @@ var SessionEngineStore = class {
|
|
|
11195
11337
|
read() {
|
|
11196
11338
|
let text;
|
|
11197
11339
|
try {
|
|
11198
|
-
text =
|
|
11340
|
+
text = readFileSync4(this.path, "utf8");
|
|
11199
11341
|
} catch (error) {
|
|
11200
11342
|
if (isMissing(error)) return /* @__PURE__ */ new Map();
|
|
11201
11343
|
return this.degrade(`could not read "${this.path}": ${String(error)}`);
|
|
@@ -11276,7 +11418,7 @@ var Config11 = z12.object({
|
|
|
11276
11418
|
});
|
|
11277
11419
|
function resolvePatchPath(config) {
|
|
11278
11420
|
if (config.patchPath !== void 0 && config.patchPath !== "") return config.patchPath;
|
|
11279
|
-
return
|
|
11421
|
+
return join21(
|
|
11280
11422
|
resolveDshHome2(),
|
|
11281
11423
|
"profiles",
|
|
11282
11424
|
config.profile ?? "web",
|
|
@@ -11328,7 +11470,7 @@ async function syncManagedBlock(path) {
|
|
|
11328
11470
|
}
|
|
11329
11471
|
function readPatchFileSync(path) {
|
|
11330
11472
|
try {
|
|
11331
|
-
return
|
|
11473
|
+
return readFileSync5(path, "utf8");
|
|
11332
11474
|
} catch (error) {
|
|
11333
11475
|
if (isMissing2(error)) return "";
|
|
11334
11476
|
throw error;
|
|
@@ -11395,8 +11537,9 @@ function apply(ctx, config) {
|
|
|
11395
11537
|
}];
|
|
11396
11538
|
for (const engine of HOSTED_ENGINE_IDS) {
|
|
11397
11539
|
const descriptor = ENGINE_REGISTRY[engine];
|
|
11398
|
-
|
|
11399
|
-
|
|
11540
|
+
const boot = bootCatalog(engine);
|
|
11541
|
+
if (boot.models.length === 0) continue;
|
|
11542
|
+
routes.push({ label: engine, models: () => liveCatalog(engine), displayName: descriptor.label });
|
|
11400
11543
|
}
|
|
11401
11544
|
for (const route of routes) {
|
|
11402
11545
|
try {
|