@xopcai/xopc 0.0.117 → 0.0.118
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/README.md +24 -23
- package/README.zh-CN.md +45 -42
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BBLhJ2C6.js → agent-avatar-dicebear-dzUrQoeZ.js} +1 -1
- package/dist/gateway/static/root/assets/agents-BCxZbkOw.js +2 -0
- package/dist/gateway/static/root/assets/{app-management-settings-panel-CBpLONvG.js → app-management-settings-panel-bxYJVJpx.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-CGcc54yj.js → appearance-settings-BCIykXlI.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-DdDx0V4z.js → apps-page--wMEL00f.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-DZsVqMhU.js → archive-plugin-Cki4SfU2.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-CIol6JWX.js → attachment-load-D-KnS2Do.js} +1 -1
- package/dist/gateway/static/root/assets/{binary-plugins-B3UauMfp.js → binary-plugins-D2sgvJja.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-2HJoFchH.js → block-editor-DIq-4Gvb.js} +27 -27
- package/dist/gateway/static/root/assets/browser-settings-page-DRhKdn81.js +8 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-XQoMTI0A.js → capability-presets-api-CorhiHlg.js} +1 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-qFx9Jtce.js +1 -0
- package/dist/gateway/static/root/assets/channels-settings-BAwAkqIA.js +1 -0
- package/dist/gateway/static/root/assets/connectors-page-BQLcfitM.js +2 -0
- package/dist/gateway/static/root/assets/{cron-api-R41aQCX9.js → cron-api-qGwmL-24.js} +1 -1
- package/dist/gateway/static/root/assets/cron-page-BBWMAj8-.js +3 -0
- package/dist/gateway/static/root/assets/{dreaming-settings-Bceaw1PG.js → dreaming-settings-Dw89Obml.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-DX5WRE_t.js → extension-debug-page-DYu1KaFQ.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-Buah7Bw-.js → extension-page-B3W6QwlZ.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-DuroLVnf.js → extension-settings-page-D7VQ-cxE.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-B5zdl27C.js → fetch-B7xDPu-R.js} +1 -1
- package/dist/gateway/static/root/assets/{format-interval-label-Dn_QKIqb.js → format-interval-label-BzxafKxR.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-gT4ZhE7h.js → gateway-config-api-BTBLSeUu.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-iISWAZRm.js → gateway-settings-Cmwy58rS.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-B3kL8KGY.js → gateway-startup-retry-CYj9FWCp.js} +1 -1
- package/dist/gateway/static/root/assets/goal-detail-page-l7mu5GWX.js +1 -0
- package/dist/gateway/static/root/assets/{goals-config-api-AR-fVh0P.js → goals-config-api-CQQgzPr3.js} +1 -1
- package/dist/gateway/static/root/assets/{goals-page-Cpb21ezg.js → goals-page-BHitvJAv.js} +2 -2
- package/dist/gateway/static/root/assets/{goals-settings-CPAuFwoD.js → goals-settings-CYVY4NGp.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-D7bKFEeO.js → heartbeat-config-api-DriO_CN9.js} +1 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-CUQTKxg7.js +1 -0
- package/dist/gateway/static/root/assets/index-C17Tsd_b.css +1 -0
- package/dist/gateway/static/root/assets/{index-CwhK8qCh.js → index-Cc41r16l.js} +120 -51
- package/dist/gateway/static/root/assets/{interval-presets-0DtsnxE0.js → interval-presets-DFPCKW_W.js} +1 -1
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BPREtN8B.js → keyboard-shortcuts-settings-CcVcqstx.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-DefCgF4o.js → logs-page-C2Uqvae9.js} +2 -2
- package/dist/gateway/static/root/assets/{markdown-split-ChbR9LGO.js → markdown-split-BwOFrJ2E.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-B82oP80n.js → media-plugins-Cnz6Q5G6.js} +1 -1
- package/dist/gateway/static/root/assets/messages-B1iSKjiw.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-panel-BfLfcta8.js +2 -0
- package/dist/gateway/static/root/assets/note-detail-page-BjwOQBfT.js +2 -0
- package/dist/gateway/static/root/assets/{note-image-lightbox-CDknITM3.js → note-image-lightbox-B-Svpmza.js} +1 -1
- package/dist/gateway/static/root/assets/notes-page-DktdBiwB.js +1 -0
- package/dist/gateway/static/root/assets/{preview-open-alternatives-DV3xQsWB.js → preview-open-alternatives-Bss4TiwP.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-rfVx96fq.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-BODCXnvY.js → save-bar-controls-BRNjdgKq.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-CgJSCD3B.js → schedule-field-CUCKODde.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-qtfEI6QM.js → schema-form-Dub9sy8r.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-DbtMFuuH.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-5re5gAnP.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-BHZKjVcS.js → settings-collapsible-section-BeFLavGi.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-5i35D-J1.js → settings-form-section-dmyaPOTG.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-D-WMyLlj.js +1 -0
- package/dist/gateway/static/root/assets/setup-status-panel-Cl-DEJAU.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-B0H63tDv.js → share-preview-page-C8glrdqe.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-CyPVvbLt.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-CleTH1oz.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-Ck8hdXqR.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-DXs2VmBt.js → system-settings-panel-DI-LN_8G.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-4gPuydz_.js → typed-models-lib-kX9duch4.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-BCjP_VHb.js → use-channel-catalog-DqlWTsDb.js} +1 -1
- package/dist/gateway/static/root/assets/user-profile-settings-panel-B-UFPMXy.js +1 -0
- package/dist/gateway/static/root/assets/utils-Dm0hKalR.js +1 -0
- package/dist/gateway/static/root/assets/voice-api-key-field-C73IVZeC.js +1 -0
- package/dist/gateway/static/root/assets/{voice-player-store-BlF9V05n.js → voice-player-store-C_ArLJPM.js} +1 -1
- package/dist/gateway/static/root/assets/workflows-page-BtFGp2y_.js +18 -0
- package/dist/gateway/static/root/index.html +5 -5
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.js +2 -1
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/agent-scope.js +0 -2
- package/dist/src/agent/agent-scope.js.map +1 -1
- package/dist/src/agent/background-review/prompts.d.ts +2 -2
- package/dist/src/agent/background-review/prompts.js +2 -2
- package/dist/src/agent/background-review/prompts.js.map +1 -1
- package/dist/src/agent/background-review/settings.d.ts +1 -1
- package/dist/src/agent/background-review/settings.js +7 -8
- package/dist/src/agent/background-review/settings.js.map +1 -1
- package/dist/src/agent/bootstrap/bootstrap-cache.d.ts +1 -0
- package/dist/src/agent/bootstrap/bootstrap-cache.js +4 -3
- package/dist/src/agent/bootstrap/bootstrap-cache.js.map +1 -1
- package/dist/src/agent/bootstrap/bootstrap-files.d.ts +4 -0
- package/dist/src/agent/bootstrap/bootstrap-files.js +4 -3
- package/dist/src/agent/bootstrap/bootstrap-files.js.map +1 -1
- package/dist/src/agent/bootstrap/filter-bootstrap-files.js +4 -2
- package/dist/src/agent/bootstrap/filter-bootstrap-files.js.map +1 -1
- package/dist/src/agent/bootstrap/load-bootstrap-files.d.ts +2 -1
- package/dist/src/agent/bootstrap/load-bootstrap-files.js +17 -16
- package/dist/src/agent/bootstrap/load-bootstrap-files.js.map +1 -1
- package/dist/src/agent/bootstrap/types.d.ts +1 -1
- package/dist/src/agent/context/workspace-templates/AGENTS.md +1 -1
- package/dist/src/agent/context/workspace.d.ts +4 -2
- package/dist/src/agent/context/workspace.js +5 -4
- package/dist/src/agent/context/workspace.js.map +1 -1
- package/dist/src/agent/embedded/run-for-session.js +4 -1
- package/dist/src/agent/embedded/run-for-session.js.map +1 -1
- package/dist/src/agent/fallback/candidates.js +10 -11
- package/dist/src/agent/fallback/candidates.js.map +1 -1
- package/dist/src/agent/memory/builtin-memory-store.d.ts +4 -2
- package/dist/src/agent/memory/builtin-memory-store.js +11 -6
- package/dist/src/agent/memory/builtin-memory-store.js.map +1 -1
- package/dist/src/agent/memory/builtin-provider.js +36 -7
- package/dist/src/agent/memory/builtin-provider.js.map +1 -1
- package/dist/src/agent/memory/candidate-extractor.d.ts +6 -0
- package/dist/src/agent/memory/candidate-extractor.js +60 -0
- package/dist/src/agent/memory/candidate-extractor.js.map +1 -0
- package/dist/src/agent/memory/manager.d.ts +2 -1
- package/dist/src/agent/memory/manager.js +27 -3
- package/dist/src/agent/memory/manager.js.map +1 -1
- package/dist/src/agent/memory/memory-config.js +3 -0
- package/dist/src/agent/memory/memory-config.js.map +1 -1
- package/dist/src/agent/memory/prefetch-coordinator.js.map +1 -1
- package/dist/src/agent/memory/types.d.ts +27 -4
- package/dist/src/agent/prompt/memory/index.d.ts +4 -2
- package/dist/src/agent/prompt/memory/index.js +18 -12
- package/dist/src/agent/prompt/memory/index.js.map +1 -1
- package/dist/src/agent/prompt/sections/memory-skills.js +1 -1
- package/dist/src/agent/prompt/sections/memory-skills.js.map +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +4 -19
- package/dist/src/agent/prompt/service-prompt-builder.js.map +1 -1
- package/dist/src/agent/reply/post-compaction-context.js +1 -3
- package/dist/src/agent/reply/post-compaction-context.js.map +1 -1
- package/dist/src/agent/reply/startup-context.js +1 -5
- package/dist/src/agent/reply/startup-context.js.map +1 -1
- package/dist/src/agent/service.d.ts +3 -3
- package/dist/src/agent/service.js +7 -8
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/tools/curated-memory-tool.js +57 -2
- package/dist/src/agent/tools/curated-memory-tool.js.map +1 -1
- package/dist/src/agent/tools/web-extract.js +6 -8
- package/dist/src/agent/tools/web-extract.js.map +1 -1
- package/dist/src/agent-manifest/index.js +2 -2
- package/dist/src/agent-manifest/resolver.d.ts +3 -2
- package/dist/src/agent-manifest/resolver.js +5 -3
- package/dist/src/agent-manifest/resolver.js.map +1 -1
- package/dist/src/agent-manifest/schema.d.ts +232 -0
- package/dist/src/agent-manifest/schema.js +4 -2
- package/dist/src/agent-manifest/schema.js.map +1 -1
- package/dist/src/agent-manifest/validator.d.ts +3 -2
- package/dist/src/agent-manifest/validator.js +2 -1
- package/dist/src/agent-manifest/validator.js.map +1 -1
- package/dist/src/channels/pipeline.d.ts +1 -1
- package/dist/src/channels/pipeline.js.map +1 -1
- package/dist/src/chat-commands/agent-edit.js +0 -1
- package/dist/src/chat-commands/agent-edit.js.map +1 -1
- package/dist/src/chat-commands/builtins/model.js +2 -2
- package/dist/src/chat-commands/builtins/model.js.map +1 -1
- package/dist/src/cli/command-manifest.d.ts +1 -1
- package/dist/src/cli/command-manifest.js +1 -1
- package/dist/src/cli/command-manifest.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -0
- package/dist/src/cli/commands/doctor/checks/provider-auth.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/workspace-status.js +0 -1
- package/dist/src/cli/commands/doctor/checks/workspace-status.js.map +1 -1
- package/dist/src/cli/commands/init.js +7 -6
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/models.js +13 -31
- package/dist/src/cli/commands/models.js.map +1 -1
- package/dist/src/cli/commands/onboard/model.js +17 -10
- package/dist/src/cli/commands/onboard/model.js.map +1 -1
- package/dist/src/cli/commands/onboard.js +2 -2
- package/dist/src/cli/commands/onboard.js.map +1 -1
- package/dist/src/cli/commands/tui.js +2 -2
- package/dist/src/cli/commands/tui.js.map +1 -1
- package/dist/src/cli/index.d.ts +1 -0
- package/dist/src/cli/index.js +10 -5
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/registry.js +1 -1
- package/dist/src/cli/registry.js.map +1 -1
- package/dist/src/cli/templates.d.ts +1 -1
- package/dist/src/cli/templates.js +1 -11
- package/dist/src/cli/templates.js.map +1 -1
- package/dist/src/commands/agents.config.js +2 -10
- package/dist/src/commands/agents.config.js.map +1 -1
- package/dist/src/config/agent-profile.js +3 -2
- package/dist/src/config/agent-profile.js.map +1 -1
- package/dist/src/config/agent-typed-models.js +3 -5
- package/dist/src/config/agent-typed-models.js.map +1 -1
- package/dist/src/config/index.js +2 -2
- package/dist/src/config/paths.d.ts +8 -1
- package/dist/src/config/paths.js +16 -3
- package/dist/src/config/paths.js.map +1 -1
- package/dist/src/config/schema.d.ts +32 -32
- package/dist/src/config/schema.js +46 -26
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/gateway/agents-admin.d.ts +7 -0
- package/dist/src/gateway/agents-admin.js +51 -20
- package/dist/src/gateway/agents-admin.js.map +1 -1
- package/dist/src/gateway/chat-stream/mapper.js +9 -2
- package/dist/src/gateway/chat-stream/mapper.js.map +1 -1
- package/dist/src/gateway/global-defaults-admin.d.ts +36 -0
- package/dist/src/gateway/global-defaults-admin.js +146 -0
- package/dist/src/gateway/global-defaults-admin.js.map +1 -0
- package/dist/src/gateway/hono/routes/agents.js +33 -1
- package/dist/src/gateway/hono/routes/agents.js.map +1 -1
- package/dist/src/gateway/hono/routes/commands-skills.js +4 -5
- package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
- package/dist/src/gateway/hono/routes/global-defaults.d.ts +3 -0
- package/dist/src/gateway/hono/routes/global-defaults.js +61 -0
- package/dist/src/gateway/hono/routes/global-defaults.js.map +1 -0
- package/dist/src/gateway/hono/routes/lazy-bundles.js +11 -3
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/memory.js +75 -4
- package/dist/src/gateway/hono/routes/memory.js.map +1 -1
- package/dist/src/gateway/hono/routes/models.js +1 -1
- package/dist/src/gateway/service/marketplace-service.d.ts +4 -4
- package/dist/src/gateway/service/marketplace-service.js +11 -7
- package/dist/src/gateway/service/marketplace-service.js.map +1 -1
- package/dist/src/notes/service.js +3 -1
- package/dist/src/notes/service.js.map +1 -1
- package/dist/src/providers/index.d.ts +4 -5
- package/dist/src/providers/index.js +16 -16
- package/dist/src/providers/index.js.map +1 -1
- package/dist/src/session/session-workspace.js +2 -7
- package/dist/src/session/session-workspace.js.map +1 -1
- package/dist/src/session/store.js +0 -5
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/storage/sqlite/index.d.ts +1 -1
- package/dist/src/storage/sqlite/index.js +2 -2
- package/dist/src/storage/sqlite/memory-index-repository.d.ts +1 -0
- package/dist/src/storage/sqlite/memory-index-repository.js +15 -14
- package/dist/src/storage/sqlite/memory-index-repository.js.map +1 -1
- package/dist/src/storage/sqlite/memory-records-repository.d.ts +44 -1
- package/dist/src/storage/sqlite/memory-records-repository.js +164 -20
- package/dist/src/storage/sqlite/memory-records-repository.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/014_memory_record_governance.sql +10 -0
- package/dist/src/storage/sqlite/migrations/015_memory_trace_feedback.sql +4 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/tui/backends/embedded-backend.d.ts +3 -0
- package/dist/src/tui/backends/embedded-backend.js +37 -20
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.d.ts +1 -0
- package/dist/src/tui/backends/gateway-sse-backend.js +16 -3
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
- package/dist/src/tui/components/tui-header.d.ts +0 -1
- package/dist/src/tui/components/tui-header.js +3 -8
- package/dist/src/tui/components/tui-header.js.map +1 -1
- package/dist/src/tui/tui-startup-resources.js +2 -1
- package/dist/src/tui/tui-startup-resources.js.map +1 -1
- package/dist/src/tui/tui-startup-text.js +12 -12
- package/dist/src/tui/tui-startup-text.js.map +1 -1
- package/dist/src/tui/tui.js +4 -1
- package/dist/src/tui/tui.js.map +1 -1
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/agents-C6xgagZd.js +0 -71
- package/dist/gateway/static/root/assets/browser-settings-page-CUOO-PQk.js +0 -8
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-CfqF-kGr.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-BYyRzsex.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-DIvEz4NX.js +0 -2
- package/dist/gateway/static/root/assets/cron-page-D97nFqQD.js +0 -3
- package/dist/gateway/static/root/assets/goal-detail-page-DCUROLMQ.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-CC69vNx0.js +0 -1
- package/dist/gateway/static/root/assets/index-CyfhARL-.css +0 -1
- package/dist/gateway/static/root/assets/messages-Cf1O9JB0.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-DmKiIihT.js +0 -2
- package/dist/gateway/static/root/assets/note-detail-page-CxxfLRJZ.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-X2slSx7V.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-BvmUWqgu.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-B0yESuuL.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-q2M8RKOo.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-CGozabLD.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-FoOSe6nU.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-Cy5zWyYQ.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-DaZNFro9.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-CnwtUzvw.js +0 -2
- package/dist/gateway/static/root/assets/voice-api-key-field-DvKiOglO.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-CAVZcONQ.js +0 -18
- package/dist/src/agent/context/workspace-templates/USER.md +0 -24
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.js","names":["getModelsJsonPath"],"sources":["../../../../../src/cli/commands/onboard/model.ts"],"sourcesContent":["/**\n * Catalog-driven model configuration for onboarding.\n */\n\nimport { confirm, input, select } from '@inquirer/prompts';\n\nimport { CredentialResolver } from '../../../auth/credentials.js';\nimport {\n getModelsJsonPath,\n loadModelsJson,\n saveModelsJson,\n type ModelsJsonConfig,\n} from '../../../config/models-json.js';\nimport type { Config } from '../../../config/schema.js';\nimport { getAgentDefaultModelRef } from '../../../config/schema.js';\nimport {\n getAllProviders,\n getApiKeyFromEnv,\n getModelRegistry,\n getModelsByProvider,\n getProviderDisplayName,\n providerSupportsApiKey,\n providerSupportsOAuth,\n} from '../../../providers/index.js';\nimport {\n getProviderHint,\n getRecommendedModelsForProvider,\n sortModelsForPicker,\n sortProvidersForPicker,\n} from '../../../providers/presentation.js';\nimport { listProfilesForProvider } from '../../../auth/profiles/index.js';\nimport { getOAuthProvider } from '../../utils/oauth-providers.js';\nimport { runCliOAuthLogin } from '../../utils/oauth-login.js';\nimport type { CLIContext } from '../../registry.js';\nimport { colors } from '../../utils/colors.js';\n\ntype ModelChoice = { value: string; name: string; description?: string };\ntype CustomApiKind = 'openai-completions' | 'openai-responses' | 'anthropic-messages';\n\nfunction setPrimaryModel(config: Config, workspacePath: string, modelRef: string): Config {\n const id = config.agents.default ?? config.agents.list[0]?.id ?? 'main';\n const index = config.agents.list.findIndex((entry) => entry.id === id);\n if (index >= 0) {\n const agent = config.agents.list[index]!;\n config.agents.list[index] = {\n ...agent,\n workspace: { root: workspacePath },\n models: {\n ...agent.models,\n defaultRole: agent.models.defaultRole || 'deep',\n roles: { ...agent.models.roles, [agent.models.defaultRole || 'deep']: { model: modelRef } },\n },\n };\n }\n return config;\n}\n\nfunction formatRecommended(provider: string): string | undefined {\n const labels = getRecommendedModelsForProvider(provider, 3).map((m) => m.name || m.id);\n return labels.length > 0 ? `Recommended: ${labels.join(', ')}` : getProviderHint(provider);\n}\n\nfunction providerChoices(): Array<{ value: string; name: string; description?: string }> {\n const providers = sortProvidersForPicker(getAllProviders());\n const choices = providers.map((provider) => ({\n value: provider,\n name: getProviderDisplayName(provider),\n description: formatRecommended(provider),\n }));\n choices.push({\n value: 'custom-api',\n name: 'Custom API',\n description: 'OpenAI-compatible, OpenAI Responses, or Anthropic-compatible endpoint',\n });\n return choices;\n}\n\nfunction modelChoiceName(choice: ModelChoice): string {\n return choice.description ? `${choice.name} ${colors.gray(choice.description)}` : choice.name;\n}\n\nfunction getModelsForProvider(provider: string): ModelChoice[] {\n return sortModelsForPicker(getModelsByProvider(provider)).map((m) => {\n const badges = [m.reasoning ? 'reasoning' : '', m.input?.includes('image') ? 'vision' : '']\n .filter(Boolean)\n .join(', ');\n return {\n value: `${m.provider}/${m.id}`,\n name: m.name || m.id,\n description: badges || undefined,\n };\n });\n}\n\nasync function doOAuthLogin(provider: string): Promise<boolean> {\n const config = getOAuthProvider(provider);\n if (!config) {\n console.error(`OAuth not supported for provider: ${provider}`);\n return false;\n }\n\n console.log(`\\n🔐 Starting ${config.displayName} OAuth login...`);\n try {\n await runCliOAuthLogin({ provider, onProgress: (message) => console.log(' →', message) });\n return true;\n } catch (error) {\n console.error('❌ OAuth login failed:', error);\n return false;\n }\n}\n\nfunction joinEndpoint(baseUrl: string, suffix: string): string {\n return `${baseUrl.replace(/\\/+$/, '')}/${suffix.replace(/^\\/+/, '')}`;\n}\n\nasync function probeCustomProvider(params: {\n baseUrl: string;\n apiKey: string;\n modelId: string;\n api: CustomApiKind;\n}): Promise<void> {\n const timeout = AbortSignal.timeout(30_000);\n const commonHeaders = {\n 'content-type': 'application/json',\n authorization: `Bearer ${params.apiKey}`,\n };\n\n const request =\n params.api === 'anthropic-messages'\n ? {\n url: joinEndpoint(params.baseUrl, '/messages'),\n headers: { ...commonHeaders, 'anthropic-version': '2023-06-01' },\n body: { model: params.modelId, max_tokens: 1, messages: [{ role: 'user', content: 'ping' }] },\n }\n : params.api === 'openai-responses'\n ? {\n url: joinEndpoint(params.baseUrl, '/responses'),\n headers: commonHeaders,\n body: { model: params.modelId, input: 'ping', max_output_tokens: 1 },\n }\n : {\n url: joinEndpoint(params.baseUrl, '/chat/completions'),\n headers: commonHeaders,\n body: { model: params.modelId, messages: [{ role: 'user', content: 'ping' }], max_tokens: 1 },\n };\n\n const res = await fetch(request.url, {\n method: 'POST',\n headers: request.headers,\n body: JSON.stringify(request.body),\n signal: timeout,\n });\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(`Probe failed (${res.status}) at ${request.url}${text ? `: ${text.slice(0, 300)}` : ''}`);\n }\n}\n\nfunction defaultProviderIdFromBaseUrl(baseUrl: string): string {\n try {\n const url = new URL(baseUrl);\n return url.hostname\n .replace(/^api\\./, '')\n .split('.')\n .filter(Boolean)\n .slice(0, 2)\n .join('-')\n .toLowerCase()\n .replace(/[^a-z0-9-_]+/g, '-')\n .replace(/^-+|-+$/g, '') || 'custom';\n } catch {\n return 'custom';\n }\n}\n\nfunction validateProviderId(value: string): true | string {\n return /^[a-z0-9]([a-z0-9-_]*[a-z0-9])?$/.test(value)\n ? true\n : 'Use lowercase letters, numbers, hyphens, or underscores; start/end with a letter or number.';\n}\n\nasync function setupCustomApi(config: Config, ctx: CLIContext): Promise<Config> {\n console.log('\\n🔌 Custom API provider\\n');\n\n const baseUrl = (await input({\n message: 'API base URL:',\n default: 'https://api.example.com/v1',\n validate: (value) => URL.canParse(value) || 'Enter a valid URL',\n })).trim();\n\n const apiKey = (await input({\n message: 'API key:',\n validate: (value) => value.trim().length > 0 || 'Required',\n })).trim();\n\n const api = await select<CustomApiKind>({\n message: 'Compatibility:',\n choices: [\n { value: 'openai-completions', name: 'OpenAI-compatible Chat Completions' },\n { value: 'openai-responses', name: 'OpenAI Responses' },\n { value: 'anthropic-messages', name: 'Anthropic Messages' },\n ],\n });\n\n const modelId = (await input({\n message: 'Model ID:',\n validate: (value) => value.trim().length > 0 || 'Required',\n })).trim();\n\n console.log('\\n→ Probing endpoint...');\n await probeCustomProvider({ baseUrl, apiKey, modelId, api });\n console.log(colors.green('✓ Probe succeeded'));\n\n const existingProviders = new Set(getAllProviders());\n const providerId = (await input({\n message: 'Provider ID:',\n default: defaultProviderIdFromBaseUrl(baseUrl),\n validate: (value) => {\n const valid = validateProviderId(value.trim());\n if (valid !== true) return valid;\n if (existingProviders.has(value.trim())) return 'Provider ID already exists; choose a new ID.';\n return true;\n },\n })).trim();\n\n const path = getModelsJsonPath();\n const { config: modelsConfig } = loadModelsJson(path);\n const nextModelsConfig: ModelsJsonConfig = {\n providers: {\n ...(modelsConfig.providers ?? {}),\n [providerId]: {\n baseUrl,\n apiKey,\n api,\n models: [{ id: modelId, name: modelId, api, contextWindow: 128000, input: ['text'] }],\n },\n },\n };\n const saved = saveModelsJson(path, nextModelsConfig);\n if (!saved.success) {\n throw new Error(saved.error || 'Failed to save models.json');\n }\n getModelRegistry().refresh();\n\n const ref = `${providerId}/${modelId}`;\n console.log('\\n✅ Custom model configured:', ref);\n return setPrimaryModel(config, ctx.workspacePath, ref);\n}\n\nasync function ensureProviderCredential(provider: string, providerName: string): Promise<boolean> {\n const existingProfiles = listProfilesForProvider(provider);\n if (existingProfiles.length > 0) {\n console.log(`\\n${colors.green('✓')} Found existing credentials for ${providerName}`);\n return await confirm({ message: 'Use existing credentials?', default: true });\n }\n\n const envKey = getApiKeyFromEnv(provider);\n if (envKey) {\n console.log(`\\n${colors.green('✓')} Found API key for ${providerName} in environment`);\n return true;\n }\n\n const supportsOAuth = providerSupportsOAuth(provider);\n const supportsApiKey = providerSupportsApiKey(provider);\n\n if (supportsOAuth && !supportsApiKey) {\n return await doOAuthLogin(provider);\n }\n\n let useOAuth = false;\n if (supportsOAuth && supportsApiKey) {\n const authMethod = await select<'api_key' | 'oauth'>({\n message: `How would you like to authenticate with ${providerName}?`,\n choices: [\n { value: 'api_key', name: 'API key' },\n { value: 'oauth', name: 'OAuth login' },\n ],\n });\n useOAuth = authMethod === 'oauth';\n }\n\n if (useOAuth) {\n const ok = await doOAuthLogin(provider);\n if (ok) return true;\n console.log('\\n⚠️ OAuth login failed. Enter an API key instead.');\n }\n\n if (!supportsApiKey) return false;\n const apiKey = await input({\n message: `API key for ${providerName}:`,\n validate: (value) => value.trim().length > 0 || 'Required',\n });\n const resolver = new CredentialResolver();\n await resolver.saveApiKey(provider, apiKey.trim(), { profileName: 'default' });\n return true;\n}\n\nexport async function setupModel(existingConfig: Config | null, ctx: CLIContext): Promise<Config> {\n console.log('\\n🤖 Step: AI Model\\n');\n\n const config = existingConfig || ({} as Config);\n const currentModel = getAgentDefaultModelRef(config);\n\n if (currentModel) {\n console.log('Current model:', currentModel);\n const keepCurrent = await confirm({ message: 'Keep using this model?', default: true });\n if (keepCurrent) {\n console.log('✅ Keeping:', currentModel);\n return config;\n }\n }\n\n const provider = await select({\n message: 'Model/auth provider:',\n choices: providerChoices(),\n });\n\n if (provider === 'custom-api') {\n return await setupCustomApi(config, ctx);\n }\n\n const providerName = getProviderDisplayName(provider);\n const credentialOk = await ensureProviderCredential(provider, providerName);\n if (!credentialOk) {\n console.error(`\\n❌ Could not configure credentials for ${providerName}.`);\n return config;\n }\n\n const modelChoices = getModelsForProvider(provider);\n if (modelChoices.length === 0) {\n throw new Error(`No catalog models found for ${providerName}. Add a Custom API provider instead.`);\n }\n\n console.log(`\\n📋 Models for ${providerName}:`);\n const model = await select({\n message: 'Model:',\n choices: modelChoices.map((choice) => ({ ...choice, name: modelChoiceName(choice) })),\n });\n\n console.log('\\n✅ Model configured:', model);\n return setPrimaryModel(config, ctx.workspacePath, model);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"model.js","names":["getModelsJsonPath"],"sources":["../../../../../src/cli/commands/onboard/model.ts"],"sourcesContent":["/**\n * Catalog-driven model configuration for onboarding.\n */\n\nimport { confirm, input, select } from '@inquirer/prompts';\n\nimport { CredentialResolver } from '../../../auth/credentials.js';\nimport {\n getModelsJsonPath,\n loadModelsJson,\n saveModelsJson,\n type ModelsJsonConfig,\n} from '../../../config/models-json.js';\nimport type { Config } from '../../../config/schema.js';\nimport { getAgentDefaultModelRef } from '../../../config/schema.js';\nimport { prepareUpdateGlobalDefaults } from '../../../gateway/global-defaults-admin.js';\nimport {\n getAllProviders,\n getApiKeyFromEnv,\n getModelRegistry,\n getModelsByProvider,\n getProviderDisplayName,\n providerSupportsApiKey,\n providerSupportsOAuth,\n} from '../../../providers/index.js';\nimport {\n getProviderHint,\n getRecommendedModelsForProvider,\n sortModelsForPicker,\n sortProvidersForPicker,\n} from '../../../providers/presentation.js';\nimport { listProfilesForProvider } from '../../../auth/profiles/index.js';\nimport { getOAuthProvider } from '../../utils/oauth-providers.js';\nimport { runCliOAuthLogin } from '../../utils/oauth-login.js';\nimport type { CLIContext } from '../../registry.js';\nimport { colors } from '../../utils/colors.js';\n\ntype ModelChoice = { value: string; name: string; description?: string };\ntype CustomApiKind = 'openai-completions' | 'openai-responses' | 'anthropic-messages';\n\nfunction setPrimaryModel(config: Config, workspacePath: string, modelRef: string): Config {\n const id = config.agents.default ?? config.agents.list[0]?.id ?? 'main';\n const index = config.agents.list.findIndex((entry) => entry.id === id);\n let nextConfig = config;\n if (index >= 0) {\n const agent = config.agents.list[index]!;\n const nextList = [...config.agents.list];\n nextList[index] = {\n ...agent,\n workspace: { root: workspacePath },\n };\n nextConfig = { ...config, agents: { ...config.agents, list: nextList } };\n }\n const prep = prepareUpdateGlobalDefaults(nextConfig, {\n models: {\n defaultRole: 'deep',\n roles: { deep: { model: modelRef } },\n },\n });\n if (prep.ok === false) {\n throw new Error(prep.error);\n }\n return prep.data.nextConfig;\n}\n\nfunction formatRecommended(provider: string): string | undefined {\n const labels = getRecommendedModelsForProvider(provider, 3).map((m) => m.name || m.id);\n return labels.length > 0 ? `Recommended: ${labels.join(', ')}` : getProviderHint(provider);\n}\n\nfunction providerChoices(): Array<{ value: string; name: string; description?: string }> {\n const providers = sortProvidersForPicker(getAllProviders());\n const choices = providers.map((provider) => ({\n value: provider,\n name: getProviderDisplayName(provider),\n description: formatRecommended(provider),\n }));\n choices.push({\n value: 'custom-api',\n name: 'Custom API',\n description: 'OpenAI-compatible, OpenAI Responses, or Anthropic-compatible endpoint',\n });\n return choices;\n}\n\nfunction modelChoiceName(choice: ModelChoice): string {\n return choice.description ? `${choice.name} ${colors.gray(choice.description)}` : choice.name;\n}\n\nfunction getModelsForProvider(provider: string): ModelChoice[] {\n return sortModelsForPicker(getModelsByProvider(provider)).map((m) => {\n const badges = [m.reasoning ? 'reasoning' : '', m.input?.includes('image') ? 'vision' : '']\n .filter(Boolean)\n .join(', ');\n return {\n value: `${m.provider}/${m.id}`,\n name: m.name || m.id,\n description: badges || undefined,\n };\n });\n}\n\nasync function doOAuthLogin(provider: string): Promise<boolean> {\n const config = getOAuthProvider(provider);\n if (!config) {\n console.error(`OAuth not supported for provider: ${provider}`);\n return false;\n }\n\n console.log(`\\n🔐 Starting ${config.displayName} OAuth login...`);\n try {\n await runCliOAuthLogin({ provider, onProgress: (message) => console.log(' →', message) });\n return true;\n } catch (error) {\n console.error('❌ OAuth login failed:', error);\n return false;\n }\n}\n\nfunction joinEndpoint(baseUrl: string, suffix: string): string {\n return `${baseUrl.replace(/\\/+$/, '')}/${suffix.replace(/^\\/+/, '')}`;\n}\n\nasync function probeCustomProvider(params: {\n baseUrl: string;\n apiKey: string;\n modelId: string;\n api: CustomApiKind;\n}): Promise<void> {\n const timeout = AbortSignal.timeout(30_000);\n const commonHeaders = {\n 'content-type': 'application/json',\n authorization: `Bearer ${params.apiKey}`,\n };\n\n const request =\n params.api === 'anthropic-messages'\n ? {\n url: joinEndpoint(params.baseUrl, '/messages'),\n headers: { ...commonHeaders, 'anthropic-version': '2023-06-01' },\n body: { model: params.modelId, max_tokens: 1, messages: [{ role: 'user', content: 'ping' }] },\n }\n : params.api === 'openai-responses'\n ? {\n url: joinEndpoint(params.baseUrl, '/responses'),\n headers: commonHeaders,\n body: { model: params.modelId, input: 'ping', max_output_tokens: 1 },\n }\n : {\n url: joinEndpoint(params.baseUrl, '/chat/completions'),\n headers: commonHeaders,\n body: { model: params.modelId, messages: [{ role: 'user', content: 'ping' }], max_tokens: 1 },\n };\n\n const res = await fetch(request.url, {\n method: 'POST',\n headers: request.headers,\n body: JSON.stringify(request.body),\n signal: timeout,\n });\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(`Probe failed (${res.status}) at ${request.url}${text ? `: ${text.slice(0, 300)}` : ''}`);\n }\n}\n\nfunction defaultProviderIdFromBaseUrl(baseUrl: string): string {\n try {\n const url = new URL(baseUrl);\n return url.hostname\n .replace(/^api\\./, '')\n .split('.')\n .filter(Boolean)\n .slice(0, 2)\n .join('-')\n .toLowerCase()\n .replace(/[^a-z0-9-_]+/g, '-')\n .replace(/^-+|-+$/g, '') || 'custom';\n } catch {\n return 'custom';\n }\n}\n\nfunction validateProviderId(value: string): true | string {\n return /^[a-z0-9]([a-z0-9-_]*[a-z0-9])?$/.test(value)\n ? true\n : 'Use lowercase letters, numbers, hyphens, or underscores; start/end with a letter or number.';\n}\n\nasync function setupCustomApi(config: Config, ctx: CLIContext): Promise<Config> {\n console.log('\\n🔌 Custom API provider\\n');\n\n const baseUrl = (await input({\n message: 'API base URL:',\n default: 'https://api.example.com/v1',\n validate: (value) => URL.canParse(value) || 'Enter a valid URL',\n })).trim();\n\n const apiKey = (await input({\n message: 'API key:',\n validate: (value) => value.trim().length > 0 || 'Required',\n })).trim();\n\n const api = await select<CustomApiKind>({\n message: 'Compatibility:',\n choices: [\n { value: 'openai-completions', name: 'OpenAI-compatible Chat Completions' },\n { value: 'openai-responses', name: 'OpenAI Responses' },\n { value: 'anthropic-messages', name: 'Anthropic Messages' },\n ],\n });\n\n const modelId = (await input({\n message: 'Model ID:',\n validate: (value) => value.trim().length > 0 || 'Required',\n })).trim();\n\n console.log('\\n→ Probing endpoint...');\n await probeCustomProvider({ baseUrl, apiKey, modelId, api });\n console.log(colors.green('✓ Probe succeeded'));\n\n const existingProviders = new Set(getAllProviders());\n const providerId = (await input({\n message: 'Provider ID:',\n default: defaultProviderIdFromBaseUrl(baseUrl),\n validate: (value) => {\n const valid = validateProviderId(value.trim());\n if (valid !== true) return valid;\n if (existingProviders.has(value.trim())) return 'Provider ID already exists; choose a new ID.';\n return true;\n },\n })).trim();\n\n const path = getModelsJsonPath();\n const { config: modelsConfig } = loadModelsJson(path);\n const nextModelsConfig: ModelsJsonConfig = {\n providers: {\n ...(modelsConfig.providers ?? {}),\n [providerId]: {\n baseUrl,\n apiKey,\n api,\n models: [{ id: modelId, name: modelId, api, contextWindow: 128000, input: ['text'] }],\n },\n },\n };\n const saved = saveModelsJson(path, nextModelsConfig);\n if (!saved.success) {\n throw new Error(saved.error || 'Failed to save models.json');\n }\n getModelRegistry().refresh();\n\n const ref = `${providerId}/${modelId}`;\n console.log('\\n✅ Custom model configured:', ref);\n return setPrimaryModel(config, ctx.workspacePath, ref);\n}\n\nasync function ensureProviderCredential(provider: string, providerName: string): Promise<boolean> {\n const existingProfiles = listProfilesForProvider(provider);\n if (existingProfiles.length > 0) {\n console.log(`\\n${colors.green('✓')} Found existing credentials for ${providerName}`);\n return await confirm({ message: 'Use existing credentials?', default: true });\n }\n\n const envKey = getApiKeyFromEnv(provider);\n if (envKey) {\n console.log(`\\n${colors.green('✓')} Found API key for ${providerName} in environment`);\n return true;\n }\n\n const supportsOAuth = providerSupportsOAuth(provider);\n const supportsApiKey = providerSupportsApiKey(provider);\n\n if (supportsOAuth && !supportsApiKey) {\n return await doOAuthLogin(provider);\n }\n\n let useOAuth = false;\n if (supportsOAuth && supportsApiKey) {\n const authMethod = await select<'api_key' | 'oauth'>({\n message: `How would you like to authenticate with ${providerName}?`,\n choices: [\n { value: 'api_key', name: 'API key' },\n { value: 'oauth', name: 'OAuth login' },\n ],\n });\n useOAuth = authMethod === 'oauth';\n }\n\n if (useOAuth) {\n const ok = await doOAuthLogin(provider);\n if (ok) return true;\n console.log('\\n⚠️ OAuth login failed. Enter an API key instead.');\n }\n\n if (!supportsApiKey) return false;\n const apiKey = await input({\n message: `API key for ${providerName}:`,\n validate: (value) => value.trim().length > 0 || 'Required',\n });\n const resolver = new CredentialResolver();\n await resolver.saveApiKey(provider, apiKey.trim(), { profileName: 'default' });\n return true;\n}\n\nexport async function setupModel(existingConfig: Config | null, ctx: CLIContext): Promise<Config> {\n console.log('\\n🤖 Step: AI Model\\n');\n\n const config = existingConfig || ({} as Config);\n const currentModel = getAgentDefaultModelRef(config);\n\n if (currentModel) {\n console.log('Current model:', currentModel);\n const keepCurrent = await confirm({ message: 'Keep using this model?', default: true });\n if (keepCurrent) {\n console.log('✅ Keeping:', currentModel);\n return config;\n }\n }\n\n const provider = await select({\n message: 'Model/auth provider:',\n choices: providerChoices(),\n });\n\n if (provider === 'custom-api') {\n return await setupCustomApi(config, ctx);\n }\n\n const providerName = getProviderDisplayName(provider);\n const credentialOk = await ensureProviderCredential(provider, providerName);\n if (!credentialOk) {\n console.error(`\\n❌ Could not configure credentials for ${providerName}.`);\n return config;\n }\n\n const modelChoices = getModelsForProvider(provider);\n if (modelChoices.length === 0) {\n throw new Error(`No catalog models found for ${providerName}. Add a Custom API provider instead.`);\n }\n\n console.log(`\\n📋 Models for ${providerName}:`);\n const model = await select({\n message: 'Model:',\n choices: modelChoices.map((choice) => ({ ...choice, name: modelChoiceName(choice) })),\n });\n\n console.log('\\n✅ Model configured:', model);\n return setPrimaryModel(config, ctx.workspacePath, model);\n}\n"],"mappings":"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"}
|
|
@@ -138,7 +138,7 @@ async function promptLaunchAfterOnboard(config, ctx, _flags) {
|
|
|
138
138
|
{
|
|
139
139
|
value: "tui",
|
|
140
140
|
name: "Terminal UI (embedded)",
|
|
141
|
-
description: "xopc
|
|
141
|
+
description: "xopc — no gateway process required"
|
|
142
142
|
},
|
|
143
143
|
{
|
|
144
144
|
value: "gateway",
|
|
@@ -165,7 +165,7 @@ async function promptLaunchAfterOnboard(config, ctx, _flags) {
|
|
|
165
165
|
console.log("\n⏭️ You can start later:");
|
|
166
166
|
console.log(" xopc gateway service install");
|
|
167
167
|
console.log(" xopc gateway");
|
|
168
|
-
console.log(" xopc
|
|
168
|
+
console.log(" xopc");
|
|
169
169
|
}
|
|
170
170
|
async function setupGateway(config) {
|
|
171
171
|
console.log(colors.cyan("\n🌐 Gateway WebUI\n"));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"onboard.js","names":["runModelSetup","runChannelOnboard"],"sources":["../../../../src/cli/commands/onboard.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { select } from '@inquirer/prompts';\nimport { saveConfig } from '../../config/index.js';\nimport { register, formatExamples } from '../registry.js';\nimport type { CLIContext } from '../registry.js';\nimport type { Config } from '../../config/schema.js';\nimport { setupModel as runModelSetup } from './onboard/model.js';\nimport { colors } from '../utils/colors.js';\nimport { setupChannels as runChannelOnboard, getChannelConfigurators } from './onboard/channels/index.js';\nimport { resolveGatewayLocalClientHost } from '../../config/gateway-bind.js';\nimport { initWorkspace } from '../utils/init-workspace.js';\nimport { ConfigSchema } from '../../config/schema.js';\n\nfunction isInteractive(): boolean {\n return process.stdin.isTTY && process.stdout.isTTY;\n}\n\nfunction printGitHubStarHint(): void {\n console.log('\\n⭐ If xopc helps you keep long-term AI work moving, please star the repo:');\n console.log(' https://github.com/xopcai/xopc');\n}\n\nasync function setupNonInteractive(_configPath: string, existingConfig: Config): Promise<Config> {\n console.log('\\n🤖 AI Model Configuration (Non-Interactive Mode)\\n');\n console.log('Current agent manifests:', JSON.stringify(existingConfig.agents?.list ?? [], null, 2));\n console.log('\\n💡 To configure in interactive mode, run: xopc onboard');\n console.log('💡 Or set up manually in:', _configPath);\n return existingConfig;\n}\n\nfunction createOnboardCommand(ctx: CLIContext): Command {\n const cmd = new Command('onboard')\n .description('Interactive setup wizard for xopc (gateway uses schema defaults)')\n .addHelpText(\n 'after',\n formatExamples([\n 'xopc onboard # Full interactive setup',\n 'xopc onboard --quick # Configure model only, then launch locally',\n 'xopc onboard --model # Configure LLM model only',\n 'xopc onboard --channels # Configure messaging channels',\n 'xopc onboard --gateway # Apply default gateway settings (quiet)',\n ])\n )\n .option('--quick', 'Configure model only, then launch locally')\n .option('--model', 'Configure LLM provider and model')\n .option('--channels', 'Configure messaging channels')\n .option('--gateway', 'Configure gateway WebUI')\n .option('--all', 'Configure everything (default)')\n .action(async (options) => {\n try {\n await runOnboard(options, ctx);\n } catch (error: unknown) {\n const err = error as { name?: string; code?: string };\n if (err?.name === 'ExitPromptError' || err?.code === 'EXIT_PROMPT') {\n console.log('\\n\\n👋 Setup cancelled.');\n process.exit(0);\n }\n throw error;\n }\n });\n\n return cmd;\n}\n\ntype OnboardOptions = {\n quick?: boolean;\n model?: boolean;\n channels?: boolean;\n gateway?: boolean;\n all?: boolean;\n};\n\nasync function runOnboard(\n options: OnboardOptions,\n ctx: CLIContext\n): Promise<void> {\n console.log(colors.cyan('\\n🚀 Welcome to xopc setup!\\n'));\n console.log('═'.repeat(50));\n\n const workspacePath = ctx.workspacePath;\n const configPath = ctx.configPath;\n\n const initResult = await initWorkspace({ configPath, workspacePath });\n let config = initResult.config;\n\n // Determine what to configure based on options\n const doModel = options.quick || options.model || options.all || (!options.channels && !options.gateway);\n const doChannels = !options.quick && (options.channels || options.all || (!options.model && !options.gateway));\n const doGateway = !options.quick && (options.gateway || options.all || (!options.model && !options.channels));\n const runFullWizard = !options.quick && !options.model && !options.channels && !options.gateway;\n /** Any setup step besides the unified launch prompt ran in interactive flow. */\n const didConfigurableSteps = doModel || doChannels || doGateway;\n\n if (!isInteractive()) {\n // Non-interactive mode\n if (doModel) {\n config = await setupNonInteractive(configPath, config);\n }\n if (doChannels) {\n console.log('\\n💬 Channels Configuration (Non-Interactive Mode)\\n');\n console.log('💡 To configure channels, edit the config file manually.');\n }\n if (doGateway) {\n console.log('\\n🌐 Gateway Configuration (Non-Interactive Mode)\\n');\n console.log('💡 To configure gateway, edit the config file manually.');\n }\n } else {\n // Interactive mode\n if (doModel) {\n config = await runModelSetup(config, ctx);\n }\n\n if (doChannels) {\n const channelIds = (await getChannelConfigurators(config)).map(c => c.id);\n console.log(colors.gray(`\\nChannel onboarding: ${channelIds.join(', ')}\\n`));\n config = await runChannelOnboard(config);\n }\n\n if (doGateway) {\n config = await setupGateway(config);\n }\n }\n\n // Save config once at the end\n await saveConfig(config as Config, configPath);\n\n console.log('\\n' + '═'.repeat(50));\n console.log('\\n🎉 Setup Complete!\\n');\n\n const gatewayAuth = (config as any)?.gateway?.auth;\n const gatewayConfigured =\n gatewayAuth?.mode === 'token' &&\n typeof gatewayAuth?.token === 'string' &&\n gatewayAuth.token.length > 0;\n const port = (config as Config)?.gateway?.port ?? 18790;\n const displayHost = resolveGatewayLocalClientHost(config as Config);\n const gwToken = gatewayConfigured ? (gatewayAuth.token as string) : undefined;\n\n const showGatewaySummary = Boolean(gatewayConfigured && gwToken && (doGateway || runFullWizard));\n\n if (showGatewaySummary && gwToken) {\n const webuiUrl = `http://${displayHost}:${port}?token=${gwToken}`;\n console.log('🌐 Web console (browser) — start here');\n console.log(` Open: http://${displayHost}:${port}`);\n console.log(` Token: ${gwToken.slice(0, 8)}...${gwToken.slice(-8)}`);\n console.log(' Bookmark link (token is saved in the browser when you open it):');\n console.log(` ${webuiUrl}`);\n console.log('');\n }\n\n if (runFullWizard) {\n console.log('🚀 Next steps:');\n if (gatewayConfigured) {\n console.log(' 1. Choose how to launch below (gateway or terminal UI)');\n console.log(' 2. Or chat with: xopc agent -i');\n } else {\n console.log(' 1. Chat in the terminal: xopc agent -i');\n console.log(' 2. Optional: add the Web console: xopc onboard --gateway');\n }\n console.log('');\n } else if (doGateway && gatewayConfigured) {\n console.log('🚀 Next step:');\n console.log(' Start the gateway if it is not running, then open the Web console URL above.');\n console.log('');\n }\n\n console.log('📝 Usage:');\n console.log(' xopc agent -m \"Hello\" # Chat with AI');\n console.log(' xopc agent -i # Interactive mode');\n console.log(' xopc models list # List models');\n console.log(' xopc config validate # Validate xopc.json');\n console.log(' xopc auth list # View authentication');\n console.log(' xopc init # Full state dirs (if upgrading or missing data)');\n\n console.log('\\n📁 Files:');\n console.log(' Config:', configPath);\n console.log(' Workspace:', workspacePath);\n\n printGitHubStarHint();\n\n if (isInteractive() && didConfigurableSteps) {\n await promptLaunchAfterOnboard(config as Config, ctx, { doChannels });\n }\n\n process.exit(0);\n}\n\nasync function startGatewayAsService(config: Config, ctx: CLIContext): Promise<void> {\n const { startGatewayNow } = await import('./onboard/gateway.js');\n await startGatewayNow(config, ctx);\n}\n\nasync function promptLaunchAfterOnboard(\n config: Config,\n ctx: CLIContext,\n _flags: { doChannels: boolean },\n): Promise<void> {\n console.log('');\n const choice = await select<'tui' | 'gateway' | 'none'>({\n message: 'How do you want to launch xopc now?',\n choices: [\n {\n value: 'tui',\n name: 'Terminal UI (embedded)',\n description: 'xopc tui --local — no gateway process required',\n },\n {\n value: 'gateway',\n name: 'Gateway WebUI (OS service)',\n description: 'Install and start the HTTP gateway for the browser console',\n },\n {\n value: 'none',\n name: 'Exit — I will start manually',\n description: 'Finish setup without starting a runtime',\n },\n ],\n default: 'tui',\n });\n\n if (choice === 'gateway') {\n await startGatewayAsService(config, ctx);\n return;\n }\n\n if (choice === 'tui') {\n const { runTui } = await import('../../tui/tui.js');\n await runTui({ local: true });\n return;\n }\n\n console.log('\\n⏭️ You can start later:');\n console.log(' xopc gateway service install');\n console.log(' xopc gateway');\n console.log(' xopc tui --local');\n}\n\nasync function setupGateway(config: Config): Promise<Config> {\n console.log(colors.cyan('\\n🌐 Gateway WebUI\\n'));\n console.log(\n colors.gray(\n 'Applying defaults from config schema (127.0.0.1:18790, token auth; token generated if missing).\\n',\n ),\n );\n\n const gw = config.gateway ?? {};\n const { randomBytes } = await import('node:crypto');\n const authMode = gw.auth?.mode === 'none' ? ('none' as const) : ('token' as const);\n const token =\n authMode === 'token'\n ? typeof gw.auth?.token === 'string' && gw.auth.token.length > 0\n ? gw.auth.token\n : randomBytes(24).toString('hex')\n : undefined;\n\n const merged: Config = {\n ...config,\n gateway: {\n ...gw,\n bind: gw.bind ?? 'loopback',\n port: gw.port ?? 18790,\n auth:\n authMode === 'none'\n ? { mode: 'none' as const }\n : { mode: 'token' as const, token: token! },\n },\n };\n\n const parsed = ConfigSchema.parse(merged);\n console.log('✅ Gateway defaults applied.\\n');\n return parsed;\n}\n\nregister({\n id: 'onboard',\n name: 'onboard',\n description: 'Interactive setup wizard',\n factory: createOnboardCommand,\n metadata: {\n category: 'setup',\n examples: ['xopc onboard', 'xopc onboard --model', 'xopc onboard --channels'],\n },\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"onboard.js","names":["runModelSetup","runChannelOnboard"],"sources":["../../../../src/cli/commands/onboard.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { select } from '@inquirer/prompts';\nimport { saveConfig } from '../../config/index.js';\nimport { register, formatExamples } from '../registry.js';\nimport type { CLIContext } from '../registry.js';\nimport type { Config } from '../../config/schema.js';\nimport { setupModel as runModelSetup } from './onboard/model.js';\nimport { colors } from '../utils/colors.js';\nimport { setupChannels as runChannelOnboard, getChannelConfigurators } from './onboard/channels/index.js';\nimport { resolveGatewayLocalClientHost } from '../../config/gateway-bind.js';\nimport { initWorkspace } from '../utils/init-workspace.js';\nimport { ConfigSchema } from '../../config/schema.js';\n\nfunction isInteractive(): boolean {\n return process.stdin.isTTY && process.stdout.isTTY;\n}\n\nfunction printGitHubStarHint(): void {\n console.log('\\n⭐ If xopc helps you keep long-term AI work moving, please star the repo:');\n console.log(' https://github.com/xopcai/xopc');\n}\n\nasync function setupNonInteractive(_configPath: string, existingConfig: Config): Promise<Config> {\n console.log('\\n🤖 AI Model Configuration (Non-Interactive Mode)\\n');\n console.log('Current agent manifests:', JSON.stringify(existingConfig.agents?.list ?? [], null, 2));\n console.log('\\n💡 To configure in interactive mode, run: xopc onboard');\n console.log('💡 Or set up manually in:', _configPath);\n return existingConfig;\n}\n\nfunction createOnboardCommand(ctx: CLIContext): Command {\n const cmd = new Command('onboard')\n .description('Interactive setup wizard for xopc (gateway uses schema defaults)')\n .addHelpText(\n 'after',\n formatExamples([\n 'xopc onboard # Full interactive setup',\n 'xopc onboard --quick # Configure model only, then launch locally',\n 'xopc onboard --model # Configure LLM model only',\n 'xopc onboard --channels # Configure messaging channels',\n 'xopc onboard --gateway # Apply default gateway settings (quiet)',\n ])\n )\n .option('--quick', 'Configure model only, then launch locally')\n .option('--model', 'Configure LLM provider and model')\n .option('--channels', 'Configure messaging channels')\n .option('--gateway', 'Configure gateway WebUI')\n .option('--all', 'Configure everything (default)')\n .action(async (options) => {\n try {\n await runOnboard(options, ctx);\n } catch (error: unknown) {\n const err = error as { name?: string; code?: string };\n if (err?.name === 'ExitPromptError' || err?.code === 'EXIT_PROMPT') {\n console.log('\\n\\n👋 Setup cancelled.');\n process.exit(0);\n }\n throw error;\n }\n });\n\n return cmd;\n}\n\ntype OnboardOptions = {\n quick?: boolean;\n model?: boolean;\n channels?: boolean;\n gateway?: boolean;\n all?: boolean;\n};\n\nasync function runOnboard(\n options: OnboardOptions,\n ctx: CLIContext\n): Promise<void> {\n console.log(colors.cyan('\\n🚀 Welcome to xopc setup!\\n'));\n console.log('═'.repeat(50));\n\n const workspacePath = ctx.workspacePath;\n const configPath = ctx.configPath;\n\n const initResult = await initWorkspace({ configPath, workspacePath });\n let config = initResult.config;\n\n // Determine what to configure based on options\n const doModel = options.quick || options.model || options.all || (!options.channels && !options.gateway);\n const doChannels = !options.quick && (options.channels || options.all || (!options.model && !options.gateway));\n const doGateway = !options.quick && (options.gateway || options.all || (!options.model && !options.channels));\n const runFullWizard = !options.quick && !options.model && !options.channels && !options.gateway;\n /** Any setup step besides the unified launch prompt ran in interactive flow. */\n const didConfigurableSteps = doModel || doChannels || doGateway;\n\n if (!isInteractive()) {\n // Non-interactive mode\n if (doModel) {\n config = await setupNonInteractive(configPath, config);\n }\n if (doChannels) {\n console.log('\\n💬 Channels Configuration (Non-Interactive Mode)\\n');\n console.log('💡 To configure channels, edit the config file manually.');\n }\n if (doGateway) {\n console.log('\\n🌐 Gateway Configuration (Non-Interactive Mode)\\n');\n console.log('💡 To configure gateway, edit the config file manually.');\n }\n } else {\n // Interactive mode\n if (doModel) {\n config = await runModelSetup(config, ctx);\n }\n\n if (doChannels) {\n const channelIds = (await getChannelConfigurators(config)).map(c => c.id);\n console.log(colors.gray(`\\nChannel onboarding: ${channelIds.join(', ')}\\n`));\n config = await runChannelOnboard(config);\n }\n\n if (doGateway) {\n config = await setupGateway(config);\n }\n }\n\n // Save config once at the end\n await saveConfig(config as Config, configPath);\n\n console.log('\\n' + '═'.repeat(50));\n console.log('\\n🎉 Setup Complete!\\n');\n\n const gatewayAuth = (config as any)?.gateway?.auth;\n const gatewayConfigured =\n gatewayAuth?.mode === 'token' &&\n typeof gatewayAuth?.token === 'string' &&\n gatewayAuth.token.length > 0;\n const port = (config as Config)?.gateway?.port ?? 18790;\n const displayHost = resolveGatewayLocalClientHost(config as Config);\n const gwToken = gatewayConfigured ? (gatewayAuth.token as string) : undefined;\n\n const showGatewaySummary = Boolean(gatewayConfigured && gwToken && (doGateway || runFullWizard));\n\n if (showGatewaySummary && gwToken) {\n const webuiUrl = `http://${displayHost}:${port}?token=${gwToken}`;\n console.log('🌐 Web console (browser) — start here');\n console.log(` Open: http://${displayHost}:${port}`);\n console.log(` Token: ${gwToken.slice(0, 8)}...${gwToken.slice(-8)}`);\n console.log(' Bookmark link (token is saved in the browser when you open it):');\n console.log(` ${webuiUrl}`);\n console.log('');\n }\n\n if (runFullWizard) {\n console.log('🚀 Next steps:');\n if (gatewayConfigured) {\n console.log(' 1. Choose how to launch below (gateway or terminal UI)');\n console.log(' 2. Or chat with: xopc agent -i');\n } else {\n console.log(' 1. Chat in the terminal: xopc agent -i');\n console.log(' 2. Optional: add the Web console: xopc onboard --gateway');\n }\n console.log('');\n } else if (doGateway && gatewayConfigured) {\n console.log('🚀 Next step:');\n console.log(' Start the gateway if it is not running, then open the Web console URL above.');\n console.log('');\n }\n\n console.log('📝 Usage:');\n console.log(' xopc agent -m \"Hello\" # Chat with AI');\n console.log(' xopc agent -i # Interactive mode');\n console.log(' xopc models list # List models');\n console.log(' xopc config validate # Validate xopc.json');\n console.log(' xopc auth list # View authentication');\n console.log(' xopc init # Full state dirs (if upgrading or missing data)');\n\n console.log('\\n📁 Files:');\n console.log(' Config:', configPath);\n console.log(' Workspace:', workspacePath);\n\n printGitHubStarHint();\n\n if (isInteractive() && didConfigurableSteps) {\n await promptLaunchAfterOnboard(config as Config, ctx, { doChannels });\n }\n\n process.exit(0);\n}\n\nasync function startGatewayAsService(config: Config, ctx: CLIContext): Promise<void> {\n const { startGatewayNow } = await import('./onboard/gateway.js');\n await startGatewayNow(config, ctx);\n}\n\nasync function promptLaunchAfterOnboard(\n config: Config,\n ctx: CLIContext,\n _flags: { doChannels: boolean },\n): Promise<void> {\n console.log('');\n const choice = await select<'tui' | 'gateway' | 'none'>({\n message: 'How do you want to launch xopc now?',\n choices: [\n {\n value: 'tui',\n name: 'Terminal UI (embedded)',\n description: 'xopc — no gateway process required',\n },\n {\n value: 'gateway',\n name: 'Gateway WebUI (OS service)',\n description: 'Install and start the HTTP gateway for the browser console',\n },\n {\n value: 'none',\n name: 'Exit — I will start manually',\n description: 'Finish setup without starting a runtime',\n },\n ],\n default: 'tui',\n });\n\n if (choice === 'gateway') {\n await startGatewayAsService(config, ctx);\n return;\n }\n\n if (choice === 'tui') {\n const { runTui } = await import('../../tui/tui.js');\n await runTui({ local: true });\n return;\n }\n\n console.log('\\n⏭️ You can start later:');\n console.log(' xopc gateway service install');\n console.log(' xopc gateway');\n console.log(' xopc');\n}\n\nasync function setupGateway(config: Config): Promise<Config> {\n console.log(colors.cyan('\\n🌐 Gateway WebUI\\n'));\n console.log(\n colors.gray(\n 'Applying defaults from config schema (127.0.0.1:18790, token auth; token generated if missing).\\n',\n ),\n );\n\n const gw = config.gateway ?? {};\n const { randomBytes } = await import('node:crypto');\n const authMode = gw.auth?.mode === 'none' ? ('none' as const) : ('token' as const);\n const token =\n authMode === 'token'\n ? typeof gw.auth?.token === 'string' && gw.auth.token.length > 0\n ? gw.auth.token\n : randomBytes(24).toString('hex')\n : undefined;\n\n const merged: Config = {\n ...config,\n gateway: {\n ...gw,\n bind: gw.bind ?? 'loopback',\n port: gw.port ?? 18790,\n auth:\n authMode === 'none'\n ? { mode: 'none' as const }\n : { mode: 'token' as const, token: token! },\n },\n };\n\n const parsed = ConfigSchema.parse(merged);\n console.log('✅ Gateway defaults applied.\\n');\n return parsed;\n}\n\nregister({\n id: 'onboard',\n name: 'onboard',\n description: 'Interactive setup wizard',\n factory: createOnboardCommand,\n metadata: {\n category: 'setup',\n examples: ['xopc onboard', 'xopc onboard --model', 'xopc onboard --channels'],\n },\n});\n"],"mappings":"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"}
|
|
@@ -3,9 +3,9 @@ import { Command } from "commander";
|
|
|
3
3
|
//#region src/cli/commands/tui.ts
|
|
4
4
|
function createTuiCommand(_ctx) {
|
|
5
5
|
return new Command("tui").description("Interactive terminal UI (pi-tui)").addHelpText("after", formatExamples([
|
|
6
|
+
"xopc # Open embedded TUI (default command)",
|
|
6
7
|
"xopc tui # Embedded mode (default)",
|
|
7
8
|
"xopc tui --gateway # Force gateway mode",
|
|
8
|
-
"xopc tui --local # Embedded mode (default)",
|
|
9
9
|
"xopc tui --url http://host:3120 --token xxx # Connect to remote gateway",
|
|
10
10
|
"xopc tui -s agent:main:tui-... # Resume a session",
|
|
11
11
|
"xopc tui -m \"Summarize my inbox\" # Send a message on launch"
|
|
@@ -36,8 +36,8 @@ register({
|
|
|
36
36
|
metadata: {
|
|
37
37
|
category: "runtime",
|
|
38
38
|
examples: [
|
|
39
|
+
"xopc",
|
|
39
40
|
"xopc tui",
|
|
40
|
-
"xopc tui --local",
|
|
41
41
|
"xopc tui --gateway",
|
|
42
42
|
"xopc tui --url http://host:3120"
|
|
43
43
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui.js","names":[],"sources":["../../../../src/cli/commands/tui.ts"],"sourcesContent":["import { Command } from 'commander';\n\nimport { register, formatExamples, type CLIContext } from '../registry.js';\n\nfunction createTuiCommand(_ctx: CLIContext): Command {\n const cmd = new Command('tui')\n .description('Interactive terminal UI (pi-tui)')\n .addHelpText(\n 'after',\n formatExamples([\n 'xopc
|
|
1
|
+
{"version":3,"file":"tui.js","names":[],"sources":["../../../../src/cli/commands/tui.ts"],"sourcesContent":["import { Command } from 'commander';\n\nimport { register, formatExamples, type CLIContext } from '../registry.js';\n\nfunction createTuiCommand(_ctx: CLIContext): Command {\n const cmd = new Command('tui')\n .description('Interactive terminal UI (pi-tui)')\n .addHelpText(\n 'after',\n formatExamples([\n 'xopc # Open embedded TUI (default command)',\n 'xopc tui # Embedded mode (default)',\n 'xopc tui --gateway # Force gateway mode',\n 'xopc tui --url http://host:3120 --token xxx # Connect to remote gateway',\n 'xopc tui -s agent:main:tui-... # Resume a session',\n 'xopc tui -m \"Summarize my inbox\" # Send a message on launch',\n ]),\n )\n .option('--url <url>', 'Gateway URL (default: http://localhost:3120)')\n .option('--token <token>', 'Gateway bearer token')\n .option('-s, --session <key>', 'Session key to resume (omitted: start a fresh TUI session)')\n .option('-m, --message <text>', 'Send a message on launch')\n .option('--workdir <dir>', 'Workspace directory for the new TUI session')\n .option('--no-cwd', 'Do not use the launch directory as the new TUI session workspace')\n .option('--local', 'Run in embedded mode (no gateway required)')\n .option('--gateway', 'Force gateway mode even without explicit --url or --token')\n .option('--theme <name>', 'Theme: auto, dark, light, or custom name from ~/.xopc/themes/')\n .option('--thinking <level>', 'Thinking level override')\n .action(async (options: Record<string, string | boolean | undefined>) => {\n const { runTui } = await import('../../tui/tui.js');\n const useLocal = options.local === true;\n const useGateway =\n options.gateway === true ||\n typeof options.url === 'string' ||\n typeof options.token === 'string';\n if (useLocal && useGateway) {\n console.log('`--local` and gateway flags both set. Using local mode.');\n }\n const localMode = useLocal || !useGateway;\n await runTui({\n url: typeof options.url === 'string' ? options.url : undefined,\n token: typeof options.token === 'string' ? options.token : undefined,\n session: typeof options.session === 'string' ? options.session : undefined,\n message: typeof options.message === 'string' ? options.message : undefined,\n workdir: typeof options.workdir === 'string' ? options.workdir : undefined,\n useStartupCwd: options.cwd !== false,\n local: localMode,\n thinking: typeof options.thinking === 'string' ? options.thinking : undefined,\n theme: typeof options.theme === 'string' ? options.theme : undefined,\n });\n });\n\n return cmd;\n}\n\nregister({\n id: 'tui',\n name: 'tui',\n description: 'Interactive terminal UI (pi-tui)',\n factory: createTuiCommand,\n metadata: {\n category: 'runtime',\n examples: [\n 'xopc',\n 'xopc tui',\n 'xopc tui --gateway',\n 'xopc tui --url http://host:3120',\n ],\n },\n});\n"],"mappings":";;;AAIA,SAAS,iBAAiB,MAA2B;AAgDnD,QA/CY,IAAI,QAAQ,MAAM,CAC3B,YAAY,mCAAmC,CAC/C,YACC,SACA,eAAe;EACb;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,CACH,CACA,OAAO,eAAe,+CAA+C,CACrE,OAAO,mBAAmB,uBAAuB,CACjD,OAAO,uBAAuB,6DAA6D,CAC3F,OAAO,wBAAwB,2BAA2B,CAC1D,OAAO,mBAAmB,8CAA8C,CACxE,OAAO,YAAY,mEAAmE,CACtF,OAAO,WAAW,6CAA6C,CAC/D,OAAO,aAAa,4DAA4D,CAChF,OAAO,kBAAkB,gEAAgE,CACzF,OAAO,sBAAsB,0BAA0B,CACvD,OAAO,OAAO,YAA0D;EACvE,MAAM,EAAE,WAAW,MAAM,OAAO;EAChC,MAAM,WAAW,QAAQ,UAAU;EACnC,MAAM,aACJ,QAAQ,YAAY,QACpB,OAAO,QAAQ,QAAQ,YACvB,OAAO,QAAQ,UAAU;AAC3B,MAAI,YAAY,WACd,SAAQ,IAAI,0DAA0D;EAExE,MAAM,YAAY,YAAY,CAAC;AAC/B,QAAM,OAAO;GACX,KAAK,OAAO,QAAQ,QAAQ,WAAW,QAAQ,MAAM,KAAA;GACrD,OAAO,OAAO,QAAQ,UAAU,WAAW,QAAQ,QAAQ,KAAA;GAC3D,SAAS,OAAO,QAAQ,YAAY,WAAW,QAAQ,UAAU,KAAA;GACjE,SAAS,OAAO,QAAQ,YAAY,WAAW,QAAQ,UAAU,KAAA;GACjE,SAAS,OAAO,QAAQ,YAAY,WAAW,QAAQ,UAAU,KAAA;GACjE,eAAe,QAAQ,QAAQ;GAC/B,OAAO;GACP,UAAU,OAAO,QAAQ,aAAa,WAAW,QAAQ,WAAW,KAAA;GACpE,OAAO,OAAO,QAAQ,UAAU,WAAW,QAAQ,QAAQ,KAAA;GAC5D,CAAC;GAGI;;AAGZ,SAAS;CACP,IAAI;CACJ,MAAM;CACN,aAAa;CACb,SAAS;CACT,UAAU;EACR,UAAU;EACV,UAAU;GACR;GACA;GACA;GACA;GACD;EACF;CACF,CAAC"}
|
package/dist/src/cli/index.d.ts
CHANGED
package/dist/src/cli/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { version } from "../../package.js";
|
|
3
|
+
import { isHelpOrVersionInvocation } from "./argv.js";
|
|
3
4
|
import { ROOT_COMMAND_DESCRIPTION } from "./command-manifest.js";
|
|
4
5
|
import { loadAllCommands, resolveCommandName, tryLoadCommand } from "./command-loaders.js";
|
|
5
6
|
import { getContextWithOpts, parsedOpts } from "./context.js";
|
|
@@ -12,6 +13,10 @@ async function flushLoggerAndExit(code) {
|
|
|
12
13
|
process.exit(code);
|
|
13
14
|
}
|
|
14
15
|
const LONG_RUNNING_COMMANDS = new Set(["gateway", "agent"]);
|
|
16
|
+
function argvWithDefaultCommand(argv, defaultCommand = "tui") {
|
|
17
|
+
if (resolveCommandName(argv) || isHelpOrVersionInvocation(argv)) return argv;
|
|
18
|
+
return [...argv, defaultCommand];
|
|
19
|
+
}
|
|
15
20
|
function isExtensionsDevCommand(command) {
|
|
16
21
|
return command.name() === "dev" && command.parent?.name() === "extensions";
|
|
17
22
|
}
|
|
@@ -39,17 +44,17 @@ function buildProgram() {
|
|
|
39
44
|
async function runCli(argv = process.argv) {
|
|
40
45
|
const program = buildProgram();
|
|
41
46
|
const ctx = getContextWithOpts(argv);
|
|
42
|
-
const
|
|
47
|
+
const argvToParse = argvWithDefaultCommand(argv.filter((arg, index) => {
|
|
43
48
|
if (arg !== "--") return true;
|
|
44
49
|
return index < 2;
|
|
45
|
-
});
|
|
46
|
-
const target = resolveCommandName(
|
|
50
|
+
}));
|
|
51
|
+
const target = resolveCommandName(argvToParse);
|
|
47
52
|
let loaded = false;
|
|
48
53
|
if (target) loaded = await tryLoadCommand(program, ctx, target, getContextWithOpts);
|
|
49
54
|
if (!loaded) await loadAllCommands(program, ctx, getContextWithOpts);
|
|
50
|
-
program.parse(
|
|
55
|
+
program.parse(argvToParse);
|
|
51
56
|
}
|
|
52
57
|
//#endregion
|
|
53
|
-
export { getContextWithOpts, parsedOpts, runCli };
|
|
58
|
+
export { argvWithDefaultCommand, getContextWithOpts, parsedOpts, runCli };
|
|
54
59
|
|
|
55
60
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["pkg.version"],"sources":["../../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\n/** Command wiring and `program.parse`; executable entry is `bin.ts` (log preset before logger init). */\nimport { Command } from 'commander';\nimport { ROOT_COMMAND_DESCRIPTION } from './command-manifest.js';\nimport pkg from '../../package.json' with { type: 'json' };\nimport { resolveCommandName, tryLoadCommand, loadAllCommands } from './command-loaders.js';\n\n// Lazy logger flush so that pure parameter-parsing paths (--help, --version,\n// `<unknown>`) never load the logger barrel. Imports `logger/shutdown.js`\n// directly to bypass `logger/index.ts` (pino + 8 sub-modules) on the cold path\n// — when an action did log, that import is already cached.\nasync function flushLoggerAndExit(code: number): Promise<never> {\n const { flushAndClose } = await import('../utils/logger/shutdown.js');\n await flushAndClose();\n process.exit(code);\n}\n\n// Re-exported from `./context.js` for backward compat. Command modules should\n// import from `./context.js` directly to avoid the CLI barrel cycle.\nexport { parsedOpts, getContextWithOpts } from './context.js';\nimport { parsedOpts, getContextWithOpts } from './context.js';\n\n// Commands whose action never resolves until an external shutdown signal.\n// `tui` is intentionally omitted: `await runTui()` completes when the user exits\n// the TUI and the process must call `process.exit` (interactive stdin stays open).\nconst LONG_RUNNING_COMMANDS = new Set(['gateway', 'agent']);\n\nfunction isExtensionsDevCommand(command: Command): boolean {\n return command.name() === 'dev' && command.parent?.name() === 'extensions';\n}\n\nfunction buildProgram(): Command {\n const program = new Command()\n .name('xopc')\n .description(ROOT_COMMAND_DESCRIPTION)\n .version(pkg.version)\n .option('--verbose', 'Enable verbose logging', false)\n .option('--config <path>', 'Config file path')\n .option('--workspace <path>', 'Workspace directory');\n\n // Hook to capture parsed options before each command runs. Mutate the\n // shared object in place — `parsedOpts` is a `const` import from\n // `./context.js` so command modules see updates through the same reference.\n program.hook('preAction', (thisCommand) => {\n const next = thisCommand.opts() as Record<string, unknown>;\n for (const k of Object.keys(parsedOpts)) {\n delete (parsedOpts as Record<string, unknown>)[k];\n }\n Object.assign(parsedOpts, next);\n });\n\n // Hook to ensure process exits after command completion.\n // Second arg is the command whose action ran; the first is the ancestor that\n // registered the hook (often the root program), so using only the first arg\n // mis-detects the subcommand as \"xopc\".\n program.hook('postAction', async (_hookOwner, actionCommand) => {\n const cmd = actionCommand ?? program;\n const args = cmd.args;\n const subCommandName = args.length > 0 ? args[0] : cmd.name();\n\n if (LONG_RUNNING_COMMANDS.has(subCommandName) || isExtensionsDevCommand(cmd)) {\n if (subCommandName === 'agent') {\n const hasInteractiveFlag = process.argv.includes('-i') || process.argv.includes('--interactive');\n if (!hasInteractiveFlag) {\n await flushLoggerAndExit(0);\n }\n }\n return;\n }\n await flushLoggerAndExit(0);\n });\n\n return program;\n}\n\nexport async function runCli(argv: string[] = process.argv): Promise<void> {\n const program = buildProgram();\n const ctx = getContextWithOpts(argv);\n\n // Filter out standalone '--' separator (passed by pnpm run -- <cmd>).\n // npm removes it automatically, pnpm passes it through. Keep '--' if it's a\n // script argument (index < 2), drop it only when it sits between the script\n // name and the actual command.\n const filteredArgv = argv.filter((arg, index) => {\n if (arg !== '--') return true;\n return index < 2;\n });\n\n const target = resolveCommandName(
|
|
1
|
+
{"version":3,"file":"index.js","names":["pkg.version"],"sources":["../../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\n/** Command wiring and `program.parse`; executable entry is `bin.ts` (log preset before logger init). */\nimport { Command } from 'commander';\nimport { ROOT_COMMAND_DESCRIPTION } from './command-manifest.js';\nimport pkg from '../../package.json' with { type: 'json' };\nimport { resolveCommandName, tryLoadCommand, loadAllCommands } from './command-loaders.js';\nimport { isHelpOrVersionInvocation } from './argv.js';\n\n// Lazy logger flush so that pure parameter-parsing paths (--help, --version,\n// `<unknown>`) never load the logger barrel. Imports `logger/shutdown.js`\n// directly to bypass `logger/index.ts` (pino + 8 sub-modules) on the cold path\n// — when an action did log, that import is already cached.\nasync function flushLoggerAndExit(code: number): Promise<never> {\n const { flushAndClose } = await import('../utils/logger/shutdown.js');\n await flushAndClose();\n process.exit(code);\n}\n\n// Re-exported from `./context.js` for backward compat. Command modules should\n// import from `./context.js` directly to avoid the CLI barrel cycle.\nexport { parsedOpts, getContextWithOpts } from './context.js';\nimport { parsedOpts, getContextWithOpts } from './context.js';\n\n// Commands whose action never resolves until an external shutdown signal.\n// `tui` is intentionally omitted: `await runTui()` completes when the user exits\n// the TUI and the process must call `process.exit` (interactive stdin stays open).\nconst LONG_RUNNING_COMMANDS = new Set(['gateway', 'agent']);\n\nexport function argvWithDefaultCommand(argv: string[], defaultCommand = 'tui'): string[] {\n const target = resolveCommandName(argv);\n if (target || isHelpOrVersionInvocation(argv)) {\n return argv;\n }\n return [...argv, defaultCommand];\n}\n\nfunction isExtensionsDevCommand(command: Command): boolean {\n return command.name() === 'dev' && command.parent?.name() === 'extensions';\n}\n\nfunction buildProgram(): Command {\n const program = new Command()\n .name('xopc')\n .description(ROOT_COMMAND_DESCRIPTION)\n .version(pkg.version)\n .option('--verbose', 'Enable verbose logging', false)\n .option('--config <path>', 'Config file path')\n .option('--workspace <path>', 'Workspace directory');\n\n // Hook to capture parsed options before each command runs. Mutate the\n // shared object in place — `parsedOpts` is a `const` import from\n // `./context.js` so command modules see updates through the same reference.\n program.hook('preAction', (thisCommand) => {\n const next = thisCommand.opts() as Record<string, unknown>;\n for (const k of Object.keys(parsedOpts)) {\n delete (parsedOpts as Record<string, unknown>)[k];\n }\n Object.assign(parsedOpts, next);\n });\n\n // Hook to ensure process exits after command completion.\n // Second arg is the command whose action ran; the first is the ancestor that\n // registered the hook (often the root program), so using only the first arg\n // mis-detects the subcommand as \"xopc\".\n program.hook('postAction', async (_hookOwner, actionCommand) => {\n const cmd = actionCommand ?? program;\n const args = cmd.args;\n const subCommandName = args.length > 0 ? args[0] : cmd.name();\n\n if (LONG_RUNNING_COMMANDS.has(subCommandName) || isExtensionsDevCommand(cmd)) {\n if (subCommandName === 'agent') {\n const hasInteractiveFlag = process.argv.includes('-i') || process.argv.includes('--interactive');\n if (!hasInteractiveFlag) {\n await flushLoggerAndExit(0);\n }\n }\n return;\n }\n await flushLoggerAndExit(0);\n });\n\n return program;\n}\n\nexport async function runCli(argv: string[] = process.argv): Promise<void> {\n const program = buildProgram();\n const ctx = getContextWithOpts(argv);\n\n // Filter out standalone '--' separator (passed by pnpm run -- <cmd>).\n // npm removes it automatically, pnpm passes it through. Keep '--' if it's a\n // script argument (index < 2), drop it only when it sits between the script\n // name and the actual command.\n const filteredArgv = argv.filter((arg, index) => {\n if (arg !== '--') return true;\n return index < 2;\n });\n\n const argvToParse = argvWithDefaultCommand(filteredArgv);\n const target = resolveCommandName(argvToParse);\n let loaded = false;\n if (target) {\n loaded = await tryLoadCommand(program, ctx, target, getContextWithOpts);\n }\n if (!loaded) {\n // Unknown command, no command, or commander needs the full set (e.g. for\n // root help fallback). Load every command so commander can dispatch\n // properly.\n await loadAllCommands(program, ctx, getContextWithOpts);\n }\n\n program.parse(argvToParse);\n}\n"],"mappings":";;;;;;;;;AAYA,eAAe,mBAAmB,MAA8B;CAC9D,MAAM,EAAE,kBAAkB,MAAM,OAAO;AACvC,OAAM,eAAe;AACrB,SAAQ,KAAK,KAAK;;AAWpB,MAAM,wBAAwB,IAAI,IAAI,CAAC,WAAW,QAAQ,CAAC;AAE3D,SAAgB,uBAAuB,MAAgB,iBAAiB,OAAiB;AAEvF,KADe,mBAAmB,KACxB,IAAI,0BAA0B,KAAK,CAC3C,QAAO;AAET,QAAO,CAAC,GAAG,MAAM,eAAe;;AAGlC,SAAS,uBAAuB,SAA2B;AACzD,QAAO,QAAQ,MAAM,KAAK,SAAS,QAAQ,QAAQ,MAAM,KAAK;;AAGhE,SAAS,eAAwB;CAC/B,MAAM,UAAU,IAAI,SAAS,CAC1B,KAAK,OAAO,CACZ,YAAY,yBAAyB,CACrC,QAAQA,QAAY,CACpB,OAAO,aAAa,0BAA0B,MAAM,CACpD,OAAO,mBAAmB,mBAAmB,CAC7C,OAAO,sBAAsB,sBAAsB;AAKtD,SAAQ,KAAK,cAAc,gBAAgB;EACzC,MAAM,OAAO,YAAY,MAAM;AAC/B,OAAK,MAAM,KAAK,OAAO,KAAK,WAAW,CACrC,QAAQ,WAAuC;AAEjD,SAAO,OAAO,YAAY,KAAK;GAC/B;AAMF,SAAQ,KAAK,cAAc,OAAO,YAAY,kBAAkB;EAC9D,MAAM,MAAM,iBAAiB;EAC7B,MAAM,OAAO,IAAI;EACjB,MAAM,iBAAiB,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,MAAM;AAE7D,MAAI,sBAAsB,IAAI,eAAe,IAAI,uBAAuB,IAAI,EAAE;AAC5E,OAAI,mBAAmB;QAEjB,EADuB,QAAQ,KAAK,SAAS,KAAK,IAAI,QAAQ,KAAK,SAAS,gBAAgB,EAE9F,OAAM,mBAAmB,EAAE;;AAG/B;;AAEF,QAAM,mBAAmB,EAAE;GAC3B;AAEF,QAAO;;AAGT,eAAsB,OAAO,OAAiB,QAAQ,MAAqB;CACzE,MAAM,UAAU,cAAc;CAC9B,MAAM,MAAM,mBAAmB,KAAK;CAWpC,MAAM,cAAc,uBALC,KAAK,QAAQ,KAAK,UAAU;AAC/C,MAAI,QAAQ,KAAM,QAAO;AACzB,SAAO,QAAQ;GAGsC,CAAC;CACxD,MAAM,SAAS,mBAAmB,YAAY;CAC9C,IAAI,SAAS;AACb,KAAI,OACF,UAAS,MAAM,eAAe,SAAS,KAAK,QAAQ,mBAAmB;AAEzE,KAAI,CAAC,OAIH,OAAM,gBAAgB,SAAS,KAAK,mBAAmB;AAGzD,SAAQ,MAAM,YAAY"}
|
package/dist/src/cli/registry.js
CHANGED
|
@@ -5,7 +5,7 @@ init_paths();
|
|
|
5
5
|
init_workspace_defaults();
|
|
6
6
|
function createDefaultContext(argv = process.argv, opts) {
|
|
7
7
|
return {
|
|
8
|
-
configPath: opts?.config || process.env.XOPC_CONFIG || resolveConfigPath(),
|
|
8
|
+
configPath: opts?.config || process.env.XOPC_CONFIG || process.env.XOPC_CONFIG_PATH || resolveConfigPath(),
|
|
9
9
|
workspacePath: opts?.workspace || process.env.XOPC_WORKSPACE || resolveDefaultAgentWorkspaceDir(),
|
|
10
10
|
isVerbose: opts?.verbose ?? (argv.includes("--verbose") || argv.includes("-v")),
|
|
11
11
|
argv
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","names":[],"sources":["../../../src/cli/registry.ts"],"sourcesContent":["import type { Command } from 'commander';\nimport { resolveConfigPath } from '../config/paths.js';\nimport { resolveDefaultAgentWorkspaceDir } from '../config/workspace-defaults.js';\n\nexport interface CLIContext {\n configPath: string;\n workspacePath: string;\n isVerbose: boolean;\n argv: string[];\n}\n\nexport function createDefaultContext(\n argv: string[] = process.argv,\n opts?: { config?: string; workspace?: string; verbose?: boolean }\n): CLIContext {\n return {\n configPath: opts?.config || process.env.XOPC_CONFIG || resolveConfigPath(),\n workspacePath: opts?.workspace || process.env.XOPC_WORKSPACE || resolveDefaultAgentWorkspaceDir(),\n isVerbose: (opts?.verbose ?? (argv.includes('--verbose') || argv.includes('-v'))),\n argv,\n };\n}\n\nexport interface CommandMetadata {\n category?: 'setup' | 'runtime' | 'maintenance' | 'utility';\n hidden?: boolean;\n unstable?: boolean;\n examples?: string[];\n}\n\nexport interface CommandDefinition {\n id: string;\n name: string;\n description: string;\n factory: (ctx: CLIContext, getCtx?: () => CLIContext) => Command;\n metadata?: CommandMetadata;\n}\n\nexport class CommandRegistry {\n private commands: CommandDefinition[] = [];\n private initialized = false;\n private suppressLateRegistrationWarnings = false;\n\n /**\n * Temporarily silence the \"registered after initialization\" warning. Used by\n * commands that need to bulk-load other command modules to harvest their\n * side effects during initialization.\n */\n setSuppressLateRegistrationWarnings(value: boolean): void {\n this.suppressLateRegistrationWarnings = value;\n }\n\n register(def: CommandDefinition): void {\n if (this.initialized && !this.suppressLateRegistrationWarnings) {\n console.warn(`Warning: Command \"${def.id}\" registered after initialization`);\n }\n\n const existing = this.commands.find(c => c.id === def.id);\n if (existing) {\n throw new Error(`Command with id \"${def.id}\" already registered (name: ${existing.name})`);\n }\n\n const existingName = this.commands.find(c => c.name === def.name);\n if (existingName) {\n throw new Error(`Command with name \"${def.name}\" already registered (id: ${existingName.id})`);\n }\n\n this.commands.push(def);\n }\n\n registerAll(defs: CommandDefinition[]): void {\n for (const def of defs) {\n this.register(def);\n }\n }\n\n getCommands(): ReadonlyArray<CommandDefinition> {\n return this.commands;\n }\n\n getCommandsByCategory(category: CommandMetadata['category']): ReadonlyArray<CommandDefinition> {\n return this.commands.filter(c => c.metadata?.category === category);\n }\n\n findById(id: string): CommandDefinition | undefined {\n return this.commands.find(c => c.id === id);\n }\n\n findByName(name: string): CommandDefinition | undefined {\n return this.commands.find(c => c.name === name);\n }\n\n install(program: Command, ctx: CLIContext, getCtx?: () => CLIContext): void {\n this.initialized = true;\n\n const categoryOrder = { setup: 0, runtime: 1, maintenance: 2, utility: 3 };\n const sorted = [...this.commands].sort((a, b) => {\n const orderA = categoryOrder[a.metadata?.category ?? 'utility'];\n const orderB = categoryOrder[b.metadata?.category ?? 'utility'];\n return orderA - orderB;\n });\n\n for (const def of sorted) {\n if (def.metadata?.hidden) continue;\n\n try {\n const cmd = def.factory(ctx, getCtx);\n program.addCommand(cmd);\n } catch (error) {\n console.error(`Failed to register command \"${def.id}\":`, error);\n }\n }\n }\n\n installOne(\n program: Command,\n name: string,\n ctx: CLIContext,\n getCtx?: () => CLIContext,\n ): boolean {\n this.initialized = true;\n const def = this.findByName(name);\n if (!def || def.metadata?.hidden) return false;\n try {\n const cmd = def.factory(ctx, getCtx);\n program.addCommand(cmd);\n return true;\n } catch (error) {\n console.error(`Failed to register command \"${def.id}\":`, error);\n return false;\n }\n }\n\n getStats(): { total: number; byCategory: Record<string, number> } {\n const byCategory: Record<string, number> = {};\n for (const cmd of this.commands) {\n const cat = cmd.metadata?.category ?? 'uncategorized';\n byCategory[cat] = (byCategory[cat] || 0) + 1;\n }\n return { total: this.commands.length, byCategory };\n }\n}\n\nexport const registry = new CommandRegistry();\n\nexport function register(def: CommandDefinition): void {\n registry.register(def);\n}\n\nexport function formatExamples(examples: string[]): string {\n if (examples.length === 0) return '';\n return '\\nExamples:\\n' + examples.map(e => ` $ ${e}`).join('\\n');\n}\n"],"mappings":";;;YACuD;yBAC2B;AASlF,SAAgB,qBACd,OAAiB,QAAQ,MACzB,MACY;AACZ,QAAO;EACL,YAAY,MAAM,UAAU,QAAQ,IAAI,eAAe,mBAAmB;
|
|
1
|
+
{"version":3,"file":"registry.js","names":[],"sources":["../../../src/cli/registry.ts"],"sourcesContent":["import type { Command } from 'commander';\nimport { resolveConfigPath } from '../config/paths.js';\nimport { resolveDefaultAgentWorkspaceDir } from '../config/workspace-defaults.js';\n\nexport interface CLIContext {\n configPath: string;\n workspacePath: string;\n isVerbose: boolean;\n argv: string[];\n}\n\nexport function createDefaultContext(\n argv: string[] = process.argv,\n opts?: { config?: string; workspace?: string; verbose?: boolean }\n): CLIContext {\n return {\n configPath: opts?.config || process.env.XOPC_CONFIG || process.env.XOPC_CONFIG_PATH || resolveConfigPath(),\n workspacePath: opts?.workspace || process.env.XOPC_WORKSPACE || resolveDefaultAgentWorkspaceDir(),\n isVerbose: (opts?.verbose ?? (argv.includes('--verbose') || argv.includes('-v'))),\n argv,\n };\n}\n\nexport interface CommandMetadata {\n category?: 'setup' | 'runtime' | 'maintenance' | 'utility';\n hidden?: boolean;\n unstable?: boolean;\n examples?: string[];\n}\n\nexport interface CommandDefinition {\n id: string;\n name: string;\n description: string;\n factory: (ctx: CLIContext, getCtx?: () => CLIContext) => Command;\n metadata?: CommandMetadata;\n}\n\nexport class CommandRegistry {\n private commands: CommandDefinition[] = [];\n private initialized = false;\n private suppressLateRegistrationWarnings = false;\n\n /**\n * Temporarily silence the \"registered after initialization\" warning. Used by\n * commands that need to bulk-load other command modules to harvest their\n * side effects during initialization.\n */\n setSuppressLateRegistrationWarnings(value: boolean): void {\n this.suppressLateRegistrationWarnings = value;\n }\n\n register(def: CommandDefinition): void {\n if (this.initialized && !this.suppressLateRegistrationWarnings) {\n console.warn(`Warning: Command \"${def.id}\" registered after initialization`);\n }\n\n const existing = this.commands.find(c => c.id === def.id);\n if (existing) {\n throw new Error(`Command with id \"${def.id}\" already registered (name: ${existing.name})`);\n }\n\n const existingName = this.commands.find(c => c.name === def.name);\n if (existingName) {\n throw new Error(`Command with name \"${def.name}\" already registered (id: ${existingName.id})`);\n }\n\n this.commands.push(def);\n }\n\n registerAll(defs: CommandDefinition[]): void {\n for (const def of defs) {\n this.register(def);\n }\n }\n\n getCommands(): ReadonlyArray<CommandDefinition> {\n return this.commands;\n }\n\n getCommandsByCategory(category: CommandMetadata['category']): ReadonlyArray<CommandDefinition> {\n return this.commands.filter(c => c.metadata?.category === category);\n }\n\n findById(id: string): CommandDefinition | undefined {\n return this.commands.find(c => c.id === id);\n }\n\n findByName(name: string): CommandDefinition | undefined {\n return this.commands.find(c => c.name === name);\n }\n\n install(program: Command, ctx: CLIContext, getCtx?: () => CLIContext): void {\n this.initialized = true;\n\n const categoryOrder = { setup: 0, runtime: 1, maintenance: 2, utility: 3 };\n const sorted = [...this.commands].sort((a, b) => {\n const orderA = categoryOrder[a.metadata?.category ?? 'utility'];\n const orderB = categoryOrder[b.metadata?.category ?? 'utility'];\n return orderA - orderB;\n });\n\n for (const def of sorted) {\n if (def.metadata?.hidden) continue;\n\n try {\n const cmd = def.factory(ctx, getCtx);\n program.addCommand(cmd);\n } catch (error) {\n console.error(`Failed to register command \"${def.id}\":`, error);\n }\n }\n }\n\n installOne(\n program: Command,\n name: string,\n ctx: CLIContext,\n getCtx?: () => CLIContext,\n ): boolean {\n this.initialized = true;\n const def = this.findByName(name);\n if (!def || def.metadata?.hidden) return false;\n try {\n const cmd = def.factory(ctx, getCtx);\n program.addCommand(cmd);\n return true;\n } catch (error) {\n console.error(`Failed to register command \"${def.id}\":`, error);\n return false;\n }\n }\n\n getStats(): { total: number; byCategory: Record<string, number> } {\n const byCategory: Record<string, number> = {};\n for (const cmd of this.commands) {\n const cat = cmd.metadata?.category ?? 'uncategorized';\n byCategory[cat] = (byCategory[cat] || 0) + 1;\n }\n return { total: this.commands.length, byCategory };\n }\n}\n\nexport const registry = new CommandRegistry();\n\nexport function register(def: CommandDefinition): void {\n registry.register(def);\n}\n\nexport function formatExamples(examples: string[]): string {\n if (examples.length === 0) return '';\n return '\\nExamples:\\n' + examples.map(e => ` $ ${e}`).join('\\n');\n}\n"],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Templates are stored in docs/reference/templates/ and loaded at runtime.
|
|
4
4
|
*/
|
|
5
5
|
/** Profile Markdown template file names (seeded into `agents/<id>/profile/`). */
|
|
6
|
-
export declare const TEMPLATE_FILES: readonly ["SOUL.md", "IDENTITY.md", "
|
|
6
|
+
export declare const TEMPLATE_FILES: readonly ["SOUL.md", "IDENTITY.md", "TOOLS.md", "AGENTS.md", "HEARTBEAT.md", "MEMORY.md"];
|
|
7
7
|
export type TemplateFile = (typeof TEMPLATE_FILES)[number];
|
|
8
8
|
/** Alias for profile Markdown templates used by seed helpers. */
|
|
9
9
|
export declare const PROFILE_MARKDOWN_TEMPLATE_FILES: readonly TemplateFile[];
|
|
@@ -11,7 +11,6 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
11
11
|
const TEMPLATE_FILES = [
|
|
12
12
|
"SOUL.md",
|
|
13
13
|
"IDENTITY.md",
|
|
14
|
-
"USER.md",
|
|
15
14
|
"TOOLS.md",
|
|
16
15
|
"AGENTS.md",
|
|
17
16
|
"HEARTBEAT.md",
|
|
@@ -71,7 +70,7 @@ This folder is home. Treat it that way.
|
|
|
71
70
|
|
|
72
71
|
## Session Startup
|
|
73
72
|
|
|
74
|
-
Use runtime-provided startup context first. Bootstrap files (
|
|
73
|
+
Use runtime-provided startup context first. Bootstrap files (global user profile, SOUL, MEMORY, etc.) are injected by xopc on /new and /reset.
|
|
75
74
|
|
|
76
75
|
Do not manually reread startup files unless the user asks or the provided context is incomplete.
|
|
77
76
|
|
|
@@ -116,15 +115,6 @@ _Fill this in during your first conversation._
|
|
|
116
115
|
- **Creature:**
|
|
117
116
|
- **Vibe:**
|
|
118
117
|
- **Emoji:**
|
|
119
|
-
`,
|
|
120
|
-
"USER.md": `# USER.md - About Your Human
|
|
121
|
-
|
|
122
|
-
_Learn about the person you're helping._
|
|
123
|
-
|
|
124
|
-
- **Name:**
|
|
125
|
-
- **What to call them:**
|
|
126
|
-
- **Timezone:**
|
|
127
|
-
- **Notes:**
|
|
128
118
|
`,
|
|
129
119
|
"TOOLS.md": `# TOOLS.md - Local Notes
|
|
130
120
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.js","names":[],"sources":["../../../src/cli/templates.ts"],"sourcesContent":["/**\n * Workspace template files for onboarding.\n * Templates are stored in docs/reference/templates/ and loaded at runtime.\n */\n\nimport { readFileSync, existsSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/** Profile Markdown template file names (seeded into `agents/<id>/profile/`). */\nexport const TEMPLATE_FILES = [\n 'SOUL.md',\n 'IDENTITY.md',\n '
|
|
1
|
+
{"version":3,"file":"templates.js","names":[],"sources":["../../../src/cli/templates.ts"],"sourcesContent":["/**\n * Workspace template files for onboarding.\n * Templates are stored in docs/reference/templates/ and loaded at runtime.\n */\n\nimport { readFileSync, existsSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/** Profile Markdown template file names (seeded into `agents/<id>/profile/`). */\nexport const TEMPLATE_FILES = [\n 'SOUL.md',\n 'IDENTITY.md',\n 'TOOLS.md',\n 'AGENTS.md',\n 'HEARTBEAT.md',\n 'MEMORY.md',\n] as const;\n\nexport type TemplateFile = (typeof TEMPLATE_FILES)[number];\n\n/** Alias for profile Markdown templates used by seed helpers. */\nexport const PROFILE_MARKDOWN_TEMPLATE_FILES: readonly TemplateFile[] = [...TEMPLATE_FILES];\n\n/** Template content cache */\nconst templateCache = new Map<TemplateFile, string>();\n\n/**\n * Get the path to template files.\n * Uses environment or looks in project root.\n */\nfunction getTemplatePath(): string {\n // Use environment to determine path\n const envPath = process.env.XOPC_TEMPLATE_PATH;\n if (envPath && existsSync(envPath)) {\n return envPath;\n }\n\n // Default: look in project root docs/reference/templates\n // Works for both development (src/cli/) and production (dist/cli/)\n const projectRoot = join(__dirname, '../../..');\n const defaultPath = join(projectRoot, 'docs/reference/templates');\n \n if (existsSync(defaultPath)) {\n return defaultPath;\n }\n\n // Fallback: return default (will fail gracefully)\n return defaultPath;\n}\n\n/**\n * Load a template file. Caches results for repeated access.\n */\nexport function loadTemplate(name: TemplateFile): string {\n // Return cached version if available\n if (templateCache.has(name)) {\n return templateCache.get(name)!;\n }\n\n const templatePath = join(getTemplatePath(), name);\n \n try {\n if (existsSync(templatePath)) {\n const content = readFileSync(templatePath, 'utf-8');\n templateCache.set(name, content);\n return content;\n }\n } catch {\n // Fall through to fallback\n }\n\n // Fallback: return minimal default if template is missing\n console.warn(`Warning: Template ${name} not found, using fallback`);\n return getFallbackTemplate(name);\n}\n\n/**\n * Load all templates as a record.\n */\nexport function loadAllTemplates(): Record<TemplateFile, string> {\n const result = {} as Record<TemplateFile, string>;\n for (const name of TEMPLATE_FILES) {\n result[name] = loadTemplate(name);\n }\n return result;\n}\n\n/**\n * Clear the template cache (useful for testing).\n */\nexport function clearTemplateCache(): void {\n templateCache.clear();\n}\n\n/** Minimal fallback templates in case files are missing */\nexport function getFallbackTemplate(name: TemplateFile): string {\n const fallbacks: Record<TemplateFile, string> = {\n 'AGENTS.md': `# AGENTS.md - Your Workspace\n\nThis folder is home. Treat it that way.\n\n## Session Startup\n\nUse runtime-provided startup context first. Bootstrap files (global user profile, SOUL, MEMORY, etc.) are injected by xopc on /new and /reset.\n\nDo not manually reread startup files unless the user asks or the provided context is incomplete.\n\n## Red Lines\n\n- Don't exfiltrate private data\n- Don't run destructive commands without asking\n- When in doubt, ask\n\n## Memory\n\n- **Daily notes:** \\`memory/YYYY-MM-DD.md\\`\n- **Long-term:** profile \\`MEMORY.md\\`\n\nWrite what matters. Text > Brain.\n`,\n 'SOUL.md': `# SOUL.md - Who You Are\n\n_You're not a chatbot. You're becoming someone._\n\n## Core Truths\n\n- Be genuinely helpful, not performatively helpful\n- Have opinions\n- Be resourceful before asking\n- Earn trust through competence\n- Remember you're a guest\n\n## Boundaries\n\n- Private things stay private\n- When in doubt, ask before acting externally\n- Never send half-baked replies\n\nThis file is yours to evolve.\n`,\n 'IDENTITY.md': `# IDENTITY.md - Who Am I?\n\n_Fill this in during your first conversation._\n\n- **Name:**\n- **Creature:**\n- **Vibe:**\n- **Emoji:**\n`,\n 'TOOLS.md': `# TOOLS.md - Local Notes\n\nEnvironment-specific notes:\n\n- SSH hosts\n- API endpoints\n- Device nicknames\n`,\n 'HEARTBEAT.md': `# HEARTBEAT.md - Periodic Checks\n\nEdit this file to define what you check during heartbeat polls.\n\n## Example Checklist\n\n- [ ] Check email for urgent messages\n- [ ] Check calendar for upcoming events\n\n**Remember:** If nothing needs attention, reply \\`HEARTBEAT_OK\\`.\n`,\n 'MEMORY.md': `# MEMORY.md - Long-Term Memory\n\n_Your curated memories._\n\n## People\n\n## Projects\n\n## Preferences\n\n## Learned Lessons\n\n**Only load in main sessions.**\n`,\n };\n \n return fallbacks[name] || `# ${name}\\n\\n(Template content missing)\\n`;\n}\n"],"mappings":";;;;;;;;AAUA,MAAM,YAAY,QADC,cAAc,OAAO,KAAK,IACT,CAAC;;AAGrC,MAAa,iBAAiB;CAC5B;CACA;CACA;CACA;CACA;CACA;CACD;;AAKD,MAAa,kCAA2D,CAAC,GAAG,eAAe;;AAG3F,MAAM,gCAAgB,IAAI,KAA2B;;;;;AAMrD,SAAS,kBAA0B;CAEjC,MAAM,UAAU,QAAQ,IAAI;AAC5B,KAAI,WAAW,WAAW,QAAQ,CAChC,QAAO;CAMT,MAAM,cAAc,KADA,KAAK,WAAW,WACA,EAAE,2BAA2B;AAEjE,KAAI,WAAW,YAAY,CACzB,QAAO;AAIT,QAAO;;;;;AAMT,SAAgB,aAAa,MAA4B;AAEvD,KAAI,cAAc,IAAI,KAAK,CACzB,QAAO,cAAc,IAAI,KAAK;CAGhC,MAAM,eAAe,KAAK,iBAAiB,EAAE,KAAK;AAElD,KAAI;AACF,MAAI,WAAW,aAAa,EAAE;GAC5B,MAAM,UAAU,aAAa,cAAc,QAAQ;AACnD,iBAAc,IAAI,MAAM,QAAQ;AAChC,UAAO;;SAEH;AAKR,SAAQ,KAAK,qBAAqB,KAAK,4BAA4B;AACnE,QAAO,oBAAoB,KAAK;;;;;AAMlC,SAAgB,mBAAiD;CAC/D,MAAM,SAAS,EAAE;AACjB,MAAK,MAAM,QAAQ,eACjB,QAAO,QAAQ,aAAa,KAAK;AAEnC,QAAO;;;;;AAMT,SAAgB,qBAA2B;AACzC,eAAc,OAAO;;;AAIvB,SAAgB,oBAAoB,MAA4B;AAyF9D,QAAO;EAvFL,aAAa;;;;;;;;;;;;;;;;;;;;;;;EAuBb,WAAW;;;;;;;;;;;;;;;;;;;;EAoBX,eAAe;;;;;;;;;EASf,YAAY;;;;;;;;EAQZ,gBAAgB;;;;;;;;;;;EAWhB,aAAa;;;;;;;;;;;;;;EAgBC,CAAC,SAAS,KAAK,KAAK"}
|
|
@@ -26,10 +26,6 @@ function applyAgentConfig(cfg, params) {
|
|
|
26
26
|
},
|
|
27
27
|
responsibilities: { primary: ["Help the user complete tasks"] },
|
|
28
28
|
workspace: { root: `~/.xopc/workspace/${agentId}` },
|
|
29
|
-
models: {
|
|
30
|
-
defaultRole: "deep",
|
|
31
|
-
roles: { deep: { model: params.model ?? "openai/gpt-4.1" } }
|
|
32
|
-
},
|
|
33
29
|
tools: { builtin: {} },
|
|
34
30
|
skills: { mode: "all" },
|
|
35
31
|
memory: {
|
|
@@ -50,10 +46,10 @@ function applyAgentConfig(cfg, params) {
|
|
|
50
46
|
...params.workspace ? { workspace: { root: params.workspace } } : {},
|
|
51
47
|
...params.models ? { models: params.models } : {},
|
|
52
48
|
...params.model ? { models: {
|
|
53
|
-
...base.models,
|
|
49
|
+
...base.models ?? {},
|
|
54
50
|
defaultRole: "deep",
|
|
55
51
|
roles: {
|
|
56
|
-
...base.models
|
|
52
|
+
...base.models?.roles ?? {},
|
|
57
53
|
deep: { model: params.model }
|
|
58
54
|
}
|
|
59
55
|
} } : {},
|
|
@@ -77,10 +73,6 @@ function applyAgentConfig(cfg, params) {
|
|
|
77
73
|
},
|
|
78
74
|
responsibilities: { primary: ["Help the user complete tasks"] },
|
|
79
75
|
workspace: { root: `~/.xopc/workspace/${resolveDefaultAgentId(cfg)}` },
|
|
80
|
-
models: {
|
|
81
|
-
defaultRole: "deep",
|
|
82
|
-
roles: { deep: { model: "openai/gpt-4.1" } }
|
|
83
|
-
},
|
|
84
76
|
tools: { builtin: {} },
|
|
85
77
|
skills: { mode: "all" },
|
|
86
78
|
memory: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.config.js","names":[],"sources":["../../../src/commands/agents.config.ts"],"sourcesContent":["/**\n * Mutate `agents.list` / bindings when adding or removing agents.\n */\n\nimport { rm } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\n\nimport type { Config } from '../config/schema.js';\nimport {\n listAgentEntries,\n normalizeAgentId,\n resolveAgentHomeDir,\n resolveAgentWorkspaceDir,\n resolveDefaultAgentId,\n DEFAULT_AGENT_ID,\n} from '../agent/agent-scope.js';\n\ntype AgentEntry = NonNullable<NonNullable<Config['agents']>['list']>[number];\n\nexport { listAgentEntries };\n\nexport function findAgentEntryIndex(list: AgentEntry[], agentId: string): number {\n const id = normalizeAgentId(agentId);\n return list.findIndex((e) => normalizeAgentId(e.id) === id);\n}\n\nexport function applyAgentConfig(\n cfg: Config,\n params: {\n agentId: string;\n workspace?: string;\n model?: string;\n models?: AgentEntry['models'];\n skills?: string[];\n tools?: AgentEntry['tools'];\n },\n): Config {\n const agentId = normalizeAgentId(params.agentId);\n const list = listAgentEntries(cfg);\n const index = findAgentEntryIndex(list, agentId);\n const nextTools = params.tools;\n const base = index >= 0 ? list[index] : {\n id: agentId,\n enabled: true as const,\n identity: { name: agentId, role: 'Agent', language: 'en', tone: 'direct' },\n responsibilities: { primary: ['Help the user complete tasks'] },\n workspace: { root: `~/.xopc/workspace/${agentId}` },\n
|
|
1
|
+
{"version":3,"file":"agents.config.js","names":[],"sources":["../../../src/commands/agents.config.ts"],"sourcesContent":["/**\n * Mutate `agents.list` / bindings when adding or removing agents.\n */\n\nimport { rm } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\n\nimport type { Config } from '../config/schema.js';\nimport {\n listAgentEntries,\n normalizeAgentId,\n resolveAgentHomeDir,\n resolveAgentWorkspaceDir,\n resolveDefaultAgentId,\n DEFAULT_AGENT_ID,\n} from '../agent/agent-scope.js';\n\ntype AgentEntry = NonNullable<NonNullable<Config['agents']>['list']>[number];\n\nexport { listAgentEntries };\n\nexport function findAgentEntryIndex(list: AgentEntry[], agentId: string): number {\n const id = normalizeAgentId(agentId);\n return list.findIndex((e) => normalizeAgentId(e.id) === id);\n}\n\nexport function applyAgentConfig(\n cfg: Config,\n params: {\n agentId: string;\n workspace?: string;\n model?: string;\n models?: AgentEntry['models'];\n skills?: string[];\n tools?: AgentEntry['tools'];\n },\n): Config {\n const agentId = normalizeAgentId(params.agentId);\n const list = listAgentEntries(cfg);\n const index = findAgentEntryIndex(list, agentId);\n const nextTools = params.tools;\n const base = index >= 0 ? list[index] : {\n id: agentId,\n enabled: true as const,\n identity: { name: agentId, role: 'Agent', language: 'en', tone: 'direct' },\n responsibilities: { primary: ['Help the user complete tasks'] },\n workspace: { root: `~/.xopc/workspace/${agentId}` },\n tools: { builtin: {} },\n skills: { mode: 'all' as const },\n memory: { mode: 'confirmWrite' as const, sources: ['session' as const, 'curated' as const], writePolicy: { curated: 'confirm' as const } },\n workflows: {},\n boundaries: { requiresConfirmation: [], forbidden: [], escalation: [] },\n };\n const nextEntry: AgentEntry = {\n ...base,\n enabled: base.enabled ?? true,\n ...(params.workspace ? { workspace: { root: params.workspace } } : {}),\n ...(params.models ? { models: params.models } : {}),\n ...(params.model\n ? {\n models: {\n ...(base.models ?? {}),\n defaultRole: 'deep',\n roles: { ...(base.models?.roles ?? {}), deep: { model: params.model } },\n },\n }\n : {}),\n ...(params.skills ? { skills: { mode: 'allowlist' as const, allow: params.skills } } : {}),\n ...(nextTools ? { tools: nextTools } : {}),\n };\n const nextList = [...list];\n if (index >= 0) {\n nextList[index] = nextEntry;\n } else {\n if (nextList.length === 0 && agentId !== normalizeAgentId(resolveDefaultAgentId(cfg))) {\n nextList.push({\n id: resolveDefaultAgentId(cfg),\n enabled: true,\n identity: { name: resolveDefaultAgentId(cfg), role: 'Agent', language: 'en', tone: 'direct' },\n responsibilities: { primary: ['Help the user complete tasks'] },\n workspace: { root: `~/.xopc/workspace/${resolveDefaultAgentId(cfg)}` },\n tools: { builtin: {} },\n skills: { mode: 'all' },\n memory: { mode: 'confirmWrite', sources: ['session', 'curated'], writePolicy: { curated: 'confirm' } },\n workflows: {},\n boundaries: { requiresConfirmation: [], forbidden: [], escalation: [] },\n });\n }\n nextList.push(nextEntry);\n }\n return {\n ...cfg,\n agents: {\n ...cfg.agents,\n list: nextList,\n },\n };\n}\n\nexport function pruneAgentConfig(\n cfg: Config,\n agentId: string,\n): { config: Config; removedBindings: number } {\n const id = normalizeAgentId(agentId);\n const agents = listAgentEntries(cfg);\n const nextAgentsList = agents.filter((e) => normalizeAgentId(e.id) !== id);\n const nextAgents = nextAgentsList.length > 0 ? nextAgentsList : [];\n\n const bindings = cfg.bindings ?? [];\n const filteredBindings = bindings.filter((b) => normalizeAgentId(b.agentId) !== id);\n\n return {\n config: {\n ...cfg,\n agents: { ...cfg.agents, list: nextAgents },\n bindings: filteredBindings,\n },\n removedBindings: bindings.length - filteredBindings.length,\n };\n}\n\nexport async function removeAgentDirsFromDisk(cfg: Config, id: string): Promise<void> {\n const aid = normalizeAgentId(id);\n if (aid === DEFAULT_AGENT_ID) {\n throw new Error('Refusing to delete the main agent home on disk from this command.');\n }\n const home = resolveAgentHomeDir(cfg, aid);\n const ws = resolveAgentWorkspaceDir(cfg, aid);\n if (existsSync(home)) {\n await rm(home, { recursive: true, force: true });\n }\n if (existsSync(ws) && ws !== home) {\n await rm(ws, { recursive: true, force: true });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { init_agent_scope, normalizeAgentId, resolveAgentWorkspaceDir } from "../agent/agent-scope.js";
|
|
1
2
|
import { resolveEffectiveAgentManifest } from "../agent-manifest/resolver.js";
|
|
2
3
|
import "../agent-manifest/index.js";
|
|
3
|
-
import { init_agent_scope, normalizeAgentId, resolveAgentWorkspaceDir } from "../agent/agent-scope.js";
|
|
4
4
|
import { init_session_key, parseSessionKey } from "../routing/session-key.js";
|
|
5
5
|
import { agentExists, getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
|
|
6
6
|
//#region src/config/agent-profile.ts
|
|
@@ -24,7 +24,8 @@ function resolveEffectiveAgentManifestForAgent(config, agentId) {
|
|
|
24
24
|
if (!agent) throw new Error(`No enabled agent manifest found for "${agentId}"`);
|
|
25
25
|
return resolveEffectiveAgentManifest({
|
|
26
26
|
agent,
|
|
27
|
-
presets: config.agents.capabilityPresets
|
|
27
|
+
presets: config.agents.capabilityPresets,
|
|
28
|
+
defaultPresetId: config.agents.defaultPreset
|
|
28
29
|
}).manifest;
|
|
29
30
|
}
|
|
30
31
|
function resolveEffectiveAgentManifestForSession(config, sessionKey) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-profile.js","names":[],"sources":["../../../src/config/agent-profile.ts"],"sourcesContent":["import { resolveEffectiveAgentManifest, type EffectiveAgentManifest } from '../agent-manifest/index.js';\nimport { normalizeAgentId, resolveAgentWorkspaceDir } from '../agent/agent-scope.js';\nimport type { ThinkLevel, ReasoningLevel, VerboseLevel } from '../agent/transcript/thinking-types.js';\nimport { agentExists, getDefaultAgentId } from '../routing/resolve-route.js';\nimport { parseSessionKey } from '../routing/session-key.js';\nimport type { Config } from './schema.js';\n\nexport { resolveAgentWorkspaceDir } from '../agent/agent-scope.js';\n\nexport interface EffectiveAgentTools {\n denied: Set<string>;\n}\n\nexport interface EffectiveAgentProfile {\n agentId: string;\n manifest: EffectiveAgentManifest;\n resolvedWorkspacePath: string;\n primaryModelRef: string | undefined;\n fallbacks: string[];\n thinkingDefault?: ThinkLevel;\n reasoningDefault?: ReasoningLevel;\n verboseDefault?: VerboseLevel;\n systemPromptOverride?: string;\n skillsAllowlist?: string[];\n tools: EffectiveAgentTools;\n params: Record<string, unknown>;\n}\n\nfunction findAgentManifest(config: Config, agentId: string) {\n const id = normalizeAgentId(agentId);\n return config.agents.list.find((agent) => agent.enabled !== false && normalizeAgentId(agent.id) === id);\n}\n\nexport function extractProfileAgentId(sessionKey: string | undefined | null, config: Config): string {\n const parsed = parseSessionKey(sessionKey ?? '');\n if (!parsed) {\n return getDefaultAgentId(config);\n }\n const aid = parsed.agentId;\n if (aid === 'subagent' || aid.startsWith('subagent:')) {\n return getDefaultAgentId(config);\n }\n if (!agentExists(aid, config)) {\n return getDefaultAgentId(config);\n }\n return aid.toLowerCase();\n}\n\nexport function resolveEffectiveAgentManifestForAgent(config: Config, agentId: string): EffectiveAgentManifest {\n const agent = findAgentManifest(config, agentId) ?? findAgentManifest(config, getDefaultAgentId(config));\n if (!agent) {\n throw new Error(`No enabled agent manifest found for \"${agentId}\"`);\n }\n return resolveEffectiveAgentManifest({\n agent,\n presets: config.agents.capabilityPresets,\n }).manifest;\n}\n\nexport function resolveEffectiveAgentManifestForSession(\n config: Config,\n sessionKey: string | undefined | null,\n): EffectiveAgentManifest {\n return resolveEffectiveAgentManifestForAgent(config, extractProfileAgentId(sessionKey, config));\n}\n\nexport function resolveEffectiveAgentProfile(config: Config, agentId: string): EffectiveAgentProfile {\n const manifest = resolveEffectiveAgentManifestForAgent(config, agentId);\n const defaultModel = manifest.models.roles[manifest.models.defaultRole]?.model;\n const deniedTools = Object.entries(manifest.tools.builtin)\n .filter(([, policy]) => policy.mode === 'deny')\n .map(([name]) => name);\n const skillsAllowlist = manifest.skills.mode === 'allowlist' ? [...(manifest.skills.allow ?? [])] : undefined;\n\n return {\n agentId: manifest.id,\n manifest,\n resolvedWorkspacePath: resolveAgentWorkspaceDir(config, manifest.id),\n primaryModelRef: defaultModel?.trim() || undefined,\n fallbacks: [],\n systemPromptOverride: manifest.prompt?.customInstructions,\n skillsAllowlist,\n tools: { denied: new Set(deniedTools) },\n params: {},\n };\n}\n\nexport function resolveEffectiveAgentProfileForSession(\n config: Config,\n sessionKey: string | undefined | null,\n): EffectiveAgentProfile {\n return resolveEffectiveAgentProfile(config, extractProfileAgentId(sessionKey, config));\n}\n"],"mappings":";;;;;;kBACqF;oBAER;kBACjB;AAwB5D,SAAS,kBAAkB,QAAgB,SAAiB;CAC1D,MAAM,KAAK,iBAAiB,QAAQ;AACpC,QAAO,OAAO,OAAO,KAAK,MAAM,UAAU,MAAM,YAAY,SAAS,iBAAiB,MAAM,GAAG,KAAK,GAAG;;AAGzG,SAAgB,sBAAsB,YAAuC,QAAwB;CACnG,MAAM,SAAS,gBAAgB,cAAc,GAAG;AAChD,KAAI,CAAC,OACH,QAAO,kBAAkB,OAAO;CAElC,MAAM,MAAM,OAAO;AACnB,KAAI,QAAQ,cAAc,IAAI,WAAW,YAAY,CACnD,QAAO,kBAAkB,OAAO;AAElC,KAAI,CAAC,YAAY,KAAK,OAAO,CAC3B,QAAO,kBAAkB,OAAO;AAElC,QAAO,IAAI,aAAa;;AAG1B,SAAgB,sCAAsC,QAAgB,SAAyC;CAC7G,MAAM,QAAQ,kBAAkB,QAAQ,QAAQ,IAAI,kBAAkB,QAAQ,kBAAkB,OAAO,CAAC;AACxG,KAAI,CAAC,MACH,OAAM,IAAI,MAAM,wCAAwC,QAAQ,GAAG;AAErE,QAAO,8BAA8B;EACnC;EACA,SAAS,OAAO,OAAO;
|
|
1
|
+
{"version":3,"file":"agent-profile.js","names":[],"sources":["../../../src/config/agent-profile.ts"],"sourcesContent":["import { resolveEffectiveAgentManifest, type EffectiveAgentManifest } from '../agent-manifest/index.js';\nimport { normalizeAgentId, resolveAgentWorkspaceDir } from '../agent/agent-scope.js';\nimport type { ThinkLevel, ReasoningLevel, VerboseLevel } from '../agent/transcript/thinking-types.js';\nimport { agentExists, getDefaultAgentId } from '../routing/resolve-route.js';\nimport { parseSessionKey } from '../routing/session-key.js';\nimport type { Config } from './schema.js';\n\nexport { resolveAgentWorkspaceDir } from '../agent/agent-scope.js';\n\nexport interface EffectiveAgentTools {\n denied: Set<string>;\n}\n\nexport interface EffectiveAgentProfile {\n agentId: string;\n manifest: EffectiveAgentManifest;\n resolvedWorkspacePath: string;\n primaryModelRef: string | undefined;\n fallbacks: string[];\n thinkingDefault?: ThinkLevel;\n reasoningDefault?: ReasoningLevel;\n verboseDefault?: VerboseLevel;\n systemPromptOverride?: string;\n skillsAllowlist?: string[];\n tools: EffectiveAgentTools;\n params: Record<string, unknown>;\n}\n\nfunction findAgentManifest(config: Config, agentId: string) {\n const id = normalizeAgentId(agentId);\n return config.agents.list.find((agent) => agent.enabled !== false && normalizeAgentId(agent.id) === id);\n}\n\nexport function extractProfileAgentId(sessionKey: string | undefined | null, config: Config): string {\n const parsed = parseSessionKey(sessionKey ?? '');\n if (!parsed) {\n return getDefaultAgentId(config);\n }\n const aid = parsed.agentId;\n if (aid === 'subagent' || aid.startsWith('subagent:')) {\n return getDefaultAgentId(config);\n }\n if (!agentExists(aid, config)) {\n return getDefaultAgentId(config);\n }\n return aid.toLowerCase();\n}\n\nexport function resolveEffectiveAgentManifestForAgent(config: Config, agentId: string): EffectiveAgentManifest {\n const agent = findAgentManifest(config, agentId) ?? findAgentManifest(config, getDefaultAgentId(config));\n if (!agent) {\n throw new Error(`No enabled agent manifest found for \"${agentId}\"`);\n }\n return resolveEffectiveAgentManifest({\n agent,\n presets: config.agents.capabilityPresets,\n defaultPresetId: config.agents.defaultPreset,\n }).manifest;\n}\n\nexport function resolveEffectiveAgentManifestForSession(\n config: Config,\n sessionKey: string | undefined | null,\n): EffectiveAgentManifest {\n return resolveEffectiveAgentManifestForAgent(config, extractProfileAgentId(sessionKey, config));\n}\n\nexport function resolveEffectiveAgentProfile(config: Config, agentId: string): EffectiveAgentProfile {\n const manifest = resolveEffectiveAgentManifestForAgent(config, agentId);\n const defaultModel = manifest.models.roles[manifest.models.defaultRole]?.model;\n const deniedTools = Object.entries(manifest.tools.builtin)\n .filter(([, policy]) => policy.mode === 'deny')\n .map(([name]) => name);\n const skillsAllowlist = manifest.skills.mode === 'allowlist' ? [...(manifest.skills.allow ?? [])] : undefined;\n\n return {\n agentId: manifest.id,\n manifest,\n resolvedWorkspacePath: resolveAgentWorkspaceDir(config, manifest.id),\n primaryModelRef: defaultModel?.trim() || undefined,\n fallbacks: [],\n systemPromptOverride: manifest.prompt?.customInstructions,\n skillsAllowlist,\n tools: { denied: new Set(deniedTools) },\n params: {},\n };\n}\n\nexport function resolveEffectiveAgentProfileForSession(\n config: Config,\n sessionKey: string | undefined | null,\n): EffectiveAgentProfile {\n return resolveEffectiveAgentProfile(config, extractProfileAgentId(sessionKey, config));\n}\n"],"mappings":";;;;;;kBACqF;oBAER;kBACjB;AAwB5D,SAAS,kBAAkB,QAAgB,SAAiB;CAC1D,MAAM,KAAK,iBAAiB,QAAQ;AACpC,QAAO,OAAO,OAAO,KAAK,MAAM,UAAU,MAAM,YAAY,SAAS,iBAAiB,MAAM,GAAG,KAAK,GAAG;;AAGzG,SAAgB,sBAAsB,YAAuC,QAAwB;CACnG,MAAM,SAAS,gBAAgB,cAAc,GAAG;AAChD,KAAI,CAAC,OACH,QAAO,kBAAkB,OAAO;CAElC,MAAM,MAAM,OAAO;AACnB,KAAI,QAAQ,cAAc,IAAI,WAAW,YAAY,CACnD,QAAO,kBAAkB,OAAO;AAElC,KAAI,CAAC,YAAY,KAAK,OAAO,CAC3B,QAAO,kBAAkB,OAAO;AAElC,QAAO,IAAI,aAAa;;AAG1B,SAAgB,sCAAsC,QAAgB,SAAyC;CAC7G,MAAM,QAAQ,kBAAkB,QAAQ,QAAQ,IAAI,kBAAkB,QAAQ,kBAAkB,OAAO,CAAC;AACxG,KAAI,CAAC,MACH,OAAM,IAAI,MAAM,wCAAwC,QAAQ,GAAG;AAErE,QAAO,8BAA8B;EACnC;EACA,SAAS,OAAO,OAAO;EACvB,iBAAiB,OAAO,OAAO;EAChC,CAAC,CAAC;;AAGL,SAAgB,wCACd,QACA,YACwB;AACxB,QAAO,sCAAsC,QAAQ,sBAAsB,YAAY,OAAO,CAAC;;AAGjG,SAAgB,6BAA6B,QAAgB,SAAwC;CACnG,MAAM,WAAW,sCAAsC,QAAQ,QAAQ;CACvE,MAAM,eAAe,SAAS,OAAO,MAAM,SAAS,OAAO,cAAc;CACzE,MAAM,cAAc,OAAO,QAAQ,SAAS,MAAM,QAAQ,CACvD,QAAQ,GAAG,YAAY,OAAO,SAAS,OAAO,CAC9C,KAAK,CAAC,UAAU,KAAK;CACxB,MAAM,kBAAkB,SAAS,OAAO,SAAS,cAAc,CAAC,GAAI,SAAS,OAAO,SAAS,EAAE,CAAE,GAAG,KAAA;AAEpG,QAAO;EACL,SAAS,SAAS;EAClB;EACA,uBAAuB,yBAAyB,QAAQ,SAAS,GAAG;EACpE,iBAAiB,cAAc,MAAM,IAAI,KAAA;EACzC,WAAW,EAAE;EACb,sBAAsB,SAAS,QAAQ;EACvC;EACA,OAAO,EAAE,QAAQ,IAAI,IAAI,YAAY,EAAE;EACvC,QAAQ,EAAE;EACX;;AAGH,SAAgB,uCACd,QACA,YACuB;AACvB,QAAO,6BAA6B,QAAQ,sBAAsB,YAAY,OAAO,CAAC"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { init_schema, parseModelRef } from "./schema.js";
|
|
2
|
-
import {
|
|
2
|
+
import { resolveEffectiveAgentManifestForAgent } from "./agent-profile.js";
|
|
3
3
|
//#region src/config/agent-typed-models.ts
|
|
4
4
|
init_schema();
|
|
5
|
-
init_agent_scope();
|
|
6
5
|
function rolesToEntries(roles) {
|
|
7
6
|
return Object.entries(roles ?? {}).map(([id, role]) => ({
|
|
8
7
|
id,
|
|
@@ -11,9 +10,8 @@ function rolesToEntries(roles) {
|
|
|
11
10
|
}
|
|
12
11
|
function resolveEffectiveTypedModels(config, agentId) {
|
|
13
12
|
const out = /* @__PURE__ */ new Map();
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
for (const modelRole of rolesToEntries(entry?.models?.roles)) out.set(modelRole.id, modelRole);
|
|
13
|
+
const manifest = resolveEffectiveAgentManifestForAgent(config, agentId);
|
|
14
|
+
for (const modelRole of rolesToEntries(manifest.models.roles)) out.set(modelRole.id, modelRole);
|
|
17
15
|
return out;
|
|
18
16
|
}
|
|
19
17
|
/** Resolve a typed model id to `provider/model`, or undefined when not configured. */
|