@alneas/eaos-server 0.0.0-stage → 0.2.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 +41 -0
- package/LICENSE +21 -0
- package/README.ja.md +49 -0
- package/README.md +46 -2
- package/dist/agentic/agent-jobs.d.ts +333 -0
- package/dist/agentic/agent-jobs.js +15 -0
- package/dist/agentic/agent-jobs.js.map +1 -0
- package/dist/agentic/agent-node.d.ts +40 -0
- package/dist/agentic/agent-node.js +7 -0
- package/dist/agentic/agent-node.js.map +1 -0
- package/dist/agentic/agent-runner.d.ts +33 -0
- package/dist/agentic/agent-runner.js +7 -0
- package/dist/agentic/agent-runner.js.map +1 -0
- package/dist/agentic/ai-broker.d.ts +169 -0
- package/dist/agentic/ai-broker.js +8 -0
- package/dist/agentic/ai-broker.js.map +1 -0
- package/dist/agentic/atomic-checkpointer.d.ts +137 -0
- package/dist/agentic/atomic-checkpointer.js +9 -0
- package/dist/agentic/atomic-checkpointer.js.map +1 -0
- package/dist/agentic/autonomous-worker.d.ts +122 -0
- package/dist/agentic/autonomous-worker.js +10 -0
- package/dist/agentic/autonomous-worker.js.map +1 -0
- package/dist/agentic/event-bridge.d.ts +350 -0
- package/dist/agentic/event-bridge.js +9 -0
- package/dist/agentic/event-bridge.js.map +1 -0
- package/dist/agentic/executor.d.ts +91 -0
- package/dist/agentic/executor.js +12 -0
- package/dist/agentic/executor.js.map +1 -0
- package/dist/agentic/graph-projection.d.ts +119 -0
- package/dist/agentic/graph-projection.js +7 -0
- package/dist/agentic/graph-projection.js.map +1 -0
- package/dist/agentic/graph.d.ts +524 -0
- package/dist/agentic/graph.js +7 -0
- package/dist/agentic/graph.js.map +1 -0
- package/dist/agentic/index.d.ts +28 -0
- package/dist/agentic/index.js +87 -0
- package/dist/agentic/index.js.map +1 -0
- package/dist/agentic/local-runner.d.ts +106 -0
- package/dist/agentic/local-runner.js +7 -0
- package/dist/agentic/local-runner.js.map +1 -0
- package/dist/agentic/remote-executor.d.ts +67 -0
- package/dist/agentic/remote-executor.js +8 -0
- package/dist/agentic/remote-executor.js.map +1 -0
- package/dist/agentic/types.d.ts +157 -0
- package/dist/agentic/types.js +7 -0
- package/dist/agentic/types.js.map +1 -0
- package/dist/agentic/workflow-catalog.d.ts +152 -0
- package/dist/agentic/workflow-catalog.js +7 -0
- package/dist/agentic/workflow-catalog.js.map +1 -0
- package/dist/agentic/workflow-compiler.d.ts +44 -0
- package/dist/agentic/workflow-compiler.js +8 -0
- package/dist/agentic/workflow-compiler.js.map +1 -0
- package/dist/agentic/workflow-coordinator.d.ts +170 -0
- package/dist/agentic/workflow-coordinator.js +8 -0
- package/dist/agentic/workflow-coordinator.js.map +1 -0
- package/dist/agentic/workflow-manager.d.ts +91 -0
- package/dist/agentic/workflow-manager.js +7 -0
- package/dist/agentic/workflow-manager.js.map +1 -0
- package/dist/agentic/workflow-registry.d.ts +334 -0
- package/dist/agentic/workflow-registry.js +7 -0
- package/dist/agentic/workflow-registry.js.map +1 -0
- package/dist/artifacts-CteHmCMI.d.ts +614 -0
- package/dist/auth-hooks/api-key.d.ts +75 -0
- package/dist/auth-hooks/api-key.js +7 -0
- package/dist/auth-hooks/api-key.js.map +1 -0
- package/dist/auth-hooks/index.d.ts +80 -0
- package/dist/auth-hooks/index.js +28 -0
- package/dist/auth-hooks/index.js.map +1 -0
- package/dist/browser-auth/account-memberships.d.ts +213 -0
- package/dist/browser-auth/account-memberships.js +13 -0
- package/dist/browser-auth/account-memberships.js.map +1 -0
- package/dist/browser-auth/index.d.ts +8 -0
- package/dist/browser-auth/index.js +59 -0
- package/dist/browser-auth/index.js.map +1 -0
- package/dist/browser-auth/kratos-session.d.ts +37 -0
- package/dist/browser-auth/kratos-session.js +7 -0
- package/dist/browser-auth/kratos-session.js.map +1 -0
- package/dist/browser-auth/platform-session.d.ts +120 -0
- package/dist/browser-auth/platform-session.js +7 -0
- package/dist/browser-auth/platform-session.js.map +1 -0
- package/dist/browser-auth/public-memberships.d.ts +22 -0
- package/dist/browser-auth/public-memberships.js +7 -0
- package/dist/browser-auth/public-memberships.js.map +1 -0
- package/dist/cache/index.d.ts +181 -0
- package/dist/cache/index.js +197 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/chunk-32746UQZ.js +131 -0
- package/dist/chunk-32746UQZ.js.map +1 -0
- package/dist/chunk-3NLSWP2Y.js +223 -0
- package/dist/chunk-3NLSWP2Y.js.map +1 -0
- package/dist/chunk-3P4XTTQH.js +346 -0
- package/dist/chunk-3P4XTTQH.js.map +1 -0
- package/dist/chunk-3VITSHN3.js +15 -0
- package/dist/chunk-3VITSHN3.js.map +1 -0
- package/dist/chunk-46UWPEW2.js +226 -0
- package/dist/chunk-46UWPEW2.js.map +1 -0
- package/dist/chunk-4BARRLJR.js +180 -0
- package/dist/chunk-4BARRLJR.js.map +1 -0
- package/dist/chunk-4VORUFKR.js +45 -0
- package/dist/chunk-4VORUFKR.js.map +1 -0
- package/dist/chunk-55D4ERWO.js +1 -0
- package/dist/chunk-55D4ERWO.js.map +1 -0
- package/dist/chunk-5TBBZIND.js +18 -0
- package/dist/chunk-5TBBZIND.js.map +1 -0
- package/dist/chunk-5WOZWPZA.js +211 -0
- package/dist/chunk-5WOZWPZA.js.map +1 -0
- package/dist/chunk-6CBVZ6CT.js +168 -0
- package/dist/chunk-6CBVZ6CT.js.map +1 -0
- package/dist/chunk-6XZXYNJR.js +74 -0
- package/dist/chunk-6XZXYNJR.js.map +1 -0
- package/dist/chunk-753HWDSC.js +222 -0
- package/dist/chunk-753HWDSC.js.map +1 -0
- package/dist/chunk-7AHSS7SO.js +81 -0
- package/dist/chunk-7AHSS7SO.js.map +1 -0
- package/dist/chunk-7FTJN4SA.js +1 -0
- package/dist/chunk-7FTJN4SA.js.map +1 -0
- package/dist/chunk-AVDMLTPF.js +24 -0
- package/dist/chunk-AVDMLTPF.js.map +1 -0
- package/dist/chunk-BKAHUEIT.js +95 -0
- package/dist/chunk-BKAHUEIT.js.map +1 -0
- package/dist/chunk-CJ7OFEF7.js +134 -0
- package/dist/chunk-CJ7OFEF7.js.map +1 -0
- package/dist/chunk-EJKWDZIU.js +111 -0
- package/dist/chunk-EJKWDZIU.js.map +1 -0
- package/dist/chunk-F2J6IQ6I.js +247 -0
- package/dist/chunk-F2J6IQ6I.js.map +1 -0
- package/dist/chunk-F3O7CELI.js +23 -0
- package/dist/chunk-F3O7CELI.js.map +1 -0
- package/dist/chunk-F4IITPGX.js +221 -0
- package/dist/chunk-F4IITPGX.js.map +1 -0
- package/dist/chunk-FD6VC2NA.js +66 -0
- package/dist/chunk-FD6VC2NA.js.map +1 -0
- package/dist/chunk-FRRRWAHO.js +14 -0
- package/dist/chunk-FRRRWAHO.js.map +1 -0
- package/dist/chunk-HCKAGLLB.js +17 -0
- package/dist/chunk-HCKAGLLB.js.map +1 -0
- package/dist/chunk-HVC7FG6B.js +191 -0
- package/dist/chunk-HVC7FG6B.js.map +1 -0
- package/dist/chunk-HXFVOR7Z.js +496 -0
- package/dist/chunk-HXFVOR7Z.js.map +1 -0
- package/dist/chunk-IJWYS2PF.js +122 -0
- package/dist/chunk-IJWYS2PF.js.map +1 -0
- package/dist/chunk-INCHXAFK.js +1395 -0
- package/dist/chunk-INCHXAFK.js.map +1 -0
- package/dist/chunk-JT6BRGQM.js +1 -0
- package/dist/chunk-JT6BRGQM.js.map +1 -0
- package/dist/chunk-L6PMAEMB.js +115 -0
- package/dist/chunk-L6PMAEMB.js.map +1 -0
- package/dist/chunk-LOUGW6MU.js +126 -0
- package/dist/chunk-LOUGW6MU.js.map +1 -0
- package/dist/chunk-LYPZPE53.js +129 -0
- package/dist/chunk-LYPZPE53.js.map +1 -0
- package/dist/chunk-NNCCN7JP.js +186 -0
- package/dist/chunk-NNCCN7JP.js.map +1 -0
- package/dist/chunk-PBC3MZUL.js +212 -0
- package/dist/chunk-PBC3MZUL.js.map +1 -0
- package/dist/chunk-R4ADP2DC.js +20 -0
- package/dist/chunk-R4ADP2DC.js.map +1 -0
- package/dist/chunk-RHN4Y6VS.js +44 -0
- package/dist/chunk-RHN4Y6VS.js.map +1 -0
- package/dist/chunk-SDJNYPYK.js +770 -0
- package/dist/chunk-SDJNYPYK.js.map +1 -0
- package/dist/chunk-UGNTCOVR.js +28 -0
- package/dist/chunk-UGNTCOVR.js.map +1 -0
- package/dist/chunk-VC2PCK2S.js +31 -0
- package/dist/chunk-VC2PCK2S.js.map +1 -0
- package/dist/chunk-VF5YDZJC.js +305 -0
- package/dist/chunk-VF5YDZJC.js.map +1 -0
- package/dist/chunk-VISRDVTK.js +675 -0
- package/dist/chunk-VISRDVTK.js.map +1 -0
- package/dist/chunk-W6O3LVBY.js +102 -0
- package/dist/chunk-W6O3LVBY.js.map +1 -0
- package/dist/chunk-WFEAKJLR.js +47 -0
- package/dist/chunk-WFEAKJLR.js.map +1 -0
- package/dist/chunk-XIEY2OF4.js +67 -0
- package/dist/chunk-XIEY2OF4.js.map +1 -0
- package/dist/chunk-XITLHDG3.js +37 -0
- package/dist/chunk-XITLHDG3.js.map +1 -0
- package/dist/chunk-XMWPYZWZ.js +61 -0
- package/dist/chunk-XMWPYZWZ.js.map +1 -0
- package/dist/chunk-XUP6CNOM.js +34 -0
- package/dist/chunk-XUP6CNOM.js.map +1 -0
- package/dist/chunk-YABTQZDJ.js +25 -0
- package/dist/chunk-YABTQZDJ.js.map +1 -0
- package/dist/chunk-YMHVRBUU.js +199 -0
- package/dist/chunk-YMHVRBUU.js.map +1 -0
- package/dist/chunk-YMJ7BRKU.js +510 -0
- package/dist/chunk-YMJ7BRKU.js.map +1 -0
- package/dist/chunk-ZC3XWU7B.js +28 -0
- package/dist/chunk-ZC3XWU7B.js.map +1 -0
- package/dist/chunk-ZHMTD5KV.js +90 -0
- package/dist/chunk-ZHMTD5KV.js.map +1 -0
- package/dist/chunk-ZWZDLOE7.js +160 -0
- package/dist/chunk-ZWZDLOE7.js.map +1 -0
- package/dist/db-package/db/local-first-sqlite-adapter.d.ts +432 -0
- package/dist/db-package/db/local-first-sqlite-adapter.js +7 -0
- package/dist/db-package/db/local-first-sqlite-adapter.js.map +1 -0
- package/dist/db-package/index.d.ts +7 -0
- package/dist/db-package/index.js +16 -0
- package/dist/db-package/index.js.map +1 -0
- package/dist/db-package/migration/aggregator.d.ts +86 -0
- package/dist/db-package/migration/aggregator.js +7 -0
- package/dist/db-package/migration/aggregator.js.map +1 -0
- package/dist/db-package/migration/index.d.ts +3 -0
- package/dist/db-package/migration/index.js +8 -0
- package/dist/db-package/migration/index.js.map +1 -0
- package/dist/engine.d.ts +205 -0
- package/dist/engine.js +20 -0
- package/dist/engine.js.map +1 -0
- package/dist/entitlements/index.d.ts +313 -0
- package/dist/entitlements/index.js +23 -0
- package/dist/entitlements/index.js.map +1 -0
- package/dist/execution/chat.d.ts +7 -0
- package/dist/execution/chat.js +7 -0
- package/dist/execution/chat.js.map +1 -0
- package/dist/execution/index.d.ts +342 -0
- package/dist/execution/index.js +66 -0
- package/dist/execution/index.js.map +1 -0
- package/dist/execution/tool-agent.d.ts +7 -0
- package/dist/execution/tool-agent.js +8 -0
- package/dist/execution/tool-agent.js.map +1 -0
- package/dist/extensions/index.d.ts +172 -0
- package/dist/extensions/index.js +95 -0
- package/dist/extensions/index.js.map +1 -0
- package/dist/health/index.d.ts +35 -0
- package/dist/health/index.js +7 -0
- package/dist/health/index.js.map +1 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +161 -0
- package/dist/index.js.map +1 -0
- package/dist/lifecycle/index.d.ts +133 -0
- package/dist/lifecycle/index.js +13 -0
- package/dist/lifecycle/index.js.map +1 -0
- package/dist/lifecycle-engine/backend-migration.d.ts +2 -0
- package/dist/lifecycle-engine/backend-migration.js +11 -0
- package/dist/lifecycle-engine/backend-migration.js.map +1 -0
- package/dist/lifecycle-engine/baseline.d.ts +2 -0
- package/dist/lifecycle-engine/baseline.js +9 -0
- package/dist/lifecycle-engine/baseline.js.map +1 -0
- package/dist/lifecycle-engine/index.d.ts +1497 -0
- package/dist/lifecycle-engine/index.js +41 -0
- package/dist/lifecycle-engine/index.js.map +1 -0
- package/dist/lifecycle-engine/platform/artifacts.d.ts +4 -0
- package/dist/lifecycle-engine/platform/artifacts.js +7 -0
- package/dist/lifecycle-engine/platform/artifacts.js.map +1 -0
- package/dist/lifecycle-engine/platform/control-plane.d.ts +12 -0
- package/dist/lifecycle-engine/platform/control-plane.js +2 -0
- package/dist/lifecycle-engine/platform/control-plane.js.map +1 -0
- package/dist/lifecycle-engine/platform/database-router.d.ts +118 -0
- package/dist/lifecycle-engine/platform/database-router.js +7 -0
- package/dist/lifecycle-engine/platform/database-router.js.map +1 -0
- package/dist/lifecycle-engine/platform/deployment-placements.d.ts +464 -0
- package/dist/lifecycle-engine/platform/deployment-placements.js +16 -0
- package/dist/lifecycle-engine/platform/deployment-placements.js.map +1 -0
- package/dist/lifecycle-engine/platform/deployment.d.ts +4 -0
- package/dist/lifecycle-engine/platform/deployment.js +17 -0
- package/dist/lifecycle-engine/platform/deployment.js.map +1 -0
- package/dist/lifecycle-engine/platform/index.d.ts +737 -0
- package/dist/lifecycle-engine/platform/index.js +60 -0
- package/dist/lifecycle-engine/platform/index.js.map +1 -0
- package/dist/lifecycle-engine/platform/runtime.d.ts +80 -0
- package/dist/lifecycle-engine/platform/runtime.js +11 -0
- package/dist/lifecycle-engine/platform/runtime.js.map +1 -0
- package/dist/lifecycle-engine/platform/site-publication.d.ts +102 -0
- package/dist/lifecycle-engine/platform/site-publication.js +7 -0
- package/dist/lifecycle-engine/platform/site-publication.js.map +1 -0
- package/dist/lifecycle-engine/platform/user-directory.d.ts +139 -0
- package/dist/lifecycle-engine/platform/user-directory.js +13 -0
- package/dist/lifecycle-engine/platform/user-directory.js.map +1 -0
- package/dist/mcp.d.ts +92 -0
- package/dist/mcp.js +10 -0
- package/dist/mcp.js.map +1 -0
- package/dist/middleware/auth.d.ts +118 -0
- package/dist/middleware/auth.js +7 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/middleware/error-handler.d.ts +35 -0
- package/dist/middleware/error-handler.js +7 -0
- package/dist/middleware/error-handler.js.map +1 -0
- package/dist/middleware/module-guard.d.ts +33 -0
- package/dist/middleware/module-guard.js +7 -0
- package/dist/middleware/module-guard.js.map +1 -0
- package/dist/platform-admin/index.d.ts +37 -0
- package/dist/platform-admin/index.js +11 -0
- package/dist/platform-admin/index.js.map +1 -0
- package/dist/platform-admin/store.d.ts +346 -0
- package/dist/platform-admin/store.js +7 -0
- package/dist/platform-admin/store.js.map +1 -0
- package/dist/plugin-data/annotations.d.ts +6 -0
- package/dist/plugin-data/annotations.js +12 -0
- package/dist/plugin-data/annotations.js.map +1 -0
- package/dist/plugin-data/atomic-context.d.ts +41 -0
- package/dist/plugin-data/atomic-context.js +9 -0
- package/dist/plugin-data/atomic-context.js.map +1 -0
- package/dist/plugin-data/atomic.d.ts +6 -0
- package/dist/plugin-data/atomic.js +26 -0
- package/dist/plugin-data/atomic.js.map +1 -0
- package/dist/plugin-data/audit.d.ts +6 -0
- package/dist/plugin-data/audit.js +12 -0
- package/dist/plugin-data/audit.js.map +1 -0
- package/dist/plugin-data/commands.d.ts +6 -0
- package/dist/plugin-data/commands.js +8 -0
- package/dist/plugin-data/commands.js.map +1 -0
- package/dist/plugin-data/composite.d.ts +6 -0
- package/dist/plugin-data/composite.js +8 -0
- package/dist/plugin-data/composite.js.map +1 -0
- package/dist/plugin-data/delivery.d.ts +6 -0
- package/dist/plugin-data/delivery.js +16 -0
- package/dist/plugin-data/delivery.js.map +1 -0
- package/dist/plugin-data/index.d.ts +2798 -0
- package/dist/plugin-data/index.js +102 -0
- package/dist/plugin-data/index.js.map +1 -0
- package/dist/plugin-data/json-documents.d.ts +6 -0
- package/dist/plugin-data/json-documents.js +16 -0
- package/dist/plugin-data/json-documents.js.map +1 -0
- package/dist/plugin-data/outbox.d.ts +6 -0
- package/dist/plugin-data/outbox.js +16 -0
- package/dist/plugin-data/outbox.js.map +1 -0
- package/dist/plugin-data/scoped-records.d.ts +6 -0
- package/dist/plugin-data/scoped-records.js +10 -0
- package/dist/plugin-data/scoped-records.js.map +1 -0
- package/dist/plugin-sdk.d.ts +41 -0
- package/dist/plugin-sdk.js +10 -0
- package/dist/plugin-sdk.js.map +1 -0
- package/dist/sql-lifecycle/index.d.ts +138 -0
- package/dist/sql-lifecycle/index.js +167 -0
- package/dist/sql-lifecycle/index.js.map +1 -0
- package/dist/storage/index.d.ts +2 -0
- package/dist/storage/index.js +13 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/s3-compatible.d.ts +139 -0
- package/dist/storage/s3-compatible.js +11 -0
- package/dist/storage/s3-compatible.js.map +1 -0
- package/dist/tenant.d.ts +108 -0
- package/dist/tenant.js +9 -0
- package/dist/tenant.js.map +1 -0
- package/dist/workspace-context.d.ts +119 -0
- package/dist/workspace-context.js +9 -0
- package/dist/workspace-context.js.map +1 -0
- package/docs/api.md +30560 -0
- package/docs/db/README.md +49 -0
- package/docs/db/docs/api.md +1613 -0
- package/docs/db/docs/guide.md +47 -0
- package/docs/entitlements.md +60 -0
- package/docs/guide.md +92 -0
- package/docs/index.md +57 -0
- package/docs/ja/db/README.md +46 -0
- package/docs/ja/db/docs/guide.md +53 -0
- package/docs/ja/guide.md +46 -0
- package/docs/ja/lifecycle/README.md +46 -0
- package/docs/ja/lifecycle/docs/guide.md +45 -0
- package/docs/ja/storage/README.md +46 -0
- package/docs/ja/storage/docs/guide.md +43 -0
- package/docs/lifecycle/README.md +49 -0
- package/docs/lifecycle/docs/api.md +3770 -0
- package/docs/lifecycle/docs/baseline.md +50 -0
- package/docs/lifecycle/docs/guide.md +47 -0
- package/docs/storage/README.md +49 -0
- package/docs/storage/docs/api.md +470 -0
- package/docs/storage/docs/guide.md +47 -0
- package/package.json +354 -4
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createChatClient
|
|
3
|
+
} from "./chunk-YMHVRBUU.js";
|
|
4
|
+
import {
|
|
5
|
+
createCommandAgentExecutor,
|
|
6
|
+
validateAgentRuntimePolicy
|
|
7
|
+
} from "./chunk-32746UQZ.js";
|
|
8
|
+
import {
|
|
9
|
+
ServerAgentExecutionError
|
|
10
|
+
} from "./chunk-YABTQZDJ.js";
|
|
11
|
+
|
|
12
|
+
// src/agentic/autonomous-worker.ts
|
|
13
|
+
import { createOpenAICompatibleChatAdapter } from "@alneas/appkit-core/ai/ai-chat";
|
|
14
|
+
import { defaultRuntimePlacementPolicy, McpGatekeeper } from "@alneas/eaos-core";
|
|
15
|
+
import { randomUUID } from "node:crypto";
|
|
16
|
+
function inferRuntimeRole() {
|
|
17
|
+
const configured = process.env.EAOS_RUNTIME_ROLE;
|
|
18
|
+
if (configured === "edge" || configured === "application-worker" || configured === "ai") return configured;
|
|
19
|
+
return process.arch === "arm64" ? "ai" : "application-worker";
|
|
20
|
+
}
|
|
21
|
+
var ServerAutonomousWorker = class {
|
|
22
|
+
gatekeeper;
|
|
23
|
+
goosePath;
|
|
24
|
+
hermesAgentPath;
|
|
25
|
+
litellmUrl;
|
|
26
|
+
litellmModel;
|
|
27
|
+
litellmHeaders;
|
|
28
|
+
chatOptions;
|
|
29
|
+
maxOutputChars;
|
|
30
|
+
runtimePolicy;
|
|
31
|
+
runtimeRole;
|
|
32
|
+
activeTasks = 0;
|
|
33
|
+
fetchImpl;
|
|
34
|
+
executors;
|
|
35
|
+
/**
|
|
36
|
+
* Captures runtime settings and validates resource policy, role, and output ceiling.
|
|
37
|
+
* @param options - Trusted host configuration; omitted gatekeeper uses a new McpGatekeeper and runtime role uses EAOS_RUNTIME_ROLE, then ai on arm64 or application-worker otherwise.
|
|
38
|
+
* @throws Invalid resource policy, role, or output limit.
|
|
39
|
+
*/
|
|
40
|
+
constructor(options) {
|
|
41
|
+
this.gatekeeper = options?.gatekeeper || new McpGatekeeper();
|
|
42
|
+
this.goosePath = options?.gooseBinaryPath || process.env.GOOSE_BIN_PATH || "goose";
|
|
43
|
+
this.hermesAgentPath = options?.hermesAgentBinaryPath || process.env.HERMES_AGENT_BIN_PATH || "hermes";
|
|
44
|
+
this.litellmUrl = options?.litellmEndpoint || process.env.LITELLM_ENDPOINT || "http://localhost:4000/v1";
|
|
45
|
+
this.litellmModel = options?.litellmModel || process.env.LITELLM_MODEL;
|
|
46
|
+
this.litellmHeaders = { ...options?.litellmHeaders };
|
|
47
|
+
this.chatOptions = { ...options?.chat, parameters: structuredClone(options?.chat?.parameters) };
|
|
48
|
+
this.maxOutputChars = options?.maxOutputChars ?? 1e6;
|
|
49
|
+
this.runtimePolicy = validateAgentRuntimePolicy(options?.runtimePolicy || defaultRuntimePlacementPolicy().ai.agentRuntime);
|
|
50
|
+
this.runtimeRole = options?.runtimeRole || inferRuntimeRole();
|
|
51
|
+
if (!["edge", "application-worker", "ai"].includes(this.runtimeRole)) throw new Error("Invalid agent runtime role");
|
|
52
|
+
this.fetchImpl = options?.fetch || fetch;
|
|
53
|
+
this.executors = options?.executors || {};
|
|
54
|
+
if (!Number.isSafeInteger(this.maxOutputChars) || this.maxOutputChars < 1 || this.maxOutputChars > 1e7) throw new Error("Invalid worker output limit");
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Checks task limits and gatekeeper policy before dispatching one runtime attempt.
|
|
58
|
+
* @param request - Verified task identity and instructions; required strings must be nonblank, title at most 500 characters, instructions at most 1000000, and timeout a safe integer 1–3600000 milliseconds when provided.
|
|
59
|
+
* @param execution - Optional cancellation signal for built-in shared chat tasks; does not change injected executor or process contracts.
|
|
60
|
+
* @returns COMPLETED text output, PENDING_APPROVAL ticket data without execution, or FAILED data with error and optional classification/retry advice. Duration is measured in wall-clock milliseconds.
|
|
61
|
+
* @throws Can reject a throwing gatekeeper or malformed gatekeeper interaction before dispatch; runtime execution errors are normally returned as FAILED data.
|
|
62
|
+
* @remarks Gatekeeper receives fixed agent/server_bot roles rather than request user roles. Approval tickets are generated but not persisted here. The configured framework policy overrides request.runtimePolicy before execution. Injected executors and built-in chat outputs are bounded by maxOutputChars. LiteLLM uses Appkit SSE transport through createChatClient; JSON-only endpoints require a Host adapter or executor. Existing FAILED/PENDING_APPROVAL/COMPLETED envelopes and injected-executor priority remain unchanged.
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* import { ServerAutonomousWorker, type ServerWorkerOptions } from "@alneas/eaos-server/agentic/autonomous-worker";
|
|
66
|
+
* import type { ServerAgentTaskRequest } from "@alneas/eaos-server/agentic/types";
|
|
67
|
+
* export async function execute(options: ServerWorkerOptions, request: ServerAgentTaskRequest) {
|
|
68
|
+
* return new ServerAutonomousWorker(options).runTask(request);
|
|
69
|
+
* }
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
async runTask(request, execution = {}) {
|
|
73
|
+
const startTime = Date.now();
|
|
74
|
+
if (!request || [request.id, request.tenantId, request.userId, request.title, request.instructions].some((value) => typeof value !== "string" || !value.trim())) {
|
|
75
|
+
return { taskId: typeof request?.id === "string" ? request.id : "unknown", status: "FAILED", error: "Invalid agent task request", durationMs: Date.now() - startTime };
|
|
76
|
+
}
|
|
77
|
+
if (request.instructions.length > 1e6 || request.title.length > 500 || request.timeoutMs !== void 0 && (!Number.isSafeInteger(request.timeoutMs) || request.timeoutMs < 1 || request.timeoutMs > 36e5)) {
|
|
78
|
+
return { taskId: request.id, status: "FAILED", error: "Agent task exceeds configured limits", durationMs: Date.now() - startTime };
|
|
79
|
+
}
|
|
80
|
+
const policy = this.gatekeeper.validateCall({
|
|
81
|
+
toolName: `server_agent_${request.workerType}`,
|
|
82
|
+
userRoles: ["agent", "server_bot"],
|
|
83
|
+
tenantId: request.tenantId
|
|
84
|
+
});
|
|
85
|
+
if (!policy.allowed) {
|
|
86
|
+
return {
|
|
87
|
+
taskId: request.id,
|
|
88
|
+
status: "FAILED",
|
|
89
|
+
error: `Task execution blocked by security policy: ${policy.reason}`,
|
|
90
|
+
riskLevel: policy.riskLevel,
|
|
91
|
+
durationMs: Date.now() - startTime
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
if (policy.requireHumanApproval) {
|
|
95
|
+
return {
|
|
96
|
+
taskId: request.id,
|
|
97
|
+
status: "PENDING_APPROVAL",
|
|
98
|
+
approvalTicketId: randomUUID(),
|
|
99
|
+
approvalLevel: policy.approvalLevel,
|
|
100
|
+
riskLevel: policy.riskLevel,
|
|
101
|
+
durationMs: Date.now() - startTime
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
const frameworkManaged = !this.executors[request.workerType];
|
|
105
|
+
if (frameworkManaged && (request.workerType === "goose" || request.workerType === "hermes_agent") && this.runtimeRole !== "ai") {
|
|
106
|
+
return {
|
|
107
|
+
taskId: request.id,
|
|
108
|
+
status: "FAILED",
|
|
109
|
+
error: `Built-in ${request.workerType} execution is restricted to the AI runtime placement`,
|
|
110
|
+
failureCode: "AGENT_UNAVAILABLE",
|
|
111
|
+
retryable: true,
|
|
112
|
+
durationMs: Date.now() - startTime
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
if (frameworkManaged && this.activeTasks >= this.runtimePolicy.maxConcurrent) {
|
|
116
|
+
return {
|
|
117
|
+
taskId: request.id,
|
|
118
|
+
status: "FAILED",
|
|
119
|
+
error: "Agent runtime concurrency limit reached",
|
|
120
|
+
failureCode: "AGENT_UNAVAILABLE",
|
|
121
|
+
retryable: true,
|
|
122
|
+
durationMs: Date.now() - startTime
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
if (frameworkManaged) this.activeTasks += 1;
|
|
126
|
+
try {
|
|
127
|
+
const output = await this.execute({ ...structuredClone(request), runtimePolicy: structuredClone(this.runtimePolicy) }, execution.signal);
|
|
128
|
+
return {
|
|
129
|
+
taskId: request.id,
|
|
130
|
+
status: "COMPLETED",
|
|
131
|
+
output,
|
|
132
|
+
durationMs: Date.now() - startTime
|
|
133
|
+
};
|
|
134
|
+
} catch (err) {
|
|
135
|
+
return {
|
|
136
|
+
taskId: request.id,
|
|
137
|
+
status: "FAILED",
|
|
138
|
+
error: err.message,
|
|
139
|
+
...err instanceof ServerAgentExecutionError ? { failureCode: err.failureCode, retryable: err.retryable } : {},
|
|
140
|
+
durationMs: Date.now() - startTime
|
|
141
|
+
};
|
|
142
|
+
} finally {
|
|
143
|
+
if (frameworkManaged) this.activeTasks -= 1;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
async execute(request, signal) {
|
|
147
|
+
const injected = this.executors[request.workerType];
|
|
148
|
+
if (injected) return this.boundOutput(await injected(structuredClone(request)));
|
|
149
|
+
if (request.workerType === "goose") return this.executeHeadlessGoose(request);
|
|
150
|
+
if (request.workerType === "hermes_agent") return this.executeHeadlessHermesAgent(request);
|
|
151
|
+
if (request.workerType === "litellm") return this.executeLiteLlm(request, signal);
|
|
152
|
+
throw new Error(`No executor configured for worker type '${request.workerType}'`);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Execute Goose in headless batch mode
|
|
156
|
+
*/
|
|
157
|
+
async executeHeadlessGoose(request) {
|
|
158
|
+
return createCommandAgentExecutor({
|
|
159
|
+
command: this.goosePath,
|
|
160
|
+
buildArgs: (task) => ["run", "--text", task.instructions],
|
|
161
|
+
includeProcessEnv: true,
|
|
162
|
+
maxOutputChars: this.maxOutputChars,
|
|
163
|
+
sandbox: { mode: "auto", policy: this.runtimePolicy }
|
|
164
|
+
})(request);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Execute NousResearch Hermes Agent in headless mode (-z / non-interactive)
|
|
168
|
+
* Hermes Agent provides persistent cross-session memory and self-improving skill extraction.
|
|
169
|
+
*/
|
|
170
|
+
async executeHeadlessHermesAgent(request) {
|
|
171
|
+
return createCommandAgentExecutor({
|
|
172
|
+
command: this.hermesAgentPath,
|
|
173
|
+
buildArgs: (task) => ["run", "-z", task.instructions],
|
|
174
|
+
includeProcessEnv: true,
|
|
175
|
+
maxOutputChars: this.maxOutputChars,
|
|
176
|
+
sandbox: { mode: "auto", policy: this.runtimePolicy }
|
|
177
|
+
})(request);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Execute a host-selected model through LiteLLM.
|
|
181
|
+
*/
|
|
182
|
+
async executeLiteLlm(request, signal) {
|
|
183
|
+
const configured = this.chatOptions;
|
|
184
|
+
let adapter = configured.adapter;
|
|
185
|
+
if (!adapter) {
|
|
186
|
+
if (!this.litellmModel) throw new Error("LiteLLM model is not configured");
|
|
187
|
+
const endpoint = new URL(this.litellmUrl);
|
|
188
|
+
if (!["http:", "https:"].includes(endpoint.protocol)) throw new Error("Invalid LiteLLM endpoint");
|
|
189
|
+
endpoint.pathname = `${endpoint.pathname.replace(/\/$/, "")}/chat/completions`;
|
|
190
|
+
adapter = createOpenAICompatibleChatAdapter({
|
|
191
|
+
api: endpoint.href,
|
|
192
|
+
model: this.litellmModel,
|
|
193
|
+
headers: this.litellmHeaders,
|
|
194
|
+
maxResponseChars: Math.min(1e7, this.maxOutputChars * 6 + 65536),
|
|
195
|
+
fetch: async (input, init) => {
|
|
196
|
+
const response = await this.fetchImpl(input, { ...init, redirect: "error" });
|
|
197
|
+
if (!response.ok) {
|
|
198
|
+
try {
|
|
199
|
+
void response.body?.cancel().catch(() => {
|
|
200
|
+
});
|
|
201
|
+
} catch {
|
|
202
|
+
}
|
|
203
|
+
throw new Error(`LiteLLM request failed (${response.status})`);
|
|
204
|
+
}
|
|
205
|
+
return response;
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
const metadata = configured.parameters?.metadata;
|
|
210
|
+
const timeout = request.timeoutMs ?? 6e4;
|
|
211
|
+
const chat = createChatClient({
|
|
212
|
+
...configured,
|
|
213
|
+
adapter,
|
|
214
|
+
timeoutMs: Math.min(timeout, configured.timeoutMs ?? timeout),
|
|
215
|
+
maxInputChars: configured.maxInputChars ?? 7e6,
|
|
216
|
+
maxOutputChars: Math.min(1e7, configured.maxOutputChars ?? this.maxOutputChars * 6 + 65536),
|
|
217
|
+
parameters: { ...configured.parameters, metadata: {
|
|
218
|
+
...metadata && typeof metadata === "object" && !Array.isArray(metadata) ? metadata : {},
|
|
219
|
+
tenantId: request.tenantId,
|
|
220
|
+
taskId: request.id
|
|
221
|
+
} },
|
|
222
|
+
governance: { ...configured.governance, sessionId: configured.governance?.sessionId ?? request.id },
|
|
223
|
+
authorize: async (principal, operation) => {
|
|
224
|
+
if (principal.tenantId !== request.tenantId || principal.userId !== request.userId) return false;
|
|
225
|
+
if (configured.authorize && await configured.authorize(principal, operation) !== true) return false;
|
|
226
|
+
const decision = this.gatekeeper.validateCall({ toolName: "server_agent_litellm", userRoles: ["agent", "server_bot"], tenantId: principal.tenantId });
|
|
227
|
+
return decision.allowed && !decision.requireHumanApproval;
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
const completed = await chat.complete({ tenantId: request.tenantId, userId: request.userId }, {
|
|
231
|
+
messages: [{ id: request.id, role: "user", parts: [{ type: "text", text: request.instructions }] }],
|
|
232
|
+
tools: "none",
|
|
233
|
+
signal
|
|
234
|
+
});
|
|
235
|
+
if (completed.message.parts.some((part) => part.type !== "text")) throw new Error("LiteLLM returned no assistant content");
|
|
236
|
+
return this.boundOutput(completed.message.parts.map((part) => part.type === "text" ? part.text : "").join(""));
|
|
237
|
+
}
|
|
238
|
+
boundOutput(output) {
|
|
239
|
+
if (output.length > this.maxOutputChars) throw new Error("Agent output exceeds configured limit");
|
|
240
|
+
return output;
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
export {
|
|
245
|
+
ServerAutonomousWorker
|
|
246
|
+
};
|
|
247
|
+
//# sourceMappingURL=chunk-F2J6IQ6I.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/agentic/autonomous-worker.ts"],"sourcesContent":["import {createOpenAICompatibleChatAdapter, type AIChatAdapter} from '@alneas/appkit-core/ai/ai-chat'\nimport {createChatClient, type ChatClientOptions} from '../execution/chat'\nimport { defaultRuntimePlacementPolicy, McpGatekeeper, type AgentRuntimeResourcePolicy } from '@alneas/eaos-core'\nimport { ServerAgentExecutionError, type ServerAgentExecutor, type ServerAgentTaskRequest, type ServerAgentTaskResult, type ServerAgentWorkerType } from './types'\nimport { randomUUID } from 'node:crypto'\nimport { createCommandAgentExecutor, validateAgentRuntimePolicy } from './executor'\n\n/**\n * Host composition of the shared chat path for built-in model tasks.\n * @remarks Defaults retain the worker gatekeeper, 60-second task timeout and worker output bound. Tools are undisclosed; action orchestration belongs to createToolAgent. No model transport or credential is selected from model output.\n * @see ServerWorkerOptions for complete worker configuration.\n */\nexport interface ServerWorkerChatOptions extends Omit<ChatClientOptions, 'adapter' | 'authorize' | 'tools'> {\n /** Optional host adapter; omission uses Appkit's OpenAI-compatible LiteLLM transport. */\n adapter?: AIChatAdapter\n /** Optional live Host authorization, combined with the worker gatekeeper before and after asynchronous work. */\n authorize?: ChatClientOptions['authorize']\n}\n\n/**\n * Trusted gatekeeper, runtime endpoints/adapters, and execution limits for {@link ServerAutonomousWorker}.\n */\nexport interface ServerWorkerOptions {\n /** Host security/approval policies; defaults to a new McpGatekeeper. */\n gatekeeper?: McpGatekeeper\n /** Trusted executable path; defaults to GOOSE_BIN_PATH or goose. */\n gooseBinaryPath?: string\n /** Trusted executable path; defaults to HERMES_AGENT_BIN_PATH or hermes. */\n hermesAgentBinaryPath?: string\n /** Host LiteLLM base URL; defaults to LITELLM_ENDPOINT or http://localhost:4000/v1. */\n litellmEndpoint?: string\n /** Host model identifier; defaults to LITELLM_MODEL and is required for built-in LiteLLM execution. */\n litellmModel?: string\n /** Host-owned provider headers; captured at construction and never read from task/model input. */\n litellmHeaders?: Readonly<Record<string, string>>\n /** Optional shared chat model routing, live authorization, limits, guards, usage, budget and observability. */\n chat?: ServerWorkerChatOptions\n /** Combined command output/string result ceiling, safe integer 1–10000000; defaults to 1000000. */\n maxOutputChars?: number\n /** Framework default is safe for the ARM agent host. Host adapters may tighten it. */\n runtimePolicy?: AgentRuntimeResourcePolicy\n /** Built-in Goose/Hermes execution is permitted only on the AI placement. */\n runtimeRole?: ServerRuntimeRole\n /** Host fetch implementation for built-in LiteLLM; defaults to global fetch. */\n fetch?: typeof fetch\n /** Host/plugin adapters for coding agents and other external runtimes. */\n executors?: Partial<Record<ServerAgentWorkerType, ServerAgentExecutor>>\n}\n\n/**\n * Host placement role controlling whether built-in Goose/Hermes processes may run locally.\n * @see ServerAutonomousWorker.\n */\nexport type ServerRuntimeRole = 'edge' | 'application-worker' | 'ai'\n\nfunction inferRuntimeRole(): ServerRuntimeRole {\n const configured = process.env.EAOS_RUNTIME_ROLE\n if (configured === 'edge' || configured === 'application-worker' || configured === 'ai') return configured\n // The supported three-host topology places the AI runtime on the ARM host.\n // Unknown x64 hosts therefore fail closed as application-worker hosts.\n return process.arch === 'arm64' ? 'ai' : 'application-worker'\n}\n\n/**\n * Admits and executes host agent tasks through a gatekeeper and bounded runtime adapters.\n * @remarks This class runs only when runTask is called; it installs no scheduler. The host authenticates tenant/user claims before admission. Framework-managed tasks share a per-instance concurrency counter; injected executors own scheduling and are exempt from it. Built-in Goose/Hermes require the ai role and Node process/systemd support. Queue persistence, approvals, retries, and side-effect idempotency belong to the host.\n * @example\n * ```typescript\n * import { ServerAutonomousWorker, type ServerWorkerOptions } from \"@alneas/eaos-server/agentic/autonomous-worker\";\n * export function worker(options: ServerWorkerOptions) { return new ServerAutonomousWorker(options); }\n * ```\n */\nexport class ServerAutonomousWorker {\n private gatekeeper: McpGatekeeper\n private goosePath: string\n private hermesAgentPath: string\n private litellmUrl: string\n private litellmModel?: string\n private litellmHeaders: Record<string, string>\n private chatOptions: ServerWorkerChatOptions\n private maxOutputChars: number\n private runtimePolicy: AgentRuntimeResourcePolicy\n private runtimeRole: ServerRuntimeRole\n private activeTasks = 0\n private fetchImpl: typeof fetch\n private executors: Partial<Record<ServerAgentWorkerType, ServerAgentExecutor>>\n\n /**\n * Captures runtime settings and validates resource policy, role, and output ceiling.\n * @param options - Trusted host configuration; omitted gatekeeper uses a new McpGatekeeper and runtime role uses EAOS_RUNTIME_ROLE, then ai on arm64 or application-worker otherwise.\n * @throws Invalid resource policy, role, or output limit.\n */\n constructor(options?: ServerWorkerOptions) {\n this.gatekeeper = options?.gatekeeper || new McpGatekeeper()\n this.goosePath = options?.gooseBinaryPath || process.env.GOOSE_BIN_PATH || 'goose'\n this.hermesAgentPath = options?.hermesAgentBinaryPath || process.env.HERMES_AGENT_BIN_PATH || 'hermes'\n this.litellmUrl = options?.litellmEndpoint || process.env.LITELLM_ENDPOINT || 'http://localhost:4000/v1'\n this.litellmModel = options?.litellmModel || process.env.LITELLM_MODEL\n this.litellmHeaders = {...options?.litellmHeaders}\n this.chatOptions = {...options?.chat, parameters: structuredClone(options?.chat?.parameters)}\n this.maxOutputChars = options?.maxOutputChars ?? 1_000_000\n this.runtimePolicy = validateAgentRuntimePolicy(options?.runtimePolicy || defaultRuntimePlacementPolicy().ai.agentRuntime)\n this.runtimeRole = options?.runtimeRole || inferRuntimeRole()\n if (!['edge', 'application-worker', 'ai'].includes(this.runtimeRole)) throw new Error('Invalid agent runtime role')\n this.fetchImpl = options?.fetch || fetch\n this.executors = options?.executors || {}\n if (!Number.isSafeInteger(this.maxOutputChars) || this.maxOutputChars < 1 || this.maxOutputChars > 10_000_000) throw new Error('Invalid worker output limit')\n }\n\n /**\n * Checks task limits and gatekeeper policy before dispatching one runtime attempt.\n * @param request - Verified task identity and instructions; required strings must be nonblank, title at most 500 characters, instructions at most 1000000, and timeout a safe integer 1–3600000 milliseconds when provided.\n * @param execution - Optional cancellation signal for built-in shared chat tasks; does not change injected executor or process contracts.\n * @returns COMPLETED text output, PENDING_APPROVAL ticket data without execution, or FAILED data with error and optional classification/retry advice. Duration is measured in wall-clock milliseconds.\n * @throws Can reject a throwing gatekeeper or malformed gatekeeper interaction before dispatch; runtime execution errors are normally returned as FAILED data.\n * @remarks Gatekeeper receives fixed agent/server_bot roles rather than request user roles. Approval tickets are generated but not persisted here. The configured framework policy overrides request.runtimePolicy before execution. Injected executors and built-in chat outputs are bounded by maxOutputChars. LiteLLM uses Appkit SSE transport through createChatClient; JSON-only endpoints require a Host adapter or executor. Existing FAILED/PENDING_APPROVAL/COMPLETED envelopes and injected-executor priority remain unchanged.\n * @example\n * ```typescript\n * import { ServerAutonomousWorker, type ServerWorkerOptions } from \"@alneas/eaos-server/agentic/autonomous-worker\";\n * import type { ServerAgentTaskRequest } from \"@alneas/eaos-server/agentic/types\";\n * export async function execute(options: ServerWorkerOptions, request: ServerAgentTaskRequest) {\n * return new ServerAutonomousWorker(options).runTask(request);\n * }\n * ```\n */\n async runTask(request: ServerAgentTaskRequest, execution: {\n /** Cooperatively cancel built-in shared chat. Injected executors and Goose/Hermes retain their own cancellation contracts. */\n signal?: AbortSignal\n } = {}): Promise<ServerAgentTaskResult> {\n const startTime = Date.now()\n\n if (!request || [request.id, request.tenantId, request.userId, request.title, request.instructions].some(value => typeof value !== 'string' || !value.trim())) {\n return { taskId: typeof request?.id === 'string' ? request.id : 'unknown', status: 'FAILED', error: 'Invalid agent task request', durationMs: Date.now() - startTime }\n }\n if (request.instructions.length > 1_000_000 || request.title.length > 500 || request.timeoutMs !== undefined && (!Number.isSafeInteger(request.timeoutMs) || request.timeoutMs < 1 || request.timeoutMs > 3_600_000)) {\n return { taskId: request.id, status: 'FAILED', error: 'Agent task exceeds configured limits', durationMs: Date.now() - startTime }\n }\n\n // 1. Evaluate security and gatekeeper policies\n const policy = this.gatekeeper.validateCall({\n toolName: `server_agent_${request.workerType}`,\n userRoles: ['agent', 'server_bot'],\n tenantId: request.tenantId,\n })\n\n if (!policy.allowed) {\n return {\n taskId: request.id,\n status: 'FAILED',\n error: `Task execution blocked by security policy: ${policy.reason}`,\n riskLevel: policy.riskLevel,\n durationMs: Date.now() - startTime,\n }\n }\n\n if (policy.requireHumanApproval) {\n return {\n taskId: request.id,\n status: 'PENDING_APPROVAL',\n approvalTicketId: randomUUID(),\n approvalLevel: policy.approvalLevel,\n riskLevel: policy.riskLevel,\n durationMs: Date.now() - startTime,\n }\n }\n\n // Explicitly injected executors are host-owned adapters and may implement\n // their own queue/scheduler. The framework-managed Goose/Hermes path is\n // bounded by the default policy so a forgotten host setting cannot create\n // unbounded local agent concurrency.\n const frameworkManaged = !this.executors[request.workerType]\n if (frameworkManaged && (request.workerType === 'goose' || request.workerType === 'hermes_agent') && this.runtimeRole !== 'ai') {\n return {\n taskId: request.id,\n status: 'FAILED',\n error: `Built-in ${request.workerType} execution is restricted to the AI runtime placement`,\n failureCode: 'AGENT_UNAVAILABLE',\n retryable: true,\n durationMs: Date.now() - startTime,\n }\n }\n if (frameworkManaged && this.activeTasks >= this.runtimePolicy.maxConcurrent) {\n return {\n taskId: request.id,\n status: 'FAILED',\n error: 'Agent runtime concurrency limit reached',\n failureCode: 'AGENT_UNAVAILABLE',\n retryable: true,\n durationMs: Date.now() - startTime,\n }\n }\n\n // 2. Dispatch according to worker type\n if (frameworkManaged) this.activeTasks += 1\n try {\n const output = await this.execute({ ...structuredClone(request), runtimePolicy: structuredClone(this.runtimePolicy) }, execution.signal)\n return {\n taskId: request.id,\n status: 'COMPLETED',\n output,\n durationMs: Date.now() - startTime,\n }\n } catch (err) {\n return {\n taskId: request.id,\n status: 'FAILED',\n error: (err as Error).message,\n ...(err instanceof ServerAgentExecutionError ? { failureCode: err.failureCode, retryable: err.retryable } : {}),\n durationMs: Date.now() - startTime,\n }\n } finally {\n if (frameworkManaged) this.activeTasks -= 1\n }\n }\n\n private async execute(request: ServerAgentTaskRequest, signal?: AbortSignal): Promise<string> {\n const injected = this.executors[request.workerType]\n if (injected) return this.boundOutput(await injected(structuredClone(request)))\n if (request.workerType === 'goose') return this.executeHeadlessGoose(request)\n if (request.workerType === 'hermes_agent') return this.executeHeadlessHermesAgent(request)\n if (request.workerType === 'litellm') return this.executeLiteLlm(request, signal)\n throw new Error(`No executor configured for worker type '${request.workerType}'`)\n }\n\n /**\n * Execute Goose in headless batch mode\n */\n private async executeHeadlessGoose(request: ServerAgentTaskRequest): Promise<string> {\n return createCommandAgentExecutor({\n command: this.goosePath,\n buildArgs: task => ['run', '--text', task.instructions],\n includeProcessEnv: true,\n maxOutputChars: this.maxOutputChars,\n sandbox: { mode: 'auto', policy: this.runtimePolicy },\n })(request)\n }\n\n /**\n * Execute NousResearch Hermes Agent in headless mode (-z / non-interactive)\n * Hermes Agent provides persistent cross-session memory and self-improving skill extraction.\n */\n private async executeHeadlessHermesAgent(request: ServerAgentTaskRequest): Promise<string> {\n return createCommandAgentExecutor({\n command: this.hermesAgentPath,\n buildArgs: task => ['run', '-z', task.instructions],\n includeProcessEnv: true,\n maxOutputChars: this.maxOutputChars,\n sandbox: { mode: 'auto', policy: this.runtimePolicy },\n })(request)\n }\n\n /**\n * Execute a host-selected model through LiteLLM.\n */\n private async executeLiteLlm(request: ServerAgentTaskRequest, signal?: AbortSignal): Promise<string> {\n const configured = this.chatOptions\n let adapter = configured.adapter\n if (!adapter) {\n if (!this.litellmModel) throw new Error('LiteLLM model is not configured')\n const endpoint = new URL(this.litellmUrl)\n if (!['http:', 'https:'].includes(endpoint.protocol)) throw new Error('Invalid LiteLLM endpoint')\n endpoint.pathname = `${endpoint.pathname.replace(/\\/$/, '')}/chat/completions`\n adapter = createOpenAICompatibleChatAdapter({\n api: endpoint.href, model: this.litellmModel, headers: this.litellmHeaders,\n maxResponseChars: Math.min(10_000_000, this.maxOutputChars * 6 + 65_536),\n fetch: async (input, init) => {\n const response = await this.fetchImpl(input, {...init, redirect: 'error'})\n if (!response.ok) {\n try { void response.body?.cancel().catch(() => {}) } catch { /* Preserve the provider status while releasing unread bodies. */ }\n throw new Error(`LiteLLM request failed (${response.status})`)\n }\n return response\n },\n })\n }\n const metadata = configured.parameters?.metadata\n const timeout = request.timeoutMs ?? 60_000\n const chat = createChatClient({\n ...configured, adapter,\n timeoutMs: Math.min(timeout, configured.timeoutMs ?? timeout),\n maxInputChars: configured.maxInputChars ?? 7_000_000,\n maxOutputChars: Math.min(10_000_000, configured.maxOutputChars ?? this.maxOutputChars * 6 + 65_536),\n parameters: {...configured.parameters, metadata: {\n ...(metadata && typeof metadata === 'object' && !Array.isArray(metadata) ? metadata : {}),\n tenantId: request.tenantId, taskId: request.id,\n }},\n governance: {...configured.governance, sessionId: configured.governance?.sessionId ?? request.id},\n authorize: async (principal, operation) => {\n if (principal.tenantId !== request.tenantId || principal.userId !== request.userId) return false\n if (configured.authorize && await configured.authorize(principal, operation) !== true) return false\n const decision = this.gatekeeper.validateCall({toolName: 'server_agent_litellm', userRoles: ['agent', 'server_bot'], tenantId: principal.tenantId})\n return decision.allowed && !decision.requireHumanApproval\n },\n })\n const completed = await chat.complete({tenantId: request.tenantId, userId: request.userId}, {\n messages: [{id: request.id, role: 'user', parts: [{type: 'text', text: request.instructions}]}],\n tools: 'none', signal,\n })\n if (completed.message.parts.some(part => part.type !== 'text')) throw new Error('LiteLLM returned no assistant content')\n return this.boundOutput(completed.message.parts.map(part => part.type === 'text' ? part.text : '').join(''))\n }\n\n private boundOutput(output: string): string {\n if (output.length > this.maxOutputChars) throw new Error('Agent output exceeds configured limit')\n return output\n }\n}\n"],"mappings":";;;;;;;;;;;;AAAA,SAAQ,yCAA4D;AAEpE,SAAS,+BAA+B,qBAAsD;AAE9F,SAAS,kBAAkB;AAmD3B,SAAS,mBAAsC;AAC7C,QAAM,aAAa,QAAQ,IAAI;AAC/B,MAAI,eAAe,UAAU,eAAe,wBAAwB,eAAe,KAAM,QAAO;AAGhG,SAAO,QAAQ,SAAS,UAAU,OAAO;AAC3C;AAWO,IAAM,yBAAN,MAA6B;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOR,YAAY,SAA+B;AACzC,SAAK,aAAa,SAAS,cAAc,IAAI,cAAc;AAC3D,SAAK,YAAY,SAAS,mBAAmB,QAAQ,IAAI,kBAAkB;AAC3E,SAAK,kBAAkB,SAAS,yBAAyB,QAAQ,IAAI,yBAAyB;AAC9F,SAAK,aAAa,SAAS,mBAAmB,QAAQ,IAAI,oBAAoB;AAC9E,SAAK,eAAe,SAAS,gBAAgB,QAAQ,IAAI;AACzD,SAAK,iBAAiB,EAAC,GAAG,SAAS,eAAc;AACjD,SAAK,cAAc,EAAC,GAAG,SAAS,MAAM,YAAY,gBAAgB,SAAS,MAAM,UAAU,EAAC;AAC5F,SAAK,iBAAiB,SAAS,kBAAkB;AACjD,SAAK,gBAAgB,2BAA2B,SAAS,iBAAiB,8BAA8B,EAAE,GAAG,YAAY;AACzH,SAAK,cAAc,SAAS,eAAe,iBAAiB;AAC5D,QAAI,CAAC,CAAC,QAAQ,sBAAsB,IAAI,EAAE,SAAS,KAAK,WAAW,EAAG,OAAM,IAAI,MAAM,4BAA4B;AAClH,SAAK,YAAY,SAAS,SAAS;AACnC,SAAK,YAAY,SAAS,aAAa,CAAC;AACxC,QAAI,CAAC,OAAO,cAAc,KAAK,cAAc,KAAK,KAAK,iBAAiB,KAAK,KAAK,iBAAiB,IAAY,OAAM,IAAI,MAAM,6BAA6B;AAAA,EAC9J;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,MAAM,QAAQ,SAAiC,YAG3C,CAAC,GAAmC;AACtC,UAAM,YAAY,KAAK,IAAI;AAE3B,QAAI,CAAC,WAAW,CAAC,QAAQ,IAAI,QAAQ,UAAU,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,YAAY,EAAE,KAAK,WAAS,OAAO,UAAU,YAAY,CAAC,MAAM,KAAK,CAAC,GAAG;AAC7J,aAAO,EAAE,QAAQ,OAAO,SAAS,OAAO,WAAW,QAAQ,KAAK,WAAW,QAAQ,UAAU,OAAO,8BAA8B,YAAY,KAAK,IAAI,IAAI,UAAU;AAAA,IACvK;AACA,QAAI,QAAQ,aAAa,SAAS,OAAa,QAAQ,MAAM,SAAS,OAAO,QAAQ,cAAc,WAAc,CAAC,OAAO,cAAc,QAAQ,SAAS,KAAK,QAAQ,YAAY,KAAK,QAAQ,YAAY,OAAY;AACpN,aAAO,EAAE,QAAQ,QAAQ,IAAI,QAAQ,UAAU,OAAO,wCAAwC,YAAY,KAAK,IAAI,IAAI,UAAU;AAAA,IACnI;AAGA,UAAM,SAAS,KAAK,WAAW,aAAa;AAAA,MAC1C,UAAU,gBAAgB,QAAQ,UAAU;AAAA,MAC5C,WAAW,CAAC,SAAS,YAAY;AAAA,MACjC,UAAU,QAAQ;AAAA,IACpB,CAAC;AAED,QAAI,CAAC,OAAO,SAAS;AACnB,aAAO;AAAA,QACL,QAAQ,QAAQ;AAAA,QAChB,QAAQ;AAAA,QACR,OAAO,8CAA8C,OAAO,MAAM;AAAA,QAClE,WAAW,OAAO;AAAA,QAClB,YAAY,KAAK,IAAI,IAAI;AAAA,MAC3B;AAAA,IACF;AAEA,QAAI,OAAO,sBAAsB;AAC/B,aAAO;AAAA,QACL,QAAQ,QAAQ;AAAA,QAChB,QAAQ;AAAA,QACR,kBAAkB,WAAW;AAAA,QAC7B,eAAe,OAAO;AAAA,QACtB,WAAW,OAAO;AAAA,QAClB,YAAY,KAAK,IAAI,IAAI;AAAA,MAC3B;AAAA,IACF;AAMA,UAAM,mBAAmB,CAAC,KAAK,UAAU,QAAQ,UAAU;AAC3D,QAAI,qBAAqB,QAAQ,eAAe,WAAW,QAAQ,eAAe,mBAAmB,KAAK,gBAAgB,MAAM;AAC9H,aAAO;AAAA,QACL,QAAQ,QAAQ;AAAA,QAChB,QAAQ;AAAA,QACR,OAAO,YAAY,QAAQ,UAAU;AAAA,QACrC,aAAa;AAAA,QACb,WAAW;AAAA,QACX,YAAY,KAAK,IAAI,IAAI;AAAA,MAC3B;AAAA,IACF;AACA,QAAI,oBAAoB,KAAK,eAAe,KAAK,cAAc,eAAe;AAC5E,aAAO;AAAA,QACL,QAAQ,QAAQ;AAAA,QAChB,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,aAAa;AAAA,QACb,WAAW;AAAA,QACX,YAAY,KAAK,IAAI,IAAI;AAAA,MAC3B;AAAA,IACF;AAGA,QAAI,iBAAkB,MAAK,eAAe;AAC1C,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,QAAQ,EAAE,GAAG,gBAAgB,OAAO,GAAG,eAAe,gBAAgB,KAAK,aAAa,EAAE,GAAG,UAAU,MAAM;AACvI,aAAO;AAAA,QACL,QAAQ,QAAQ;AAAA,QAChB,QAAQ;AAAA,QACR;AAAA,QACA,YAAY,KAAK,IAAI,IAAI;AAAA,MAC3B;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,QAAQ,QAAQ;AAAA,QAChB,QAAQ;AAAA,QACR,OAAQ,IAAc;AAAA,QACtB,GAAI,eAAe,4BAA4B,EAAE,aAAa,IAAI,aAAa,WAAW,IAAI,UAAU,IAAI,CAAC;AAAA,QAC7G,YAAY,KAAK,IAAI,IAAI;AAAA,MAC3B;AAAA,IACF,UAAE;AACA,UAAI,iBAAkB,MAAK,eAAe;AAAA,IAC5C;AAAA,EACF;AAAA,EAEA,MAAc,QAAQ,SAAiC,QAAuC;AAC5F,UAAM,WAAW,KAAK,UAAU,QAAQ,UAAU;AAClD,QAAI,SAAU,QAAO,KAAK,YAAY,MAAM,SAAS,gBAAgB,OAAO,CAAC,CAAC;AAC9E,QAAI,QAAQ,eAAe,QAAS,QAAO,KAAK,qBAAqB,OAAO;AAC5E,QAAI,QAAQ,eAAe,eAAgB,QAAO,KAAK,2BAA2B,OAAO;AACzF,QAAI,QAAQ,eAAe,UAAW,QAAO,KAAK,eAAe,SAAS,MAAM;AAChF,UAAM,IAAI,MAAM,2CAA2C,QAAQ,UAAU,GAAG;AAAA,EAClF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,qBAAqB,SAAkD;AACnF,WAAO,2BAA2B;AAAA,MAChC,SAAS,KAAK;AAAA,MACd,WAAW,UAAQ,CAAC,OAAO,UAAU,KAAK,YAAY;AAAA,MACtD,mBAAmB;AAAA,MACnB,gBAAgB,KAAK;AAAA,MACrB,SAAS,EAAE,MAAM,QAAQ,QAAQ,KAAK,cAAc;AAAA,IACtD,CAAC,EAAE,OAAO;AAAA,EACZ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,2BAA2B,SAAkD;AACzF,WAAO,2BAA2B;AAAA,MAChC,SAAS,KAAK;AAAA,MACd,WAAW,UAAQ,CAAC,OAAO,MAAM,KAAK,YAAY;AAAA,MAClD,mBAAmB;AAAA,MACnB,gBAAgB,KAAK;AAAA,MACrB,SAAS,EAAE,MAAM,QAAQ,QAAQ,KAAK,cAAc;AAAA,IACtD,CAAC,EAAE,OAAO;AAAA,EACZ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,eAAe,SAAiC,QAAuC;AACnG,UAAM,aAAa,KAAK;AACxB,QAAI,UAAU,WAAW;AACzB,QAAI,CAAC,SAAS;AACZ,UAAI,CAAC,KAAK,aAAc,OAAM,IAAI,MAAM,iCAAiC;AACzE,YAAM,WAAW,IAAI,IAAI,KAAK,UAAU;AACxC,UAAI,CAAC,CAAC,SAAS,QAAQ,EAAE,SAAS,SAAS,QAAQ,EAAG,OAAM,IAAI,MAAM,0BAA0B;AAChG,eAAS,WAAW,GAAG,SAAS,SAAS,QAAQ,OAAO,EAAE,CAAC;AAC3D,gBAAU,kCAAkC;AAAA,QAC1C,KAAK,SAAS;AAAA,QAAM,OAAO,KAAK;AAAA,QAAc,SAAS,KAAK;AAAA,QAC5D,kBAAkB,KAAK,IAAI,KAAY,KAAK,iBAAiB,IAAI,KAAM;AAAA,QACvE,OAAO,OAAO,OAAO,SAAS;AAC5B,gBAAM,WAAW,MAAM,KAAK,UAAU,OAAO,EAAC,GAAG,MAAM,UAAU,QAAO,CAAC;AACzE,cAAI,CAAC,SAAS,IAAI;AAChB,gBAAI;AAAE,mBAAK,SAAS,MAAM,OAAO,EAAE,MAAM,MAAM;AAAA,cAAC,CAAC;AAAA,YAAE,QAAQ;AAAA,YAAoE;AAC/H,kBAAM,IAAI,MAAM,2BAA2B,SAAS,MAAM,GAAG;AAAA,UAC/D;AACA,iBAAO;AAAA,QACT;AAAA,MACF,CAAC;AAAA,IACH;AACA,UAAM,WAAW,WAAW,YAAY;AACxC,UAAM,UAAU,QAAQ,aAAa;AACrC,UAAM,OAAO,iBAAiB;AAAA,MAC5B,GAAG;AAAA,MAAY;AAAA,MACf,WAAW,KAAK,IAAI,SAAS,WAAW,aAAa,OAAO;AAAA,MAC5D,eAAe,WAAW,iBAAiB;AAAA,MAC3C,gBAAgB,KAAK,IAAI,KAAY,WAAW,kBAAkB,KAAK,iBAAiB,IAAI,KAAM;AAAA,MAClG,YAAY,EAAC,GAAG,WAAW,YAAY,UAAU;AAAA,QAC/C,GAAI,YAAY,OAAO,aAAa,YAAY,CAAC,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC;AAAA,QACvF,UAAU,QAAQ;AAAA,QAAU,QAAQ,QAAQ;AAAA,MAC9C,EAAC;AAAA,MACD,YAAY,EAAC,GAAG,WAAW,YAAY,WAAW,WAAW,YAAY,aAAa,QAAQ,GAAE;AAAA,MAChG,WAAW,OAAO,WAAW,cAAc;AACzC,YAAI,UAAU,aAAa,QAAQ,YAAY,UAAU,WAAW,QAAQ,OAAQ,QAAO;AAC3F,YAAI,WAAW,aAAa,MAAM,WAAW,UAAU,WAAW,SAAS,MAAM,KAAM,QAAO;AAC9F,cAAM,WAAW,KAAK,WAAW,aAAa,EAAC,UAAU,wBAAwB,WAAW,CAAC,SAAS,YAAY,GAAG,UAAU,UAAU,SAAQ,CAAC;AAClJ,eAAO,SAAS,WAAW,CAAC,SAAS;AAAA,MACvC;AAAA,IACF,CAAC;AACD,UAAM,YAAY,MAAM,KAAK,SAAS,EAAC,UAAU,QAAQ,UAAU,QAAQ,QAAQ,OAAM,GAAG;AAAA,MAC1F,UAAU,CAAC,EAAC,IAAI,QAAQ,IAAI,MAAM,QAAQ,OAAO,CAAC,EAAC,MAAM,QAAQ,MAAM,QAAQ,aAAY,CAAC,EAAC,CAAC;AAAA,MAC9F,OAAO;AAAA,MAAQ;AAAA,IACjB,CAAC;AACD,QAAI,UAAU,QAAQ,MAAM,KAAK,UAAQ,KAAK,SAAS,MAAM,EAAG,OAAM,IAAI,MAAM,uCAAuC;AACvH,WAAO,KAAK,YAAY,UAAU,QAAQ,MAAM,IAAI,UAAQ,KAAK,SAAS,SAAS,KAAK,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC;AAAA,EAC7G;AAAA,EAEQ,YAAY,QAAwB;AAC1C,QAAI,OAAO,SAAS,KAAK,eAAgB,OAAM,IAAI,MAAM,uCAAuC;AAChG,WAAO;AAAA,EACT;AACF;","names":[]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// src/browser-auth/kratos-session.ts
|
|
2
|
+
function createKratosSessionVerifier(options) {
|
|
3
|
+
const base = new URL(options.publicUrl);
|
|
4
|
+
if (!["http:", "https:"].includes(base.protocol) || base.username || base.password || base.search || base.hash || base.pathname !== "/") throw new Error("Invalid Kratos endpoint");
|
|
5
|
+
const request = options.fetch ?? fetch;
|
|
6
|
+
return async (credentials) => {
|
|
7
|
+
if (!credentials.cookie && !credentials.sessionToken) return null;
|
|
8
|
+
const headers = { Accept: "application/json" };
|
|
9
|
+
if (credentials.sessionToken) headers["X-Session-Token"] = credentials.sessionToken;
|
|
10
|
+
else if (credentials.cookie) headers.Cookie = credentials.cookie;
|
|
11
|
+
const response = await request(new URL("/sessions/whoami", base), { headers, cache: "no-store", redirect: "error", signal: AbortSignal.timeout(options.timeoutMs ?? 1e4) });
|
|
12
|
+
if (response.status === 401 || response.status === 403) return null;
|
|
13
|
+
if (!response.ok) throw new Error("Identity provider unavailable");
|
|
14
|
+
const session = await response.json();
|
|
15
|
+
if (session.active !== true || typeof session.identity?.id !== "string" || !session.identity.id.trim()) return null;
|
|
16
|
+
return { userId: session.identity.id, identity: session.identity };
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export {
|
|
21
|
+
createKratosSessionVerifier
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=chunk-F3O7CELI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/browser-auth/kratos-session.ts"],"sourcesContent":["/**\n * Creates a public Kratos whoami verifier without using the Admin API or minting sessions.\n * @param options - publicUrl is an HTTP(S) origin with root path and no embedded credentials/query/fragment; fetch defaults to global fetch and timeoutMs to 10000 milliseconds.\n * @returns An async verifier accepting cookie/sessionToken credentials and resolving userId plus provider identity, or null for absent credentials, 401/403 responses, inactive sessions, or missing identity IDs. sessionToken takes precedence over cookie.\n * @throws Synchronously for an invalid provider URL. Verification rejects transport, abort, invalid timeout, non-OK provider responses other than 401/403, and JSON parsing failures.\n * @remarks Credentials are forwarded only to the configured origin with redirects disabled and no-store caching. The host must trust this origin and separately resolve memberships and tenant lifecycle. This verifier creates no listeners or background work.\n * @example\n * ```typescript\n * import { createKratosSessionVerifier } from \"@alneas/eaos-server/browser-auth/kratos-session\";\n * const verify = createKratosSessionVerifier({ publicUrl: \"https://identity.example.com\" });\n * export async function authenticate(cookie: string | undefined) {\n * return verify({ cookie });\n * }\n * ```\n */\nexport function createKratosSessionVerifier(options: {\n /**\n * Trusted HTTP(S) Kratos origin with a root path and no embedded credentials, query, or fragment.\n */\npublicUrl: string;\n /**\n * Host transport for public whoami calls; defaults to global fetch, with redirects disabled and no-store caching.\n */\nfetch?: typeof fetch;\n /**\n * AbortSignal timeout in milliseconds for each whoami request; defaults to 10000 and invalid values fail when invoked.\n */\ntimeoutMs?: number }) {\n const base = new URL(options.publicUrl)\n if (!['http:', 'https:'].includes(base.protocol) || base.username || base.password || base.search || base.hash || base.pathname !== '/') throw new Error('Invalid Kratos endpoint')\n const request = options.fetch ?? fetch\n return async (credentials: { cookie?: string; sessionToken?: string }) => {\n if (!credentials.cookie && !credentials.sessionToken) return null\n const headers: Record<string, string> = { Accept: 'application/json' }\n // Do not mix potentially different identities from two transports.\n if (credentials.sessionToken) headers['X-Session-Token'] = credentials.sessionToken\n else if (credentials.cookie) headers.Cookie = credentials.cookie\n const response = await request(new URL('/sessions/whoami', base), { headers, cache: 'no-store', redirect: 'error', signal: AbortSignal.timeout(options.timeoutMs ?? 10_000) })\n if (response.status === 401 || response.status === 403) return null\n if (!response.ok) throw new Error('Identity provider unavailable')\n const session = await response.json() as any\n if (session.active !== true || typeof session.identity?.id !== 'string' || !session.identity.id.trim()) return null\n return { userId: session.identity.id as string, identity: session.identity as Record<string, unknown> }\n }\n}\n"],"mappings":";AAeO,SAAS,4BAA4B,SAYtB;AACpB,QAAM,OAAO,IAAI,IAAI,QAAQ,SAAS;AACtC,MAAI,CAAC,CAAC,SAAS,QAAQ,EAAE,SAAS,KAAK,QAAQ,KAAK,KAAK,YAAY,KAAK,YAAY,KAAK,UAAU,KAAK,QAAQ,KAAK,aAAa,IAAK,OAAM,IAAI,MAAM,yBAAyB;AAClL,QAAM,UAAU,QAAQ,SAAS;AACjC,SAAO,OAAO,gBAA4D;AACxE,QAAI,CAAC,YAAY,UAAU,CAAC,YAAY,aAAc,QAAO;AAC7D,UAAM,UAAkC,EAAE,QAAQ,mBAAmB;AAErE,QAAI,YAAY,aAAc,SAAQ,iBAAiB,IAAI,YAAY;AAAA,aAC9D,YAAY,OAAQ,SAAQ,SAAS,YAAY;AAC1D,UAAM,WAAW,MAAM,QAAQ,IAAI,IAAI,oBAAoB,IAAI,GAAG,EAAE,SAAS,OAAO,YAAY,UAAU,SAAS,QAAQ,YAAY,QAAQ,QAAQ,aAAa,GAAM,EAAE,CAAC;AAC7K,QAAI,SAAS,WAAW,OAAO,SAAS,WAAW,IAAK,QAAO;AAC/D,QAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,+BAA+B;AACjE,UAAM,UAAU,MAAM,SAAS,KAAK;AACpC,QAAI,QAAQ,WAAW,QAAQ,OAAO,QAAQ,UAAU,OAAO,YAAY,CAAC,QAAQ,SAAS,GAAG,KAAK,EAAG,QAAO;AAC/G,WAAO,EAAE,QAAQ,QAAQ,SAAS,IAAc,UAAU,QAAQ,SAAoC;AAAA,EACxG;AACF;","names":[]}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createLifecycleGuard,
|
|
3
|
+
resolveLifecycleBackend
|
|
4
|
+
} from "./chunk-L6PMAEMB.js";
|
|
5
|
+
import {
|
|
6
|
+
createAuthMiddleware
|
|
7
|
+
} from "./chunk-XIEY2OF4.js";
|
|
8
|
+
import {
|
|
9
|
+
createErrorHandler
|
|
10
|
+
} from "./chunk-AVDMLTPF.js";
|
|
11
|
+
import {
|
|
12
|
+
createModuleGuard
|
|
13
|
+
} from "./chunk-VC2PCK2S.js";
|
|
14
|
+
import {
|
|
15
|
+
createHealthRouter
|
|
16
|
+
} from "./chunk-R4ADP2DC.js";
|
|
17
|
+
import {
|
|
18
|
+
createMcpRouter
|
|
19
|
+
} from "./chunk-VF5YDZJC.js";
|
|
20
|
+
import {
|
|
21
|
+
createPluginEntitlementGuard,
|
|
22
|
+
resolveEngineEntitlementPrincipal
|
|
23
|
+
} from "./chunk-46UWPEW2.js";
|
|
24
|
+
|
|
25
|
+
// src/engine.ts
|
|
26
|
+
import { Hono } from "hono";
|
|
27
|
+
import { cors } from "hono/cors";
|
|
28
|
+
import { PluginRegistry } from "@alneas/eaos-core";
|
|
29
|
+
import { McpGatekeeper } from "@alneas/eaos-core";
|
|
30
|
+
import { SecretResolver } from "@alneas/eaos-core";
|
|
31
|
+
function defineConfig(config) {
|
|
32
|
+
return config;
|
|
33
|
+
}
|
|
34
|
+
var ErpEngine = class {
|
|
35
|
+
/** Public plugin registry populated during initialize; external mutation affects subsequently composed apps. */
|
|
36
|
+
registry = new PluginRegistry();
|
|
37
|
+
/** Shared MCP policy registry populated from plugin manifests during initialize. */
|
|
38
|
+
gatekeeper = new McpGatekeeper();
|
|
39
|
+
initialized = false;
|
|
40
|
+
config;
|
|
41
|
+
/**
|
|
42
|
+
* Retains host composition configuration for registration and future app creation.
|
|
43
|
+
* @param config - App label, plugin manifests, and optional host composition settings.
|
|
44
|
+
*/
|
|
45
|
+
constructor(config) {
|
|
46
|
+
this.config = config;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Registers manifests and gatekeeper policies and validates declared plugin secrets by default.
|
|
50
|
+
* @returns No value; resolves after registration and validation, or immediately after a prior successful initialization.
|
|
51
|
+
* @throws Rejects duplicate plugin IDs, registry failures, or secret validation failures.
|
|
52
|
+
* @remarks Registration occurs before secret validation, so failure can leave partial registry state. Concurrent initialization is not serialized and retrying a failed initialization may encounter already-registered IDs. Create a new engine after correcting failed setup. No migrations or plugin activation are performed.
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* import { createErpEngine } from "@alneas/eaos-server/engine";
|
|
56
|
+
* const engine = createErpEngine({ appName: "example-service", plugins: [] });
|
|
57
|
+
* await engine.initialize();
|
|
58
|
+
* console.log(engine.getRegisteredPlugins().length); // 0
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
async initialize() {
|
|
62
|
+
if (this.initialized) return;
|
|
63
|
+
console.log(`[ErpEngine] Initializing ${this.config.appName}...`);
|
|
64
|
+
for (const manifest of this.config.plugins) {
|
|
65
|
+
if (this.registry.get(manifest.id)) throw new Error(`Duplicate plugin: ${manifest.id}`);
|
|
66
|
+
this.registry.register(manifest);
|
|
67
|
+
if (manifest.agentCapabilities?.gatekeeperPolicies) {
|
|
68
|
+
for (const [toolName, policy] of Object.entries(
|
|
69
|
+
manifest.agentCapabilities.gatekeeperPolicies
|
|
70
|
+
)) {
|
|
71
|
+
this.gatekeeper.registerPolicy(toolName, policy);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (this.config.validateSecrets !== false && manifest.secrets && manifest.secrets.length > 0) {
|
|
75
|
+
await SecretResolver.validatePluginSecrets(manifest.id, manifest.secrets);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
this.initialized = true;
|
|
79
|
+
console.log(
|
|
80
|
+
`[ErpEngine] Successfully loaded ${this.registry.getAll().length} plugins.`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Composes registered plugin routes, shared middleware, optional MCP/custom routes, and public health endpoints.
|
|
85
|
+
* @param options - Live host adapters and route settings; see {@link CreateAppOptions}.
|
|
86
|
+
* @returns A new Hono app sharing this engine registry, gatekeeper, and configured adapters; it does not start a server.
|
|
87
|
+
* @throws Before initialization, or for synchronous middleware, plugin route factory, or health setup failures. Request-time adapter errors pass through the app error handler.
|
|
88
|
+
* @remarks Module guarding defaults on. Lifecycle enforcement is installed only when supplied, while declared plugin entitlements require their corresponding runtime checks. CORS uses configured origins with credentials enabled; unknown origins receive the first configured allow-origin value. Repeated calls create separate routers but may reuse host dependencies.
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* import { createErpEngine } from "@alneas/eaos-server/engine";
|
|
92
|
+
* const engine = createErpEngine({ appName: "example-service", plugins: [] });
|
|
93
|
+
* await engine.initialize();
|
|
94
|
+
* const app = engine.createApp();
|
|
95
|
+
* console.log((await app.request("/health/live")).status);
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
createApp(options) {
|
|
99
|
+
if (!this.initialized) throw new Error("Call initialize() before createApp()");
|
|
100
|
+
const app = new Hono();
|
|
101
|
+
app.onError(createErrorHandler());
|
|
102
|
+
if (this.config.cors?.allowOrigins && this.config.cors.allowOrigins.length > 0) {
|
|
103
|
+
const allowed = this.config.cors.allowOrigins;
|
|
104
|
+
app.use(
|
|
105
|
+
"*",
|
|
106
|
+
cors({
|
|
107
|
+
origin: (origin) => allowed.includes(origin) ? origin : allowed[0],
|
|
108
|
+
allowMethods: ["POST", "GET", "PUT", "PATCH", "DELETE", "OPTIONS"],
|
|
109
|
+
credentials: true
|
|
110
|
+
})
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
const verifier = options?.verifier || this.config.auth?.verifier;
|
|
114
|
+
if (verifier) {
|
|
115
|
+
app.use("*", createAuthMiddleware({ verifier, skipPaths: this.config.auth?.skipPaths }));
|
|
116
|
+
}
|
|
117
|
+
if (this.config.middleware) {
|
|
118
|
+
for (const mw of this.config.middleware) {
|
|
119
|
+
mw(app);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
for (const plugin of this.registry.getAll()) {
|
|
123
|
+
if (plugin.entitlement?.allowedTenants) {
|
|
124
|
+
const conceal = async (c, next) => {
|
|
125
|
+
const principal = await (options?.resolveEntitlementPrincipal ?? resolveEngineEntitlementPrincipal)(c);
|
|
126
|
+
if (!principal) return c.json({ error: "Unauthorized" }, 401);
|
|
127
|
+
if (!plugin.entitlement.allowedTenants.includes(principal.tenantId)) return c.json({ error: "Plugin unavailable" }, 404);
|
|
128
|
+
await next();
|
|
129
|
+
};
|
|
130
|
+
app.use(`${plugin.api.prefix}/*`, conceal);
|
|
131
|
+
}
|
|
132
|
+
if (options?.lifecycle) {
|
|
133
|
+
const guard = createLifecycleGuard(options.lifecycle, plugin.id);
|
|
134
|
+
app.use(plugin.api.prefix, guard);
|
|
135
|
+
app.use(`${plugin.api.prefix}/*`, guard);
|
|
136
|
+
}
|
|
137
|
+
if (options?.enableModuleGuard !== false) {
|
|
138
|
+
const guard = options?.requireModule ? options.requireModule(plugin.id) : createModuleGuard(plugin.id);
|
|
139
|
+
app.use(`${plugin.api.prefix}/*`, guard);
|
|
140
|
+
if (plugin.extensions) {
|
|
141
|
+
for (const ext of plugin.extensions) {
|
|
142
|
+
const requiredKey = ext.industry ? `industry_${ext.industry}` : ext.id;
|
|
143
|
+
const extGuard = options?.requireModule ? options.requireModule(requiredKey) : createModuleGuard(requiredKey);
|
|
144
|
+
app.use(`${plugin.api.prefix}/${ext.id}/*`, extGuard);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (plugin.entitlement) {
|
|
149
|
+
const guard = createPluginEntitlementGuard(plugin.id, plugin.entitlement, options?.entitlements, options?.resolveEntitlementPrincipal);
|
|
150
|
+
app.use(`${plugin.api.prefix}/*`, guard);
|
|
151
|
+
}
|
|
152
|
+
if (plugin.createRoutes) {
|
|
153
|
+
app.route(plugin.api.prefix, plugin.createRoutes(options?.pluginOptions?.[plugin.id]));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (options?.mcp) app.route(options.mcp.prefix ?? "/api/mcp", createMcpRouter(this, {
|
|
157
|
+
...options.mcp,
|
|
158
|
+
entitlements: options.entitlements ?? options.mcp.entitlements,
|
|
159
|
+
isPluginEnabled: async (principal, id) => (!options.lifecycle || await options.lifecycle.lifecycle.isEnabled(await resolveLifecycleBackend(options.lifecycle, principal.tenantId), principal.tenantId, id)) && (!options.mcp?.isPluginEnabled || await options.mcp.isPluginEnabled(principal, id))
|
|
160
|
+
}));
|
|
161
|
+
if (options?.customRoutes) {
|
|
162
|
+
for (const { prefix, router } of options.customRoutes) {
|
|
163
|
+
app.route(prefix, router);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
app.route("/", createHealthRouter({ appName: this.config.appName, ...options?.health }));
|
|
167
|
+
return app;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Reads the manifests currently registered in this engine.
|
|
171
|
+
* @returns Registry manifest list, empty before registration or with no configured plugins; objects are not deep-cloned by this method.
|
|
172
|
+
* @example
|
|
173
|
+
* ```typescript
|
|
174
|
+
* import { createErpEngine } from "@alneas/eaos-server/engine";
|
|
175
|
+
* const engine = createErpEngine({ appName: "example-service", plugins: [] });
|
|
176
|
+
* await engine.initialize();
|
|
177
|
+
* console.log(engine.getRegisteredPlugins()); // []
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
getRegisteredPlugins() {
|
|
181
|
+
return this.registry.getAll();
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Collects MCP tool definitions from all currently registered manifests.
|
|
185
|
+
* @returns Registry tool definitions, or an empty array when none exist; this list is not filtered for a request principal or tenant.
|
|
186
|
+
* @example
|
|
187
|
+
* ```typescript
|
|
188
|
+
* import { createErpEngine } from "@alneas/eaos-server/engine";
|
|
189
|
+
* const engine = createErpEngine({ appName: "example-service", plugins: [] });
|
|
190
|
+
* await engine.initialize();
|
|
191
|
+
* console.log(engine.getAllMcpTools()); // []
|
|
192
|
+
* ```
|
|
193
|
+
*/
|
|
194
|
+
getAllMcpTools() {
|
|
195
|
+
return this.registry.getAllMcpTools();
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Reads the host configuration retained at construction.
|
|
199
|
+
* @returns The original mutable configuration object; no cloning occurs.
|
|
200
|
+
* @example
|
|
201
|
+
* ```typescript
|
|
202
|
+
* import { createErpEngine } from "@alneas/eaos-server/engine";
|
|
203
|
+
* const engine = createErpEngine({ appName: "example-service", plugins: [] });
|
|
204
|
+
* await engine.initialize();
|
|
205
|
+
* console.log(engine.getConfig().appName);
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
getConfig() {
|
|
209
|
+
return this.config;
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
function createErpEngine(config) {
|
|
213
|
+
return new ErpEngine(config);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export {
|
|
217
|
+
defineConfig,
|
|
218
|
+
ErpEngine,
|
|
219
|
+
createErpEngine
|
|
220
|
+
};
|
|
221
|
+
//# sourceMappingURL=chunk-F4IITPGX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/engine.ts"],"sourcesContent":["import { resolveLifecycleBackend, createLifecycleGuard, type LifecycleRuntime } from './lifecycle/index'\nimport { createMcpRouter, type McpRouterOptions } from './mcp'\nimport { Hono } from 'hono'\nimport { cors } from 'hono/cors'\nimport { PluginRegistry } from '@alneas/eaos-core'\nimport { McpGatekeeper } from '@alneas/eaos-core'\nimport { SecretResolver } from '@alneas/eaos-core'\nimport { createModuleGuard } from './middleware/module-guard'\nimport { createAuthMiddleware, type AuthSessionVerifier } from './middleware/auth'\nimport { createErrorHandler } from './middleware/error-handler'\nimport type { PluginManifest } from '@alneas/eaos-core'\nimport type { EaosEnv } from '@alneas/eaos-core'\nimport { createHealthRouter, type HealthRouterOptions } from './health/index'\nimport { createPluginEntitlementGuard, resolveEngineEntitlementPrincipal, type PluginEntitlementRuntime, type EntitlementPrincipalResolver } from './entitlements/index'\n\n// ---------- Config 型 ----------\n\n/**\n * Engine composition settings retained by {@link ErpEngine}; host adapters own authentication and persistence.\n */\nexport interface EaosConfig {\n /** Nonblank application label used by public health responses. */\n appName: string\n /** Trusted plugin manifests registered sequentially during initialize. */\n plugins: PluginManifest[]\n /** Optional host UI theme metadata retained in config; the server engine does not apply it. */\n theme?: {\n /** Optional host UI accent color; not interpreted by this engine. */\n primaryColor?: string\n /** Optional host UI logo URL; not fetched by this engine. */\n logoUrl?: string\n }\n /** Optional host driver metadata retained in config; this engine does not create a database connection. */\n database?: {\n /** Selected host database dialect; does not create or migrate a connection. */\n driver: 'oracle' | 'supabase' | 'postgres'\n }\n /** Optional exact browser allowOrigins list; empty/absent disables CORS middleware. */\n cors?: {\n /** Exact allowed browser origins; credentials are enabled for configured CORS. */\n allowOrigins: string[]\n }\n /** Optional verifier and skipped path prefixes; see AuthMiddlewareOptions. */\n auth?: {\n /** Optional verified session/API-key adapter; omission installs no authentication. */\n verifier?: AuthSessionVerifier\n /** Authentication-exempt path prefixes; defaults follow createAuthMiddleware. */\n skipPaths?: string[]\n }\n /** Validate each manifest's declared secrets unless exactly false. Defaults to true. */\n validateSecrets?: boolean\n /** Host composition callbacks invoked synchronously after shared authentication and before plugin route guards; each receives the app and returns no value. */\n middleware?: Array<(app: Hono<EaosEnv>) => void>\n}\n\n/**\n * Returns an engine configuration unchanged while checking its TypeScript shape.\n * @param config - Configuration to retain; no runtime validation or cloning occurs.\n * @returns The same object reference.\n * @example\n * ```typescript\n * import { defineConfig } from \"@alneas/eaos-server/engine\";\n * const config = defineConfig({ appName: \"example-service\", plugins: [] });\n * console.log(config.appName);\n * ```\n */\nexport function defineConfig(config: EaosConfig): EaosConfig {\n return config\n}\n\n// ---------- Engine ----------\n\n/**\n * Per-application host authorization, route, and health adapters for {@link ErpEngine.createApp}.\n */\nexport interface CreateAppOptions {\n /** Optional shared runtime for declared commercial/usage entitlement admission. */\n entitlements?: PluginEntitlementRuntime\n /** Optional verified principal resolver; defaults to resolveEngineEntitlementPrincipal. */\n resolveEntitlementPrincipal?: EntitlementPrincipalResolver\n /** Optional current lifecycle/tenant/backend admission for plugin routes and MCP tools. */\n lifecycle?: LifecycleRuntime\n /** Optional module middleware factory called at composition for each plugin/extension requirement; defaults to createModuleGuard. */\n requireModule?: (moduleId: string) => any\n /** Optional authentication verifier overriding config.auth.verifier. */\n verifier?: AuthSessionVerifier\n /** Install module guards unless exactly false. Defaults to true. */\n enableModuleGuard?: boolean\n /** Per-plugin dependencies passed to the route factory. */\n pluginOptions?: Record<string, unknown>\n /** Optional MCP adapter configuration; prefix defaults to /api/mcp and shared entitlements take precedence. */\n mcp?: McpRouterOptions & { \n /**\n * Optional mount path for the shared MCP router; defaults to /api/mcp when the engine composes routes.\n */\n prefix?: string }\n /** Additional host routers mounted after plugin/MCP routes; no plugin-specific guard is automatically added. */\n customRoutes?: Array<{\n /** Host-selected mount prefix passed directly to Hono route composition; this entry receives no automatic plugin/module-specific guard. */\n prefix: string\n /** Trusted Hono child router; host composition must install its route-specific authorization before exposing handlers. */\n router: Hono<any>\n }>\n /** Optional dependency readiness checks and clock; engine appName is supplied automatically. */\n health?: Omit<HealthRouterOptions, 'appName'>\n}\n\n/**\n * Registers plugin manifests and composes Hono routes with host authentication, entitlement, and lifecycle adapters.\n * @remarks Constructing the engine creates no HTTP listener or persistent store. Initialize once before composing apps. Configuration is retained by reference. Authentication is installed only when a verifier is supplied; custom routes need their own authorization policies beyond the shared middleware.\n * @example\n * ```typescript\n * import { createErpEngine } from \"@alneas/eaos-server/engine\";\n * const engine = createErpEngine({ appName: \"example-service\", plugins: [] });\n * await engine.initialize();\n * const app = engine.createApp();\n * console.log((await app.request(\"/health/live\")).status); // 200\n * ```\n */\nexport class ErpEngine {\n /** Public plugin registry populated during initialize; external mutation affects subsequently composed apps. */\n readonly registry = new PluginRegistry()\n /** Shared MCP policy registry populated from plugin manifests during initialize. */\n readonly gatekeeper = new McpGatekeeper()\n private initialized = false\n private config: EaosConfig\n\n /**\n * Retains host composition configuration for registration and future app creation.\n * @param config - App label, plugin manifests, and optional host composition settings.\n */\n constructor(config: EaosConfig) {\n this.config = config\n }\n\n /**\n * Registers manifests and gatekeeper policies and validates declared plugin secrets by default.\n * @returns No value; resolves after registration and validation, or immediately after a prior successful initialization.\n * @throws Rejects duplicate plugin IDs, registry failures, or secret validation failures.\n * @remarks Registration occurs before secret validation, so failure can leave partial registry state. Concurrent initialization is not serialized and retrying a failed initialization may encounter already-registered IDs. Create a new engine after correcting failed setup. No migrations or plugin activation are performed.\n * @example\n * ```typescript\n * import { createErpEngine } from \"@alneas/eaos-server/engine\";\n * const engine = createErpEngine({ appName: \"example-service\", plugins: [] });\n * await engine.initialize();\n * console.log(engine.getRegisteredPlugins().length); // 0\n * ```\n */\n async initialize(): Promise<void> {\n if (this.initialized) return\n console.log(`[ErpEngine] Initializing ${this.config.appName}...`)\n\n for (const manifest of this.config.plugins) {\n if (this.registry.get(manifest.id)) throw new Error(`Duplicate plugin: ${manifest.id}`)\n this.registry.register(manifest)\n\n if (manifest.agentCapabilities?.gatekeeperPolicies) {\n for (const [toolName, policy] of Object.entries(\n manifest.agentCapabilities.gatekeeperPolicies\n )) {\n this.gatekeeper.registerPolicy(toolName, policy)\n }\n }\n\n if (\n this.config.validateSecrets !== false &&\n manifest.secrets &&\n manifest.secrets.length > 0\n ) {\n await SecretResolver.validatePluginSecrets(manifest.id, manifest.secrets)\n }\n }\n\n this.initialized = true\n console.log(\n `[ErpEngine] Successfully loaded ${this.registry.getAll().length} plugins.`\n )\n }\n\n /**\n * Composes registered plugin routes, shared middleware, optional MCP/custom routes, and public health endpoints.\n * @param options - Live host adapters and route settings; see {@link CreateAppOptions}.\n * @returns A new Hono app sharing this engine registry, gatekeeper, and configured adapters; it does not start a server.\n * @throws Before initialization, or for synchronous middleware, plugin route factory, or health setup failures. Request-time adapter errors pass through the app error handler.\n * @remarks Module guarding defaults on. Lifecycle enforcement is installed only when supplied, while declared plugin entitlements require their corresponding runtime checks. CORS uses configured origins with credentials enabled; unknown origins receive the first configured allow-origin value. Repeated calls create separate routers but may reuse host dependencies.\n * @example\n * ```typescript\n * import { createErpEngine } from \"@alneas/eaos-server/engine\";\n * const engine = createErpEngine({ appName: \"example-service\", plugins: [] });\n * await engine.initialize();\n * const app = engine.createApp();\n * console.log((await app.request(\"/health/live\")).status);\n * ```\n */\n createApp(options?: CreateAppOptions): Hono<EaosEnv> {\n if (!this.initialized) throw new Error(\"Call initialize() before createApp()\")\n const app = new Hono<EaosEnv>()\n\n // 1. エラーハンドラ登録\n app.onError(createErrorHandler())\n\n // 2. CORS\n if (this.config.cors?.allowOrigins && this.config.cors.allowOrigins.length > 0) {\n const allowed = this.config.cors.allowOrigins\n app.use(\n '*',\n cors({\n origin: (origin) =>\n allowed.includes(origin) ? origin : allowed[0],\n allowMethods: ['POST', 'GET', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],\n credentials: true,\n })\n )\n }\n\n // 3. 認証ミドルウェア (Ory Kratos / API Key / Bearer)\n const verifier = options?.verifier || this.config.auth?.verifier\n if (verifier) {\n app.use('*', createAuthMiddleware({ verifier, skipPaths: this.config.auth?.skipPaths }))\n }\n\n // 4. Config 層から注入された独自ミドルウェア\n if (this.config.middleware) {\n for (const mw of this.config.middleware) {\n mw(app)\n }\n }\n\n // 5. Plugin 層のルートを動的マウント & ライセンス認可ガード (requireModule)\n for (const plugin of this.registry.getAll()) {\n if (plugin.entitlement?.allowedTenants) {\n const conceal = async (c: any, next: () => Promise<void>) => {\n const principal = await (options?.resolveEntitlementPrincipal ?? resolveEngineEntitlementPrincipal)(c)\n if (!principal) return c.json({ error: 'Unauthorized' }, 401)\n if (!plugin.entitlement!.allowedTenants!.includes(principal.tenantId)) return c.json({ error: 'Plugin unavailable' }, 404)\n await next()\n }\n app.use(`${plugin.api.prefix}/*`, conceal)\n }\n if (options?.lifecycle) {\n const guard = createLifecycleGuard(options.lifecycle, plugin.id)\n app.use(plugin.api.prefix, guard)\n app.use(`${plugin.api.prefix}/*`, guard)\n }\n if (options?.enableModuleGuard !== false) {\n const guard = options?.requireModule ? options.requireModule(plugin.id) : createModuleGuard(plugin.id)\n app.use(`${plugin.api.prefix}/*`, guard)\n\n if (plugin.extensions) {\n for (const ext of plugin.extensions) {\n const requiredKey = ext.industry ? `industry_${ext.industry}` : ext.id\n const extGuard = options?.requireModule ? options.requireModule(requiredKey) : createModuleGuard(requiredKey)\n app.use(`${plugin.api.prefix}/${ext.id}/*`, extGuard)\n }\n }\n }\n\n if (plugin.entitlement) {\n const guard = createPluginEntitlementGuard(plugin.id, plugin.entitlement, options?.entitlements, options?.resolveEntitlementPrincipal)\n app.use(`${plugin.api.prefix}/*`, guard)\n }\n if (plugin.createRoutes) {\n app.route(plugin.api.prefix, plugin.createRoutes(options?.pluginOptions?.[plugin.id]))\n }\n }\n\n if (options?.mcp) app.route(options.mcp.prefix ?? '/api/mcp', createMcpRouter(this, {\n ...options.mcp,\n entitlements: options.entitlements ?? options.mcp.entitlements,\n isPluginEnabled: async (principal, id) =>\n (!options.lifecycle || await options.lifecycle.lifecycle.isEnabled(await resolveLifecycleBackend(options.lifecycle, principal.tenantId), principal.tenantId, id)) &&\n (!options.mcp?.isPluginEnabled || await options.mcp.isPluginEnabled(principal, id)),\n }))\n\n // 6. カスタムルートのマウント\n if (options?.customRoutes) {\n for (const { prefix, router } of options.customRoutes) {\n app.route(prefix, router)\n }\n }\n\n // 7. Liveness/readiness. Dependency checks are explicit host adapters.\n app.route('/', createHealthRouter({ appName: this.config.appName, ...options?.health }))\n\n return app\n }\n\n /**\n * Reads the manifests currently registered in this engine.\n * @returns Registry manifest list, empty before registration or with no configured plugins; objects are not deep-cloned by this method.\n * @example\n * ```typescript\n * import { createErpEngine } from \"@alneas/eaos-server/engine\";\n * const engine = createErpEngine({ appName: \"example-service\", plugins: [] });\n * await engine.initialize();\n * console.log(engine.getRegisteredPlugins()); // []\n * ```\n */\n getRegisteredPlugins(): PluginManifest[] {\n return this.registry.getAll()\n }\n\n /**\n * Collects MCP tool definitions from all currently registered manifests.\n * @returns Registry tool definitions, or an empty array when none exist; this list is not filtered for a request principal or tenant.\n * @example\n * ```typescript\n * import { createErpEngine } from \"@alneas/eaos-server/engine\";\n * const engine = createErpEngine({ appName: \"example-service\", plugins: [] });\n * await engine.initialize();\n * console.log(engine.getAllMcpTools()); // []\n * ```\n */\n getAllMcpTools() {\n return this.registry.getAllMcpTools()\n }\n\n /**\n * Reads the host configuration retained at construction.\n * @returns The original mutable configuration object; no cloning occurs.\n * @example\n * ```typescript\n * import { createErpEngine } from \"@alneas/eaos-server/engine\";\n * const engine = createErpEngine({ appName: \"example-service\", plugins: [] });\n * await engine.initialize();\n * console.log(engine.getConfig().appName);\n * ```\n */\n getConfig(): EaosConfig {\n return this.config\n }\n}\n\n/**\n * Creates an uninitialized engine retaining the supplied host configuration.\n * @param config - Engine composition settings; see {@link EaosConfig}.\n * @returns A new engine; await initialize before createApp.\n * @example\n * ```typescript\n * import { createErpEngine } from \"@alneas/eaos-server/engine\";\n * const engine = createErpEngine({ appName: \"example-service\", plugins: [] });\n * await engine.initialize();\n * const app = engine.createApp();\n * console.log((await app.request(\"/health/live\")).status);\n * ```\n */\nexport function createErpEngine(config: EaosConfig): ErpEngine {\n return new ErpEngine(config)\n}\n"],"mappings":"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","names":[]}
|