@xopcai/xopc 0.0.8 → 0.0.11
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/extensions/telegram/src/plugin.js +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +2 -2
- package/dist/extensions/weixin/src/plugin.js +1 -1
- package/dist/gateway/static/root/assets/{agents-BSNzJWbQ.js → agents-BdC4Y-HX.js} +2 -2
- package/dist/gateway/static/root/assets/agents-BdC4Y-HX.js.map +1 -0
- package/dist/gateway/static/root/assets/{apps-page-BKk9SB4D.js → apps-page-C-oaSHkm.js} +2 -2
- package/dist/gateway/static/root/assets/{apps-page-BKk9SB4D.js.map → apps-page-C-oaSHkm.js.map} +1 -1
- package/dist/gateway/static/root/assets/attachment-load-BDDlItdE.js +1 -0
- package/dist/gateway/static/root/assets/{channels-settings-_J6cQN6G.js → channels-settings-BqEUppPO.js} +2 -2
- package/dist/gateway/static/root/assets/{channels-settings-_J6cQN6G.js.map → channels-settings-BqEUppPO.js.map} +1 -1
- package/dist/gateway/static/root/assets/{chat-agents-api-DPb_0O8M.js → chat-agents-api-BhqjQ7iL.js} +2 -2
- package/dist/gateway/static/root/assets/{chat-agents-api-DPb_0O8M.js.map → chat-agents-api-BhqjQ7iL.js.map} +1 -1
- package/dist/gateway/static/root/assets/{cron-page-BUJOuuKX.js → cron-page-Cli49RKR.js} +2 -2
- package/dist/gateway/static/root/assets/{cron-page-BUJOuuKX.js.map → cron-page-Cli49RKR.js.map} +1 -1
- package/dist/gateway/static/root/assets/{cron-utils-Cn0YVg8x.js → cron-utils-Dkj-Ldpf.js} +2 -2
- package/dist/gateway/static/root/assets/{cron-utils-Cn0YVg8x.js.map → cron-utils-Dkj-Ldpf.js.map} +1 -1
- package/dist/gateway/static/root/assets/{electron-env-D9bm1FIu.js → electron-env-BDtJw9AY.js} +2 -2
- package/dist/gateway/static/root/assets/{electron-env-D9bm1FIu.js.map → electron-env-BDtJw9AY.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-DTz4O5Ua.js → extension-debug-page-BMcZlaxF.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-debug-page-DTz4O5Ua.js.map → extension-debug-page-BMcZlaxF.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-iframe-host-Cs1Kde9o.js → extension-iframe-host-D5HEF0KR.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-iframe-host-Cs1Kde9o.js.map → extension-iframe-host-D5HEF0KR.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-G52iX0Bo.js → extension-page-CXdCSSPl.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-page-G52iX0Bo.js.map → extension-page-CXdCSSPl.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-provider-CO2jxBA9.js → extension-provider-DZCZgQE2.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-provider-CO2jxBA9.js.map → extension-provider-DZCZgQE2.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-D9Ul8uSt.js → extension-settings-page-CX6STpx3.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-settings-page-D9Ul8uSt.js.map → extension-settings-page-CX6STpx3.js.map} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-Bc8SVD15.js → gateway-config-swr-Cph02QZn.js} +2 -2
- package/dist/gateway/static/root/assets/{gateway-config-swr-Bc8SVD15.js.map → gateway-config-swr-Cph02QZn.js.map} +1 -1
- package/dist/gateway/static/root/assets/index-Bty3m0mS.css +2 -0
- package/dist/gateway/static/root/assets/{index-BXUJbteW.js → index-iTUyfzNr.js} +10 -10
- package/dist/gateway/static/root/assets/index-iTUyfzNr.js.map +1 -0
- package/dist/gateway/static/root/assets/{logs-page-5V25JkQY.js → logs-page-B9O5l3I8.js} +2 -2
- package/dist/gateway/static/root/assets/{logs-page-5V25JkQY.js.map → logs-page-B9O5l3I8.js.map} +1 -1
- package/dist/gateway/static/root/assets/{model-selector-he3aQfme.js → model-selector-BLiY_O25.js} +2 -2
- package/dist/gateway/static/root/assets/{model-selector-he3aQfme.js.map → model-selector-BLiY_O25.js.map} +1 -1
- package/dist/gateway/static/root/assets/page-header-store-BFpnFTed.js +2 -0
- package/dist/gateway/static/root/assets/{page-header-store-DJHD9Ean.js.map → page-header-store-BFpnFTed.js.map} +1 -1
- package/dist/gateway/static/root/assets/{session-api-n-4O5d9U.js → session-api-DEhQXWJg.js} +2 -2
- package/dist/gateway/static/root/assets/{session-api-n-4O5d9U.js.map → session-api-DEhQXWJg.js.map} +1 -1
- package/dist/gateway/static/root/assets/{session-working-directory-control-B6dHLvbr.js → session-working-directory-control-DKOtWs3-.js} +2 -2
- package/dist/gateway/static/root/assets/{session-working-directory-control-B6dHLvbr.js.map → session-working-directory-control-DKOtWs3-.js.map} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-rBUfTdm3.js → sessions-page-BYlWP1ep.js} +2 -2
- package/dist/gateway/static/root/assets/{sessions-page-rBUfTdm3.js.map → sessions-page-BYlWP1ep.js.map} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-B3QrJm-E.js → settings-page-oCnIavdg.js} +2 -2
- package/dist/gateway/static/root/assets/settings-page-oCnIavdg.js.map +1 -0
- package/dist/gateway/static/root/assets/{skill-api-vxtE8kI6.js → skill-api-DWrn8Az0.js} +2 -2
- package/dist/gateway/static/root/assets/{skill-api-vxtE8kI6.js.map → skill-api-DWrn8Az0.js.map} +1 -1
- package/dist/gateway/static/root/assets/{skills-page-D36_O2Ub.js → skills-page-C59WQpM1.js} +2 -2
- package/dist/gateway/static/root/assets/{skills-page-D36_O2Ub.js.map → skills-page-C59WQpM1.js.map} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-CmiSsYBd.js → theme-store-CywXkKml.js} +2 -2
- package/dist/gateway/static/root/assets/{theme-store-CmiSsYBd.js.map → theme-store-CywXkKml.js.map} +1 -1
- package/dist/gateway/static/root/assets/url-D7yWllI8.js +2 -0
- package/dist/gateway/static/root/assets/url-D7yWllI8.js.map +1 -0
- package/dist/gateway/static/root/assets/{useTranslation-DYORQ7x6.js → useTranslation-CACj0DBJ.js} +2 -2
- package/dist/gateway/static/root/assets/{useTranslation-DYORQ7x6.js.map → useTranslation-CACj0DBJ.js.map} +1 -1
- package/dist/gateway/static/root/index.html +15 -15
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +1 -0
- package/dist/src/agent/agent-manager.js +20 -12
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/background-review/run-background-review.js +2 -0
- package/dist/src/agent/background-review/run-background-review.js.map +1 -1
- package/dist/src/agent/child-agent-factory.js +2 -0
- package/dist/src/agent/child-agent-factory.js.map +1 -1
- package/dist/src/agent/context/expand-at-file-mentions.d.ts +4 -0
- package/dist/src/agent/context/expand-at-file-mentions.js +69 -0
- package/dist/src/agent/context/expand-at-file-mentions.js.map +1 -0
- package/dist/src/agent/context/workspace-seed.js +1 -1
- package/dist/src/agent/image/understanding/pi-ai-provider.js.map +1 -1
- package/dist/src/agent/ipc/bus.js +1 -1
- package/dist/src/agent/ipc/inbox.js +1 -1
- package/dist/src/agent/ipc/socket.js +1 -1
- package/dist/src/agent/memory/compaction.d.ts +1 -1
- package/dist/src/agent/memory/compaction.js +38 -11
- package/dist/src/agent/memory/compaction.js.map +1 -1
- package/dist/src/agent/messaging/command-handler.d.ts +13 -0
- package/dist/src/agent/messaging/command-handler.js +14 -2
- package/dist/src/agent/messaging/command-handler.js.map +1 -1
- package/dist/src/agent/models/manager.js +1 -1
- package/dist/src/agent/orchestration/agent-orchestrator.js +6 -1
- package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +1 -1
- package/dist/src/agent/service.d.ts +16 -1
- package/dist/src/agent/service.js +178 -20
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/skills/format-skills-prompt.js.map +1 -1
- package/dist/src/agent/skills/index.js +1 -1
- package/dist/src/agent/skills/scanner.js +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js.map +1 -1
- package/dist/src/agent/skills/skill-manager.js +1 -1
- package/dist/src/agent/tools/browser/tools.js.map +1 -1
- package/dist/src/agent/tools/factory.js +1 -1
- package/dist/src/agent/tools/image-tool.js.map +1 -1
- package/dist/src/agent/tools/send-media.js +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js +1 -1
- package/dist/src/agent/tools/write.js +1 -1
- package/dist/src/auth/credentials.js +2 -2
- package/dist/src/auth/sync-provider-auth.js +1 -1
- package/dist/src/channels/attachments/inbound-persist.js +1 -1
- package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
- package/dist/src/channels/index.d.ts +1 -1
- package/dist/src/channels/index.js +2 -2
- package/dist/src/channels/pipeline.d.ts +8 -1
- package/dist/src/channels/pipeline.js +49 -4
- package/dist/src/channels/pipeline.js.map +1 -1
- package/dist/src/chat-commands/builtins/config.d.ts +4 -0
- package/dist/src/chat-commands/builtins/config.js +197 -0
- package/dist/src/chat-commands/builtins/config.js.map +1 -0
- package/dist/src/chat-commands/builtins/context.d.ts +4 -0
- package/dist/src/chat-commands/builtins/context.js +44 -0
- package/dist/src/chat-commands/builtins/context.js.map +1 -0
- package/dist/src/chat-commands/builtins/session.js +111 -0
- package/dist/src/chat-commands/builtins/session.js.map +1 -1
- package/dist/src/chat-commands/builtins/thinking.js +49 -21
- package/dist/src/chat-commands/builtins/thinking.js.map +1 -1
- package/dist/src/chat-commands/config-paths.d.ts +10 -0
- package/dist/src/chat-commands/config-paths.js +45 -0
- package/dist/src/chat-commands/config-paths.js.map +1 -0
- package/dist/src/chat-commands/config-value.d.ts +12 -0
- package/dist/src/chat-commands/config-value.js +53 -0
- package/dist/src/chat-commands/config-value.js.map +1 -0
- package/dist/src/chat-commands/context.d.ts +24 -1
- package/dist/src/chat-commands/context.js +41 -0
- package/dist/src/chat-commands/context.js.map +1 -1
- package/dist/src/chat-commands/index.d.ts +2 -0
- package/dist/src/chat-commands/index.js +5 -1
- package/dist/src/chat-commands/index.js.map +1 -1
- package/dist/src/chat-commands/types.d.ts +33 -1
- package/dist/src/cli/commands/agent/interactive.js +1 -1
- package/dist/src/cli/commands/agent/interactive.js.map +1 -1
- package/dist/src/cli/commands/agent.js +22 -10
- package/dist/src/cli/commands/agent.js.map +1 -1
- package/dist/src/cli/commands/auth.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
- package/dist/src/cli/commands/extension.js +10 -0
- package/dist/src/cli/commands/extension.js.map +1 -1
- package/dist/src/cli/commands/init.js +3 -4
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/session/utils.js.map +1 -1
- package/dist/src/cli/commands/update.d.ts +1 -0
- package/dist/src/cli/commands/update.js +171 -0
- package/dist/src/cli/commands/update.js.map +1 -0
- package/dist/src/cli/index.d.ts +1 -1
- package/dist/src/cli/index.js +3 -1
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/config/index.d.ts +1 -0
- package/dist/src/config/index.js +5 -4
- package/dist/src/config/index.js.map +1 -1
- package/dist/src/config/loader.js +1 -1
- package/dist/src/config/models-json.js +1 -1
- package/dist/src/config/paths.js.map +1 -1
- package/dist/src/config/profile.js +2 -2
- package/dist/src/config/runtime-overrides.d.ts +8 -0
- package/dist/src/config/runtime-overrides.js +40 -0
- package/dist/src/config/runtime-overrides.js.map +1 -0
- package/dist/src/config/schema.d.ts +35 -0
- package/dist/src/config/schema.js +19 -3
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/cron/executor.js +2 -2
- package/dist/src/cron/persistence.js +1 -1
- package/dist/src/cron/run-log-store.js +1 -1
- package/dist/src/extensions/health.js +1 -1
- package/dist/src/extensions/loader.d.ts +1 -1
- package/dist/src/extensions/loader.js +6 -9
- package/dist/src/extensions/loader.js.map +1 -1
- package/dist/src/extensions/lockfile.js +1 -1
- package/dist/src/extensions/sdk/index.js +6 -1
- package/dist/src/extensions/sdk/index.js.map +1 -0
- package/dist/src/gateway/agents-admin.js +2 -2
- package/dist/src/gateway/agents-admin.js.map +1 -1
- package/dist/src/gateway/hono/oauth.js +1 -1
- package/dist/src/gateway/hono/routes/config.js +1 -1
- package/dist/src/gateway/hono/routes/index.js +2 -0
- package/dist/src/gateway/hono/routes/index.js.map +1 -1
- package/dist/src/gateway/hono/routes/models.js +64 -11
- package/dist/src/gateway/hono/routes/models.js.map +1 -1
- package/dist/src/gateway/hono/routes/public-gateway.js +10 -0
- package/dist/src/gateway/hono/routes/public-gateway.js.map +1 -1
- package/dist/src/gateway/hono/routes/update.d.ts +3 -0
- package/dist/src/gateway/hono/routes/update.js +141 -0
- package/dist/src/gateway/hono/routes/update.js.map +1 -0
- package/dist/src/gateway/hono/routes/workspace.js +84 -4
- package/dist/src/gateway/hono/routes/workspace.js.map +1 -1
- package/dist/src/gateway/hono/sse.js +2 -2
- package/dist/src/gateway/service.d.ts +1 -0
- package/dist/src/gateway/service.js +16 -4
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/workspace-fs-file-list.d.ts +5 -0
- package/dist/src/gateway/workspace-fs-file-list.js +56 -0
- package/dist/src/gateway/workspace-fs-file-list.js.map +1 -0
- package/dist/src/gateway/workspace-heartbeat-path.js +1 -1
- package/dist/src/gateway/workspace-ripgrep.d.ts +5 -0
- package/dist/src/gateway/workspace-ripgrep.js +88 -4
- package/dist/src/gateway/workspace-ripgrep.js.map +1 -1
- package/dist/src/infra/update-channels.d.ts +14 -0
- package/dist/src/infra/update-channels.js +30 -0
- package/dist/src/infra/update-channels.js.map +1 -0
- package/dist/src/infra/update-check.d.ts +53 -0
- package/dist/src/infra/update-check.js +155 -0
- package/dist/src/infra/update-check.js.map +1 -0
- package/dist/src/infra/update-runner.d.ts +18 -0
- package/dist/src/infra/update-runner.js +112 -0
- package/dist/src/infra/update-runner.js.map +1 -0
- package/dist/src/infra/update-startup.d.ts +20 -0
- package/dist/src/infra/update-startup.js +246 -0
- package/dist/src/infra/update-startup.js.map +1 -0
- package/dist/src/providers/extension-stream-bridge.d.ts +3 -0
- package/dist/src/providers/extension-stream-bridge.js +239 -0
- package/dist/src/providers/extension-stream-bridge.js.map +1 -0
- package/dist/src/providers/index.d.ts +7 -2
- package/dist/src/providers/index.js +77 -14
- package/dist/src/providers/index.js.map +1 -1
- package/dist/src/providers/model-registry.js +1 -1
- package/dist/src/providers/plugin-registry.js +92 -87
- package/dist/src/providers/plugin-registry.js.map +1 -1
- package/dist/src/session/chat-export.d.ts +5 -0
- package/dist/src/session/chat-export.js +35 -0
- package/dist/src/session/chat-export.js.map +1 -0
- package/dist/src/session/config-store.js +1 -1
- package/dist/src/session/manager.d.ts +1 -1
- package/dist/src/session/manager.js +2 -2
- package/dist/src/session/manager.js.map +1 -1
- package/dist/src/session/session-title.js +1 -1
- package/dist/src/session/store.d.ts +1 -1
- package/dist/src/session/store.js +5 -5
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/utils/logger/audit.js +1 -1
- package/dist/src/utils/logger/log-store.js +1 -1
- package/dist/src/utils/logger/rotation.js +1 -1
- package/dist/src/voice/tts/audio.js +1 -1
- package/package.json +2 -1
- package/dist/gateway/static/root/assets/agents-BSNzJWbQ.js.map +0 -1
- package/dist/gateway/static/root/assets/attachment-load-DXcJLSWT.js +0 -1
- package/dist/gateway/static/root/assets/index-BXUJbteW.js.map +0 -1
- package/dist/gateway/static/root/assets/index-CQLMxWSA.css +0 -2
- package/dist/gateway/static/root/assets/page-header-store-DJHD9Ean.js +0 -2
- package/dist/gateway/static/root/assets/settings-page-B3QrJm-E.js.map +0 -1
- package/dist/gateway/static/root/assets/url-CtSqjF9J.js +0 -2
- package/dist/gateway/static/root/assets/url-CtSqjF9J.js.map +0 -1
|
@@ -2,12 +2,31 @@ import { resolveModelsJsonPath } from "../../../config/paths.js";
|
|
|
2
2
|
import { init_resolve_config_value, testApiKeyResolution } from "../../../config/resolve-config-value.js";
|
|
3
3
|
import { init_models_json, loadModelsJson, saveModelsJson, validateModelsConfig } from "../../../config/models-json.js";
|
|
4
4
|
import { getModelRegistry } from "../../../providers/model-registry.js";
|
|
5
|
+
import { getProviderRegistry, init_plugin_registry } from "../../../providers/plugin-registry.js";
|
|
5
6
|
import { PROVIDER_META, getAllModels, getAllProviders, getAvailableModels, getProviderActiveKeySource, init_providers, isProviderConfigured } from "../../../providers/index.js";
|
|
6
7
|
import { listImageGenerationProvidersSummary } from "../../../agent/image/generation/runtime.js";
|
|
7
8
|
//#region src/gateway/hono/routes/models.ts
|
|
8
9
|
init_models_json();
|
|
9
10
|
init_resolve_config_value();
|
|
10
11
|
init_providers();
|
|
12
|
+
init_plugin_registry();
|
|
13
|
+
function mapPluginModel(providerId, model, available) {
|
|
14
|
+
return {
|
|
15
|
+
id: `${providerId}/${model.id}`,
|
|
16
|
+
name: model.name,
|
|
17
|
+
provider: providerId,
|
|
18
|
+
contextWindow: model.contextWindow ?? 128e3,
|
|
19
|
+
maxTokens: model.maxOutputTokens ?? 4096,
|
|
20
|
+
reasoning: false,
|
|
21
|
+
vision: model.supportsImages ?? false,
|
|
22
|
+
cost: {
|
|
23
|
+
input: model.pricing?.input ?? 0,
|
|
24
|
+
output: model.pricing?.output ?? 0
|
|
25
|
+
},
|
|
26
|
+
available,
|
|
27
|
+
source: "extension"
|
|
28
|
+
};
|
|
29
|
+
}
|
|
11
30
|
function registerModelsRoutes(authenticated, deps) {
|
|
12
31
|
const { service } = deps;
|
|
13
32
|
authenticated.get("/api/models-json", async (c) => {
|
|
@@ -76,6 +95,7 @@ function registerModelsRoutes(authenticated, deps) {
|
|
|
76
95
|
});
|
|
77
96
|
});
|
|
78
97
|
authenticated.get("/api/models", async (c) => {
|
|
98
|
+
const pluginRegistry = getProviderRegistry();
|
|
79
99
|
const models = (await getAvailableModels()).map((m) => ({
|
|
80
100
|
id: `${m.provider}/${m.id}`,
|
|
81
101
|
name: m.name,
|
|
@@ -87,8 +107,17 @@ function registerModelsRoutes(authenticated, deps) {
|
|
|
87
107
|
cost: {
|
|
88
108
|
input: m.cost?.input ?? 0,
|
|
89
109
|
output: m.cost?.output ?? 0
|
|
90
|
-
}
|
|
110
|
+
},
|
|
111
|
+
...pluginRegistry.has(m.provider) ? { source: "extension" } : {}
|
|
91
112
|
}));
|
|
113
|
+
const existingIds = new Set(models.map((m) => m.id));
|
|
114
|
+
for (const plugin of pluginRegistry.listAll()) for (const model of plugin.models) {
|
|
115
|
+
const compositeId = `${plugin.id}/${model.id}`;
|
|
116
|
+
if (!existingIds.has(compositeId)) {
|
|
117
|
+
models.push(mapPluginModel(plugin.id, model, true));
|
|
118
|
+
existingIds.add(compositeId);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
92
121
|
models.sort((a, b) => {
|
|
93
122
|
if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);
|
|
94
123
|
return a.name.localeCompare(b.name);
|
|
@@ -106,6 +135,7 @@ function registerModelsRoutes(authenticated, deps) {
|
|
|
106
135
|
});
|
|
107
136
|
});
|
|
108
137
|
authenticated.get("/api/providers", async (c) => {
|
|
138
|
+
const pluginRegistry = getProviderRegistry();
|
|
109
139
|
const allModels = getAllModels();
|
|
110
140
|
const availableModels = await getAvailableModels();
|
|
111
141
|
const configured = new Set(availableModels.map((m) => `${m.provider}/${m.id}`));
|
|
@@ -121,8 +151,17 @@ function registerModelsRoutes(authenticated, deps) {
|
|
|
121
151
|
input: m.cost?.input ?? 0,
|
|
122
152
|
output: m.cost?.output ?? 0
|
|
123
153
|
},
|
|
124
|
-
available: configured.has(`${m.provider}/${m.id}`)
|
|
154
|
+
available: configured.has(`${m.provider}/${m.id}`),
|
|
155
|
+
...pluginRegistry.has(m.provider) ? { source: "extension" } : {}
|
|
125
156
|
}));
|
|
157
|
+
const existingIds = new Set(models.map((m) => m.id));
|
|
158
|
+
for (const plugin of pluginRegistry.listAll()) for (const model of plugin.models) {
|
|
159
|
+
const compositeId = `${plugin.id}/${model.id}`;
|
|
160
|
+
if (!existingIds.has(compositeId)) {
|
|
161
|
+
models.push(mapPluginModel(plugin.id, model, configured.has(compositeId)));
|
|
162
|
+
existingIds.add(compositeId);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
126
165
|
models.sort((a, b) => {
|
|
127
166
|
if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);
|
|
128
167
|
return a.name.localeCompare(b.name);
|
|
@@ -134,15 +173,29 @@ function registerModelsRoutes(authenticated, deps) {
|
|
|
134
173
|
});
|
|
135
174
|
authenticated.get("/api/providers/meta", async (c) => {
|
|
136
175
|
const providers = getAllProviders();
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
176
|
+
const pluginRegistry = getProviderRegistry();
|
|
177
|
+
const meta = await Promise.all(providers.map(async (provider) => {
|
|
178
|
+
const plugin = pluginRegistry.get(provider);
|
|
179
|
+
return {
|
|
180
|
+
id: provider,
|
|
181
|
+
name: plugin?.name ?? PROVIDER_META[provider]?.name ?? provider,
|
|
182
|
+
category: plugin ? "extension" : PROVIDER_META[provider]?.category || "specialty",
|
|
183
|
+
supportsOAuth: plugin ? false : PROVIDER_META[provider]?.supportsOAuth ?? false,
|
|
184
|
+
supportsApiKey: plugin ? true : PROVIDER_META[provider]?.supportsApiKey ?? true,
|
|
185
|
+
configured: await isProviderConfigured(provider),
|
|
186
|
+
activeKeySource: await getProviderActiveKeySource(provider)
|
|
187
|
+
};
|
|
188
|
+
}));
|
|
189
|
+
const knownProviderIds = new Set(providers);
|
|
190
|
+
for (const plugin of pluginRegistry.listAll()) if (!knownProviderIds.has(plugin.id)) meta.push({
|
|
191
|
+
id: plugin.id,
|
|
192
|
+
name: plugin.name,
|
|
193
|
+
category: "extension",
|
|
194
|
+
supportsOAuth: false,
|
|
195
|
+
supportsApiKey: true,
|
|
196
|
+
configured: true,
|
|
197
|
+
activeKeySource: "extension"
|
|
198
|
+
});
|
|
146
199
|
return c.json({
|
|
147
200
|
ok: true,
|
|
148
201
|
payload: { providers: meta }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"models.js","names":["getModelsJsonPath"],"sources":["../../../../../src/gateway/hono/routes/models.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport {\n getModelsJsonPath,\n loadModelsJson,\n saveModelsJson,\n validateModelsConfig,\n} from '../../../config/models-json.js';\nimport { testApiKeyResolution } from '../../../config/resolve-config-value.js';\nimport { listImageGenerationProvidersSummary } from '../../../agent/image/generation/runtime.js';\nimport {\n getAllModels,\n getAvailableModels,\n getModelRegistry,\n getAllProviders,\n getProviderActiveKeySource,\n isProviderConfigured,\n PROVIDER_META,\n} from '../../../providers/index.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nexport function registerModelsRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n\n // GET /api/models-json - Get models.json configuration\n authenticated.get('/api/models-json', async (c) => {\n const path = getModelsJsonPath();\n const { config, error } = loadModelsJson(path);\n const registry = getModelRegistry();\n \n return c.json({\n ok: true,\n payload: {\n config,\n path,\n exists: error === undefined,\n loadError: error || registry.getError(),\n },\n });\n });\n\n // POST /api/models-json/validate - Validate models.json configuration\n authenticated.post('/api/models-json/validate', async (c) => {\n const body = await c.req.json();\n const { config } = body;\n \n const result = validateModelsConfig(config);\n \n return c.json({\n ok: true,\n payload: result,\n });\n });\n\n // PATCH /api/models-json - Save models.json configuration\n authenticated.patch('/api/models-json', async (c) => {\n const body = await c.req.json();\n const { config } = body;\n \n const path = getModelsJsonPath();\n const result = saveModelsJson(path, config);\n \n if (!result.success) {\n return c.json({ ok: false, error: result.error }, 400);\n }\n \n // Refresh registry\n const registry = getModelRegistry();\n registry.refresh();\n \n // Emit event\n service.emit('models-json.updated', { \n modelCount: registry.getAll().length,\n });\n \n return c.json({ \n ok: true, \n payload: { \n saved: true,\n modelCount: registry.getAll().length,\n },\n });\n });\n\n // POST /api/models-json/reload - Hot reload models.json\n authenticated.post('/api/models-json/reload', async (c) => {\n const registry = getModelRegistry();\n registry.refresh();\n \n const error = registry.getError();\n const models = registry.getAll();\n \n service.emit('models-json.reloaded', { \n modelCount: models.length,\n error: error || undefined,\n });\n \n return c.json({\n ok: true,\n payload: {\n modelCount: models.length,\n error,\n },\n });\n });\n\n // POST /api/models-json/test-api-key - Test API key resolution\n authenticated.post('/api/models-json/test-api-key', async (c) => {\n const body = await c.req.json();\n const { value } = body;\n \n const result = testApiKeyResolution(value);\n \n return c.json({\n ok: true,\n payload: result,\n });\n });\n\n // GET /api/models - Get available models (only configured providers)\n authenticated.get('/api/models', async (c) => {\n const models = (await getAvailableModels()).map(m => ({\n id: `${m.provider}/${m.id}`,\n name: m.name,\n provider: m.provider,\n contextWindow: m.contextWindow ?? 128000,\n maxTokens: m.maxTokens ?? 4096,\n reasoning: m.reasoning ?? false,\n vision: m.input?.includes('image') ?? false,\n cost: {\n input: m.cost?.input ?? 0,\n output: m.cost?.output ?? 0,\n },\n }));\n\n // Sort by provider then name\n models.sort((a, b) => {\n if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);\n return a.name.localeCompare(b.name);\n });\n\n return c.json({ ok: true, payload: { models } });\n });\n\n // GET /api/image/providers — registered image generation providers and models (not in LLM model registry)\n authenticated.get('/api/image/providers', (c) => {\n const providers = listImageGenerationProvidersSummary();\n return c.json({ ok: true, payload: { providers } });\n });\n\n // GET /api/providers - Get ALL available providers and models\n authenticated.get('/api/providers', async (c) => {\n const allModels = getAllModels();\n const availableModels = await getAvailableModels();\n const configured = new Set(availableModels.map(m => `${m.provider}/${m.id}`));\n \n const models = allModels.map(m => ({\n id: `${m.provider}/${m.id}`,\n name: m.name,\n provider: m.provider,\n contextWindow: m.contextWindow ?? 128000,\n maxTokens: m.maxTokens ?? 4096,\n reasoning: m.reasoning ?? false,\n vision: m.input?.includes('image') ?? false,\n cost: {\n input: m.cost?.input ?? 0,\n output: m.cost?.output ?? 0,\n },\n available: configured.has(`${m.provider}/${m.id}`),\n }));\n\n // Sort by provider then name\n models.sort((a, b) => {\n if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);\n return a.name.localeCompare(b.name);\n });\n\n return c.json({ ok: true, payload: { models } });\n });\n\n // GET /api/providers/meta - Get provider metadata (categories, display names)\n authenticated.get('/api/providers/meta', async (c) => {\n const providers = getAllProviders();\n \n const meta = await Promise.all(\n providers.map(async (provider) => ({\n id: provider,\n name: PROVIDER_META[provider]?.name || provider,\n category: PROVIDER_META[provider]?.category || 'specialty',\n supportsOAuth: PROVIDER_META[provider]?.supportsOAuth ?? false,\n supportsApiKey: PROVIDER_META[provider]?.supportsApiKey ?? true,\n configured: await isProviderConfigured(provider),\n activeKeySource: await getProviderActiveKeySource(provider),\n })),\n );\n\n return c.json({ ok: true, payload: { providers: meta } });\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"models.js","names":["getModelsJsonPath"],"sources":["../../../../../src/gateway/hono/routes/models.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport {\n getModelsJsonPath,\n loadModelsJson,\n saveModelsJson,\n validateModelsConfig,\n} from '../../../config/models-json.js';\nimport { testApiKeyResolution } from '../../../config/resolve-config-value.js';\nimport { listImageGenerationProvidersSummary } from '../../../agent/image/generation/runtime.js';\nimport {\n getAllModels,\n getAvailableModels,\n getModelRegistry,\n getAllProviders,\n getProviderActiveKeySource,\n isProviderConfigured,\n PROVIDER_META,\n} from '../../../providers/index.js';\nimport { getProviderRegistry } from '../../../providers/plugin-registry.js';\nimport type { ProviderModelDefinition } from '../../../extensions/types/providers.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nfunction mapPluginModel(providerId: string, model: ProviderModelDefinition, available: boolean) {\n return {\n id: `${providerId}/${model.id}`,\n name: model.name,\n provider: providerId,\n contextWindow: model.contextWindow ?? 128000,\n maxTokens: model.maxOutputTokens ?? 4096,\n reasoning: false,\n vision: model.supportsImages ?? false,\n cost: { input: model.pricing?.input ?? 0, output: model.pricing?.output ?? 0 },\n available,\n source: 'extension' as const,\n };\n}\n\nexport function registerModelsRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n\n // GET /api/models-json - Get models.json configuration\n authenticated.get('/api/models-json', async (c) => {\n const path = getModelsJsonPath();\n const { config, error } = loadModelsJson(path);\n const registry = getModelRegistry();\n \n return c.json({\n ok: true,\n payload: {\n config,\n path,\n exists: error === undefined,\n loadError: error || registry.getError(),\n },\n });\n });\n\n // POST /api/models-json/validate - Validate models.json configuration\n authenticated.post('/api/models-json/validate', async (c) => {\n const body = await c.req.json();\n const { config } = body;\n \n const result = validateModelsConfig(config);\n \n return c.json({\n ok: true,\n payload: result,\n });\n });\n\n // PATCH /api/models-json - Save models.json configuration\n authenticated.patch('/api/models-json', async (c) => {\n const body = await c.req.json();\n const { config } = body;\n \n const path = getModelsJsonPath();\n const result = saveModelsJson(path, config);\n \n if (!result.success) {\n return c.json({ ok: false, error: result.error }, 400);\n }\n \n // Refresh registry\n const registry = getModelRegistry();\n registry.refresh();\n \n // Emit event\n service.emit('models-json.updated', { \n modelCount: registry.getAll().length,\n });\n \n return c.json({ \n ok: true, \n payload: { \n saved: true,\n modelCount: registry.getAll().length,\n },\n });\n });\n\n // POST /api/models-json/reload - Hot reload models.json\n authenticated.post('/api/models-json/reload', async (c) => {\n const registry = getModelRegistry();\n registry.refresh();\n \n const error = registry.getError();\n const models = registry.getAll();\n \n service.emit('models-json.reloaded', { \n modelCount: models.length,\n error: error || undefined,\n });\n \n return c.json({\n ok: true,\n payload: {\n modelCount: models.length,\n error,\n },\n });\n });\n\n // POST /api/models-json/test-api-key - Test API key resolution\n authenticated.post('/api/models-json/test-api-key', async (c) => {\n const body = await c.req.json();\n const { value } = body;\n \n const result = testApiKeyResolution(value);\n \n return c.json({\n ok: true,\n payload: result,\n });\n });\n\n // GET /api/models - Get available models (only configured providers)\n authenticated.get('/api/models', async (c) => {\n const pluginRegistry = getProviderRegistry();\n const models = (await getAvailableModels()).map(m => ({\n id: `${m.provider}/${m.id}`,\n name: m.name,\n provider: m.provider,\n contextWindow: m.contextWindow ?? 128000,\n maxTokens: m.maxTokens ?? 4096,\n reasoning: m.reasoning ?? false,\n vision: m.input?.includes('image') ?? false,\n cost: {\n input: m.cost?.input ?? 0,\n output: m.cost?.output ?? 0,\n },\n ...(pluginRegistry.has(m.provider) ? { source: 'extension' as const } : {}),\n }));\n\n const existingIds = new Set(models.map(m => m.id));\n for (const plugin of pluginRegistry.listAll()) {\n for (const model of plugin.models) {\n const compositeId = `${plugin.id}/${model.id}`;\n if (!existingIds.has(compositeId)) {\n models.push(mapPluginModel(plugin.id, model, true));\n existingIds.add(compositeId);\n }\n }\n }\n\n // Sort by provider then name\n models.sort((a, b) => {\n if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);\n return a.name.localeCompare(b.name);\n });\n\n return c.json({ ok: true, payload: { models } });\n });\n\n // GET /api/image/providers — registered image generation providers and models (not in LLM model registry)\n authenticated.get('/api/image/providers', (c) => {\n const providers = listImageGenerationProvidersSummary();\n return c.json({ ok: true, payload: { providers } });\n });\n\n // GET /api/providers - Get ALL available providers and models\n authenticated.get('/api/providers', async (c) => {\n const pluginRegistry = getProviderRegistry();\n const allModels = getAllModels();\n const availableModels = await getAvailableModels();\n const configured = new Set(availableModels.map(m => `${m.provider}/${m.id}`));\n\n const models = allModels.map(m => ({\n id: `${m.provider}/${m.id}`,\n name: m.name,\n provider: m.provider,\n contextWindow: m.contextWindow ?? 128000,\n maxTokens: m.maxTokens ?? 4096,\n reasoning: m.reasoning ?? false,\n vision: m.input?.includes('image') ?? false,\n cost: {\n input: m.cost?.input ?? 0,\n output: m.cost?.output ?? 0,\n },\n available: configured.has(`${m.provider}/${m.id}`),\n ...(pluginRegistry.has(m.provider) ? { source: 'extension' as const } : {}),\n }));\n\n const existingIds = new Set(models.map(m => m.id));\n for (const plugin of pluginRegistry.listAll()) {\n for (const model of plugin.models) {\n const compositeId = `${plugin.id}/${model.id}`;\n if (!existingIds.has(compositeId)) {\n models.push(mapPluginModel(plugin.id, model, configured.has(compositeId)));\n existingIds.add(compositeId);\n }\n }\n }\n\n // Sort by provider then name\n models.sort((a, b) => {\n if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);\n return a.name.localeCompare(b.name);\n });\n\n return c.json({ ok: true, payload: { models } });\n });\n\n // GET /api/providers/meta - Get provider metadata (categories, display names)\n authenticated.get('/api/providers/meta', async (c) => {\n const providers = getAllProviders();\n const pluginRegistry = getProviderRegistry();\n\n const meta = await Promise.all(\n providers.map(async (provider) => {\n const plugin = pluginRegistry.get(provider);\n return {\n id: provider,\n name: plugin?.name ?? PROVIDER_META[provider]?.name ?? provider,\n category: plugin ? ('extension' as const) : PROVIDER_META[provider]?.category || 'specialty',\n supportsOAuth: plugin ? false : (PROVIDER_META[provider]?.supportsOAuth ?? false),\n supportsApiKey: plugin ? true : (PROVIDER_META[provider]?.supportsApiKey ?? true),\n configured: await isProviderConfigured(provider),\n activeKeySource: await getProviderActiveKeySource(provider),\n };\n }),\n );\n\n const knownProviderIds = new Set(providers);\n for (const plugin of pluginRegistry.listAll()) {\n if (!knownProviderIds.has(plugin.id)) {\n meta.push({\n id: plugin.id,\n name: plugin.name,\n category: 'extension',\n supportsOAuth: false,\n supportsApiKey: true,\n configured: true,\n activeKeySource: 'extension',\n });\n }\n }\n\n return c.json({ ok: true, payload: { providers: meta } });\n });\n}\n"],"mappings":"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"}
|
|
@@ -49,6 +49,16 @@ function registerPublicGatewayRoutes(app, service) {
|
|
|
49
49
|
if (response) return response;
|
|
50
50
|
return c.text("Not found", 404);
|
|
51
51
|
});
|
|
52
|
+
app.get("/logo.svg", (c) => {
|
|
53
|
+
const response = serveStaticFile("logo.svg");
|
|
54
|
+
if (response) return response;
|
|
55
|
+
return c.text("Not found", 404);
|
|
56
|
+
});
|
|
57
|
+
app.get("/logo-dark.svg", (c) => {
|
|
58
|
+
const response = serveStaticFile("logo-dark.svg");
|
|
59
|
+
if (response) return response;
|
|
60
|
+
return c.text("Not found", 404);
|
|
61
|
+
});
|
|
52
62
|
app.get("/", (c) => {
|
|
53
63
|
const response = serveStaticFile("index.html");
|
|
54
64
|
if (response) return response;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public-gateway.js","names":[],"sources":["../../../../../src/gateway/hono/routes/public-gateway.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { PACKAGE_VERSION } from '../../../package-version.js';\nimport type { GatewayService } from '../../service.js';\nimport { serveStaticFile } from '../lib/static-ui.js';\n\nexport function registerPublicGatewayRoutes(app: Hono, service: GatewayService): void {\n app.get('/health', (c) => {\n return c.json(service.getHealth());\n });\n\n app.get('/api', (c) => {\n return c.json({\n service: 'xopc-gateway',\n version: PACKAGE_VERSION,\n transport: 'streamable-http',\n endpoints: [\n 'GET /health',\n 'GET /status',\n 'POST /api/agent (SSE stream / JSON)',\n 'POST /api/agent/abort',\n 'POST /api/agent/steer',\n 'POST /api/send',\n 'GET /api/events (SSE stream)',\n 'GET /api/channels/status',\n 'POST /api/channels/weixin/login/start',\n 'GET /api/channels/weixin/login/:sessionKey',\n 'GET /api/config',\n 'GET /api/agents',\n 'POST /api/agents',\n 'PATCH /api/agents/:id',\n 'DELETE /api/agents/:id',\n 'GET/PUT /api/agents/:id/files/...',\n 'PATCH /api/config',\n 'POST /api/config/reload',\n 'POST /api/heartbeat/trigger',\n '... /api/cron/*',\n 'GET/PATCH /api/sessions/:key/agent-config',\n '... /api/sessions/*',\n 'GET /api/host/fs/meta',\n 'GET /api/host/fs/list',\n ],\n });\n });\n\n app.get('/assets/*', (c) => {\n const path = c.req.path.replace('/assets/', '');\n const response = serveStaticFile(`assets/${path}`);\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n app.get('/favicon.ico', (c) => {\n const response = serveStaticFile('favicon.ico');\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n app.get('/', (c) => {\n const response = serveStaticFile('index.html');\n if (response) return response;\n return c.text('UI not found', 404);\n });\n}\n"],"mappings":";;;sBAE8D;AAI9D,SAAgB,4BAA4B,KAAW,SAA+B;AACpF,KAAI,IAAI,YAAY,MAAM;AACxB,SAAO,EAAE,KAAK,QAAQ,WAAW,CAAC;GAClC;AAEF,KAAI,IAAI,SAAS,MAAM;AACrB,SAAO,EAAE,KAAK;GACZ,SAAS;GACT,SAAS;GACT,WAAW;GACX,WAAW;IACT;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACD;GACF,CAAC;GACF;AAEF,KAAI,IAAI,cAAc,MAAM;EAE1B,MAAM,WAAW,gBAAgB,UADpB,EAAE,IAAI,KAAK,QAAQ,YAAY,GAAG,GACG;AAClD,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;AAEF,KAAI,IAAI,iBAAiB,MAAM;EAC7B,MAAM,WAAW,gBAAgB,cAAc;AAC/C,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;AAEF,KAAI,IAAI,MAAM,MAAM;EAClB,MAAM,WAAW,gBAAgB,aAAa;AAC9C,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,gBAAgB,IAAI;GAClC"}
|
|
1
|
+
{"version":3,"file":"public-gateway.js","names":[],"sources":["../../../../../src/gateway/hono/routes/public-gateway.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { PACKAGE_VERSION } from '../../../package-version.js';\nimport type { GatewayService } from '../../service.js';\nimport { serveStaticFile } from '../lib/static-ui.js';\n\nexport function registerPublicGatewayRoutes(app: Hono, service: GatewayService): void {\n app.get('/health', (c) => {\n return c.json(service.getHealth());\n });\n\n app.get('/api', (c) => {\n return c.json({\n service: 'xopc-gateway',\n version: PACKAGE_VERSION,\n transport: 'streamable-http',\n endpoints: [\n 'GET /health',\n 'GET /status',\n 'POST /api/agent (SSE stream / JSON)',\n 'POST /api/agent/abort',\n 'POST /api/agent/steer',\n 'POST /api/send',\n 'GET /api/events (SSE stream)',\n 'GET /api/channels/status',\n 'POST /api/channels/weixin/login/start',\n 'GET /api/channels/weixin/login/:sessionKey',\n 'GET /api/config',\n 'GET /api/agents',\n 'POST /api/agents',\n 'PATCH /api/agents/:id',\n 'DELETE /api/agents/:id',\n 'GET/PUT /api/agents/:id/files/...',\n 'PATCH /api/config',\n 'POST /api/config/reload',\n 'POST /api/heartbeat/trigger',\n '... /api/cron/*',\n 'GET/PATCH /api/sessions/:key/agent-config',\n '... /api/sessions/*',\n 'GET /api/host/fs/meta',\n 'GET /api/host/fs/list',\n ],\n });\n });\n\n app.get('/assets/*', (c) => {\n const path = c.req.path.replace('/assets/', '');\n const response = serveStaticFile(`assets/${path}`);\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n app.get('/favicon.ico', (c) => {\n const response = serveStaticFile('favicon.ico');\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n app.get('/logo.svg', (c) => {\n const response = serveStaticFile('logo.svg');\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n app.get('/logo-dark.svg', (c) => {\n const response = serveStaticFile('logo-dark.svg');\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n app.get('/', (c) => {\n const response = serveStaticFile('index.html');\n if (response) return response;\n return c.text('UI not found', 404);\n });\n}\n"],"mappings":";;;sBAE8D;AAI9D,SAAgB,4BAA4B,KAAW,SAA+B;AACpF,KAAI,IAAI,YAAY,MAAM;AACxB,SAAO,EAAE,KAAK,QAAQ,WAAW,CAAC;GAClC;AAEF,KAAI,IAAI,SAAS,MAAM;AACrB,SAAO,EAAE,KAAK;GACZ,SAAS;GACT,SAAS;GACT,WAAW;GACX,WAAW;IACT;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACD;GACF,CAAC;GACF;AAEF,KAAI,IAAI,cAAc,MAAM;EAE1B,MAAM,WAAW,gBAAgB,UADpB,EAAE,IAAI,KAAK,QAAQ,YAAY,GAAG,GACG;AAClD,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;AAEF,KAAI,IAAI,iBAAiB,MAAM;EAC7B,MAAM,WAAW,gBAAgB,cAAc;AAC/C,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;AAEF,KAAI,IAAI,cAAc,MAAM;EAC1B,MAAM,WAAW,gBAAgB,WAAW;AAC5C,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;AAEF,KAAI,IAAI,mBAAmB,MAAM;EAC/B,MAAM,WAAW,gBAAgB,gBAAgB;AACjD,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;AAEF,KAAI,IAAI,MAAM,MAAM;EAClB,MAAM,WAAW,gBAAgB,aAAa;AAC9C,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,gBAAgB,IAAI;GAClC"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { PACKAGE_VERSION, init_package_version } from "../../../package-version.js";
|
|
2
|
+
import { createLogger } from "../../../utils/logger/index.js";
|
|
3
|
+
import { init_logger } from "../../../utils/logger.js";
|
|
4
|
+
import { loadConfig } from "../../../config/loader.js";
|
|
5
|
+
import "../../../config/index.js";
|
|
6
|
+
import { normalizeUpdateChannel } from "../../../infra/update-channels.js";
|
|
7
|
+
import { detectInstallKind, resolvePackageRoot } from "../../../infra/update-check.js";
|
|
8
|
+
import { getUpdateAvailable, runGatewayUpdateCheck } from "../../../infra/update-startup.js";
|
|
9
|
+
import { runAutoUpdateCommand } from "../../../infra/update-runner.js";
|
|
10
|
+
//#region src/gateway/hono/routes/update.ts
|
|
11
|
+
init_package_version();
|
|
12
|
+
init_logger();
|
|
13
|
+
const log = createLogger("GatewayUpdate");
|
|
14
|
+
let updateRunInFlight = false;
|
|
15
|
+
function parseUpdateCliJson(stdout) {
|
|
16
|
+
const t = stdout.trim();
|
|
17
|
+
if (!t) return null;
|
|
18
|
+
try {
|
|
19
|
+
const parsed = JSON.parse(t);
|
|
20
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
21
|
+
} catch {
|
|
22
|
+
const lines = t.split("\n").filter(Boolean);
|
|
23
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
24
|
+
const line = lines[i].trim();
|
|
25
|
+
if (!line.startsWith("{")) continue;
|
|
26
|
+
try {
|
|
27
|
+
const parsed = JSON.parse(line);
|
|
28
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
|
|
29
|
+
} catch {}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
function registerUpdateRoutes(authenticated, deps) {
|
|
35
|
+
const { strictRateLimitMiddleware, service } = deps;
|
|
36
|
+
/**
|
|
37
|
+
* GET /api/update/status
|
|
38
|
+
*/
|
|
39
|
+
authenticated.get("/api/update/status", (c) => {
|
|
40
|
+
const update = getUpdateAvailable();
|
|
41
|
+
return c.json({
|
|
42
|
+
ok: true,
|
|
43
|
+
payload: {
|
|
44
|
+
currentVersion: PACKAGE_VERSION,
|
|
45
|
+
updateAvailable: update !== null,
|
|
46
|
+
latestVersion: update?.latestVersion ?? null,
|
|
47
|
+
channel: update?.channel ?? null
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
/**
|
|
52
|
+
* POST /api/update/check
|
|
53
|
+
*/
|
|
54
|
+
authenticated.post("/api/update/check", strictRateLimitMiddleware, async (c) => {
|
|
55
|
+
await runGatewayUpdateCheck({
|
|
56
|
+
config: loadConfig(service.getHealth().configPath),
|
|
57
|
+
force: true,
|
|
58
|
+
onUpdateAvailableChange: (update) => {
|
|
59
|
+
service.emit("update.available", update);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
const result = getUpdateAvailable();
|
|
63
|
+
return c.json({
|
|
64
|
+
ok: true,
|
|
65
|
+
payload: {
|
|
66
|
+
currentVersion: PACKAGE_VERSION,
|
|
67
|
+
updateAvailable: result !== null,
|
|
68
|
+
latestVersion: result?.latestVersion ?? null,
|
|
69
|
+
channel: result?.channel ?? null
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
/**
|
|
74
|
+
* POST /api/update/run — one-click npm install (OpenClaw-style). Rejects git checkouts.
|
|
75
|
+
*/
|
|
76
|
+
authenticated.post("/api/update/run", strictRateLimitMiddleware, async (c) => {
|
|
77
|
+
if (updateRunInFlight) return c.json({
|
|
78
|
+
ok: false,
|
|
79
|
+
error: "busy",
|
|
80
|
+
message: "Another update is already in progress."
|
|
81
|
+
}, 409);
|
|
82
|
+
const configPath = service.getHealth().configPath;
|
|
83
|
+
const channel = normalizeUpdateChannel(loadConfig(configPath).update?.channel) ?? "stable";
|
|
84
|
+
const root = await resolvePackageRoot();
|
|
85
|
+
if (root) {
|
|
86
|
+
if (await detectInstallKind(root) === "git") return c.json({
|
|
87
|
+
ok: false,
|
|
88
|
+
error: "git-checkout",
|
|
89
|
+
message: "Running from a git checkout. Use `git pull` in the repo, or install from npm to use one-click update."
|
|
90
|
+
}, 400);
|
|
91
|
+
}
|
|
92
|
+
updateRunInFlight = true;
|
|
93
|
+
try {
|
|
94
|
+
log.info({ channel }, "Gateway: starting one-click npm update");
|
|
95
|
+
const result = await runAutoUpdateCommand({
|
|
96
|
+
channel,
|
|
97
|
+
root
|
|
98
|
+
});
|
|
99
|
+
const parsed = parseUpdateCliJson(result.stdout ?? "");
|
|
100
|
+
if (result.ok && parsed?.status === "skipped" && parsed?.reason === "git-checkout") return c.json({
|
|
101
|
+
ok: false,
|
|
102
|
+
error: "git-checkout",
|
|
103
|
+
message: String(parsed.message ?? "Git checkout — use git pull instead.")
|
|
104
|
+
}, 400);
|
|
105
|
+
if (!result.ok) {
|
|
106
|
+
log.warn({
|
|
107
|
+
channel,
|
|
108
|
+
exitCode: result.exitCode,
|
|
109
|
+
reason: result.reason
|
|
110
|
+
}, "Gateway: one-click npm update failed");
|
|
111
|
+
return c.json({
|
|
112
|
+
ok: false,
|
|
113
|
+
error: "update-failed",
|
|
114
|
+
message: result.stderr?.trim() || result.reason || `Update exited with code ${result.exitCode ?? "unknown"}`,
|
|
115
|
+
result: parsed
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
log.info({ channel }, "Gateway: one-click npm update finished");
|
|
119
|
+
return c.json({
|
|
120
|
+
ok: true,
|
|
121
|
+
result: parsed
|
|
122
|
+
});
|
|
123
|
+
} catch (err) {
|
|
124
|
+
log.error({
|
|
125
|
+
err,
|
|
126
|
+
channel
|
|
127
|
+
}, "Gateway: one-click npm update threw");
|
|
128
|
+
return c.json({
|
|
129
|
+
ok: false,
|
|
130
|
+
error: "internal",
|
|
131
|
+
message: err instanceof Error ? err.message : String(err)
|
|
132
|
+
}, 500);
|
|
133
|
+
} finally {
|
|
134
|
+
updateRunInFlight = false;
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
//#endregion
|
|
139
|
+
export { registerUpdateRoutes };
|
|
140
|
+
|
|
141
|
+
//# sourceMappingURL=update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.js","names":[],"sources":["../../../../../src/gateway/hono/routes/update.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { loadConfig } from '../../../config/index.js';\nimport { detectInstallKind, resolvePackageRoot } from '../../../infra/update-check.js';\nimport { DEFAULT_PACKAGE_CHANNEL, normalizeUpdateChannel } from '../../../infra/update-channels.js';\nimport { runAutoUpdateCommand } from '../../../infra/update-runner.js';\nimport { getUpdateAvailable, runGatewayUpdateCheck } from '../../../infra/update-startup.js';\nimport { PACKAGE_VERSION } from '../../../package-version.js';\nimport { createLogger } from '../../../utils/logger.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nconst log = createLogger('GatewayUpdate');\n\nlet updateRunInFlight = false;\n\nfunction parseUpdateCliJson(stdout: string): Record<string, unknown> | null {\n const t = stdout.trim();\n if (!t) return null;\n try {\n const parsed = JSON.parse(t) as unknown;\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : null;\n } catch {\n const lines = t.split('\\n').filter(Boolean);\n for (let i = lines.length - 1; i >= 0; i--) {\n const line = lines[i]!.trim();\n if (!line.startsWith('{')) continue;\n try {\n const parsed = JSON.parse(line) as unknown;\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n } catch {\n // try previous line\n }\n }\n }\n return null;\n}\n\nexport function registerUpdateRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { strictRateLimitMiddleware, service } = deps;\n\n /**\n * GET /api/update/status\n */\n authenticated.get('/api/update/status', (c) => {\n const update = getUpdateAvailable();\n return c.json({\n ok: true,\n payload: {\n currentVersion: PACKAGE_VERSION,\n updateAvailable: update !== null,\n latestVersion: update?.latestVersion ?? null,\n channel: update?.channel ?? null,\n },\n });\n });\n\n /**\n * POST /api/update/check\n */\n authenticated.post('/api/update/check', strictRateLimitMiddleware, async (c) => {\n const config = loadConfig(service.getHealth().configPath);\n await runGatewayUpdateCheck({\n config,\n force: true,\n onUpdateAvailableChange: (update) => {\n service.emit('update.available', update);\n },\n });\n const result = getUpdateAvailable();\n return c.json({\n ok: true,\n payload: {\n currentVersion: PACKAGE_VERSION,\n updateAvailable: result !== null,\n latestVersion: result?.latestVersion ?? null,\n channel: result?.channel ?? null,\n },\n });\n });\n\n /**\n * POST /api/update/run — one-click npm install (OpenClaw-style). Rejects git checkouts.\n */\n authenticated.post('/api/update/run', strictRateLimitMiddleware, async (c) => {\n if (updateRunInFlight) {\n return c.json(\n {\n ok: false,\n error: 'busy',\n message: 'Another update is already in progress.',\n },\n 409,\n );\n }\n\n const configPath = service.getHealth().configPath;\n const config = loadConfig(configPath);\n const channel =\n normalizeUpdateChannel(config.update?.channel) ?? DEFAULT_PACKAGE_CHANNEL;\n\n const root = await resolvePackageRoot();\n if (root) {\n const kind = await detectInstallKind(root);\n if (kind === 'git') {\n return c.json(\n {\n ok: false,\n error: 'git-checkout',\n message:\n 'Running from a git checkout. Use `git pull` in the repo, or install from npm to use one-click update.',\n },\n 400,\n );\n }\n }\n\n updateRunInFlight = true;\n try {\n log.info({ channel }, 'Gateway: starting one-click npm update');\n const result = await runAutoUpdateCommand({ channel, root });\n const parsed = parseUpdateCliJson(result.stdout ?? '');\n\n if (result.ok && parsed?.status === 'skipped' && parsed?.reason === 'git-checkout') {\n return c.json(\n {\n ok: false,\n error: 'git-checkout',\n message: String(parsed.message ?? 'Git checkout — use git pull instead.'),\n },\n 400,\n );\n }\n\n if (!result.ok) {\n log.warn(\n { channel, exitCode: result.exitCode, reason: result.reason },\n 'Gateway: one-click npm update failed',\n );\n return c.json({\n ok: false,\n error: 'update-failed',\n message: result.stderr?.trim() || result.reason || `Update exited with code ${result.exitCode ?? 'unknown'}`,\n result: parsed,\n });\n }\n\n log.info({ channel }, 'Gateway: one-click npm update finished');\n // Do not run registry check here: the process still reports the old `PACKAGE_VERSION`\n // until the gateway is restarted, which would keep `update available` set incorrectly.\n return c.json({ ok: true, result: parsed });\n } catch (err) {\n log.error({ err, channel }, 'Gateway: one-click npm update threw');\n return c.json(\n {\n ok: false,\n error: 'internal',\n message: err instanceof Error ? err.message : String(err),\n },\n 500,\n );\n } finally {\n updateRunInFlight = false;\n }\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
import { createLogger } from "../../../utils/logger/index.js";
|
|
2
|
+
import { init_logger } from "../../../utils/logger.js";
|
|
1
3
|
import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveAgentHomeDir, resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../../../agent/agent-scope.js";
|
|
2
4
|
import { getWorkspacePath, init_schema } from "../../../config/schema.js";
|
|
3
5
|
import { extractProfileAgentId } from "../../../config/agent-profile.js";
|
|
4
|
-
import { createLogger } from "../../../utils/logger/index.js";
|
|
5
|
-
import { init_logger } from "../../../utils/logger.js";
|
|
6
6
|
import { resolveSafeInboundFilePath } from "../../../channels/attachments/inbound-persist.js";
|
|
7
|
+
import { isPathUnderWorkspace, resolveWorkspaceSafePath, toWorkspaceRelativePosix } from "../../workspace-editor-path.js";
|
|
7
8
|
import { resolveSafeTtsFilePath } from "../../../channels/attachments/outbound-tts-persist.js";
|
|
8
9
|
import { resolveHeartbeatMdPath } from "../../workspace-heartbeat-path.js";
|
|
9
|
-
import {
|
|
10
|
-
import { runRipgrepInDirectory } from "../../workspace-ripgrep.js";
|
|
10
|
+
import { listWorkspaceRelativeFilesFsFallback } from "../../workspace-fs-file-list.js";
|
|
11
|
+
import { runRipgrepInDirectory, runRipgrepListFiles } from "../../workspace-ripgrep.js";
|
|
11
12
|
import { join, resolve } from "node:path";
|
|
12
13
|
import { readFile, readdir, stat, writeFile } from "node:fs/promises";
|
|
13
14
|
//#region src/gateway/hono/routes/workspace.ts
|
|
@@ -20,6 +21,69 @@ function resolvePersistedAttachmentAgentHome(cfg, sessionKeyRaw) {
|
|
|
20
21
|
const sk = typeof sessionKeyRaw === "string" ? sessionKeyRaw.trim() : "";
|
|
21
22
|
return resolveAgentHomeDir(cfg, sk ? extractProfileAgentId(sk, cfg) : resolveDefaultAgentId(cfg));
|
|
22
23
|
}
|
|
24
|
+
const FILE_SEARCH_MAX_LIMIT = 50;
|
|
25
|
+
/** Subsequence fuzzy match: all query chars appear in order in `candidate` (case-insensitive). */
|
|
26
|
+
function fuzzySubsequenceScore(query, candidate) {
|
|
27
|
+
const q = query.toLowerCase();
|
|
28
|
+
const c = candidate.toLowerCase();
|
|
29
|
+
if (q.length === 0) return 0;
|
|
30
|
+
let qi = 0;
|
|
31
|
+
for (let ci = 0; ci < c.length && qi < q.length; ci++) if (c[ci] === q[qi]) qi++;
|
|
32
|
+
if (qi < q.length) return null;
|
|
33
|
+
const base = c.split("/").pop() ?? c;
|
|
34
|
+
let score = 10;
|
|
35
|
+
if (c.startsWith(q)) score += 40;
|
|
36
|
+
if (base.startsWith(q)) score += 35;
|
|
37
|
+
else if (base.includes(q)) score += 20;
|
|
38
|
+
else if (c.includes(q)) score += 10;
|
|
39
|
+
score -= c.length * 1e-4;
|
|
40
|
+
return score;
|
|
41
|
+
}
|
|
42
|
+
async function fuzzySearchWorkspaceFiles(workspaceRoot, query, limit) {
|
|
43
|
+
let files = await runRipgrepListFiles(workspaceRoot);
|
|
44
|
+
if (files.length === 0) {
|
|
45
|
+
files = await listWorkspaceRelativeFilesFsFallback(workspaceRoot, 12e4);
|
|
46
|
+
if (files.length > 0) log.debug({
|
|
47
|
+
workspaceRoot,
|
|
48
|
+
fileCount: files.length
|
|
49
|
+
}, "workspace files/search: file list from fs walk (ripgrep unavailable or returned empty)");
|
|
50
|
+
}
|
|
51
|
+
const q = query.trim();
|
|
52
|
+
const capped = Math.min(Math.max(limit, 1), FILE_SEARCH_MAX_LIMIT);
|
|
53
|
+
const rows = [];
|
|
54
|
+
if (!q) {
|
|
55
|
+
const sorted = [...files].sort((a, b) => a.localeCompare(b));
|
|
56
|
+
for (const rel of sorted.slice(0, capped)) {
|
|
57
|
+
const name = rel.split("/").pop() ?? rel;
|
|
58
|
+
rows.push({
|
|
59
|
+
name,
|
|
60
|
+
path: rel,
|
|
61
|
+
isDirectory: false,
|
|
62
|
+
score: 0
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return rows;
|
|
66
|
+
}
|
|
67
|
+
for (const rel of files) {
|
|
68
|
+
const name = rel.split("/").pop() ?? rel;
|
|
69
|
+
const scorePath = fuzzySubsequenceScore(q, rel);
|
|
70
|
+
const scoreName = fuzzySubsequenceScore(q, name);
|
|
71
|
+
const score = Math.max(scorePath ?? -Infinity, scoreName ?? -Infinity);
|
|
72
|
+
if (score === -Infinity) continue;
|
|
73
|
+
rows.push({
|
|
74
|
+
name,
|
|
75
|
+
path: rel,
|
|
76
|
+
isDirectory: false,
|
|
77
|
+
score
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
rows.sort((a, b) => b.score - a.score || a.path.localeCompare(b.path));
|
|
81
|
+
return rows.slice(0, capped).map(({ name, path, isDirectory }) => ({
|
|
82
|
+
name,
|
|
83
|
+
path,
|
|
84
|
+
isDirectory
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
23
87
|
function isKnownEditorAgentId(cfg, id) {
|
|
24
88
|
const n = normalizeAgentId(id);
|
|
25
89
|
if (n === resolveDefaultAgentId(cfg)) return true;
|
|
@@ -556,6 +620,22 @@ function registerWorkspaceRoutes(authenticated, deps) {
|
|
|
556
620
|
payload: { results }
|
|
557
621
|
});
|
|
558
622
|
});
|
|
623
|
+
/** Fuzzy filename / path search over the session workspace (ripgrep `--files` + subsequence scoring). */
|
|
624
|
+
authenticated.get("/api/workspace/editor/files/search", async (c) => {
|
|
625
|
+
const q = typeof c.req.query("q") === "string" ? c.req.query("q").trim() : "";
|
|
626
|
+
const limitRaw = c.req.query("limit");
|
|
627
|
+
const limit = Math.min(Math.max(parseInt(typeof limitRaw === "string" ? limitRaw : "15", 10) || 15, 1), FILE_SEARCH_MAX_LIMIT);
|
|
628
|
+
const ws = await resolveEditorWorkspaceRootAsync(service, service.currentConfig, c.req.query("sessionKey"), c.req.query("agentId"));
|
|
629
|
+
if (ws.ok === false) return c.json({
|
|
630
|
+
ok: false,
|
|
631
|
+
error: { message: ws.message }
|
|
632
|
+
}, 400);
|
|
633
|
+
const entries = await fuzzySearchWorkspaceFiles(ws.root, q, limit);
|
|
634
|
+
return c.json({
|
|
635
|
+
ok: true,
|
|
636
|
+
payload: { entries }
|
|
637
|
+
});
|
|
638
|
+
});
|
|
559
639
|
}
|
|
560
640
|
//#endregion
|
|
561
641
|
export { registerWorkspaceRoutes };
|