@geminixiang/mikan 1.0.0-beta.9 → 1.0.0-beta.91
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +342 -424
- package/README.md +102 -42
- package/dist/adapters/commands/admin.d.ts.map +1 -0
- package/dist/adapters/commands/admin.js +33 -0
- package/dist/adapters/commands/admin.js.map +1 -0
- package/dist/adapters/commands/auto-reply.d.ts +5 -0
- package/dist/adapters/commands/auto-reply.d.ts.map +1 -0
- package/dist/adapters/commands/auto-reply.js +47 -0
- package/dist/adapters/commands/auto-reply.js.map +1 -0
- package/dist/adapters/commands/login.d.ts +6 -0
- package/dist/adapters/commands/login.d.ts.map +1 -0
- package/dist/adapters/commands/login.js +158 -0
- package/dist/adapters/commands/login.js.map +1 -0
- package/dist/adapters/commands/manifest.d.ts +17 -0
- package/dist/adapters/commands/manifest.d.ts.map +1 -0
- package/dist/adapters/commands/manifest.js +121 -0
- package/dist/adapters/commands/manifest.js.map +1 -0
- package/dist/adapters/commands/model.d.ts +9 -0
- package/dist/adapters/commands/model.d.ts.map +1 -0
- package/dist/adapters/commands/model.js +136 -0
- package/dist/adapters/commands/model.js.map +1 -0
- package/dist/adapters/commands/new.d.ts.map +1 -0
- package/dist/adapters/commands/new.js +39 -0
- package/dist/adapters/commands/new.js.map +1 -0
- package/dist/adapters/commands/registry.d.ts +4 -0
- package/dist/adapters/commands/registry.d.ts.map +1 -0
- package/dist/adapters/commands/registry.js +35 -0
- package/dist/adapters/commands/registry.js.map +1 -0
- package/dist/adapters/commands/sandbox.d.ts +6 -0
- package/dist/adapters/commands/sandbox.d.ts.map +1 -0
- package/dist/adapters/commands/sandbox.js +125 -0
- package/dist/adapters/commands/sandbox.js.map +1 -0
- package/dist/adapters/commands/session-view.d.ts.map +1 -0
- package/dist/adapters/commands/session-view.js +46 -0
- package/dist/adapters/commands/session-view.js.map +1 -0
- package/dist/adapters/commands/types.d.ts +105 -0
- package/dist/adapters/commands/types.d.ts.map +1 -0
- package/dist/adapters/commands/types.js.map +1 -0
- package/dist/adapters/commands/utils.d.ts +11 -0
- package/dist/adapters/commands/utils.d.ts.map +1 -0
- package/dist/adapters/commands/utils.js +43 -0
- package/dist/adapters/commands/utils.js.map +1 -0
- package/dist/adapters/discord/bot.d.ts +14 -18
- package/dist/adapters/discord/bot.d.ts.map +1 -1
- package/dist/adapters/discord/bot.js +234 -303
- package/dist/adapters/discord/bot.js.map +1 -1
- package/dist/adapters/discord/components.d.ts +4 -0
- package/dist/adapters/discord/components.d.ts.map +1 -0
- package/dist/adapters/discord/components.js +9 -0
- package/dist/adapters/discord/components.js.map +1 -0
- package/dist/adapters/discord/context.d.ts +3 -7
- package/dist/adapters/discord/context.d.ts.map +1 -1
- package/dist/adapters/discord/context.js +57 -219
- package/dist/adapters/discord/context.js.map +1 -1
- package/dist/adapters/discord/format.d.ts +2 -0
- package/dist/adapters/discord/format.d.ts.map +1 -0
- package/dist/adapters/discord/format.js +47 -0
- package/dist/adapters/discord/format.js.map +1 -0
- package/dist/adapters/discord/types.d.ts +91 -1
- package/dist/adapters/discord/types.d.ts.map +1 -1
- package/dist/adapters/discord/types.js.map +1 -1
- package/dist/adapters/github/activity.d.ts +3 -0
- package/dist/adapters/github/activity.d.ts.map +1 -0
- package/dist/adapters/github/activity.js +148 -0
- package/dist/adapters/github/activity.js.map +1 -0
- package/dist/adapters/github/bot.d.ts +24 -37
- package/dist/adapters/github/bot.d.ts.map +1 -1
- package/dist/adapters/github/bot.js +209 -397
- package/dist/adapters/github/bot.js.map +1 -1
- package/dist/adapters/github/client.d.ts +32 -49
- package/dist/adapters/github/client.d.ts.map +1 -1
- package/dist/adapters/github/client.js +108 -118
- package/dist/adapters/github/client.js.map +1 -1
- package/dist/adapters/github/context.d.ts +3 -8
- package/dist/adapters/github/context.d.ts.map +1 -1
- package/dist/adapters/github/context.js +74 -138
- package/dist/adapters/github/context.js.map +1 -1
- package/dist/adapters/github/github-ops.d.ts +14 -0
- package/dist/adapters/github/github-ops.d.ts.map +1 -0
- package/dist/adapters/github/github-ops.js +218 -0
- package/dist/adapters/github/github-ops.js.map +1 -0
- package/dist/adapters/github/ids.d.ts +2 -23
- package/dist/adapters/github/ids.d.ts.map +1 -1
- package/dist/adapters/github/ids.js +6 -36
- package/dist/adapters/github/ids.js.map +1 -1
- package/dist/adapters/github/policy.d.ts +19 -0
- package/dist/adapters/github/policy.d.ts.map +1 -0
- package/dist/adapters/github/policy.js +79 -0
- package/dist/adapters/github/policy.js.map +1 -0
- package/dist/adapters/github/tool-pack.d.ts +4 -0
- package/dist/adapters/github/tool-pack.d.ts.map +1 -0
- package/dist/adapters/github/tool-pack.js +40 -0
- package/dist/adapters/github/tool-pack.js.map +1 -0
- package/dist/adapters/github/tools/checks.d.ts +14 -0
- package/dist/adapters/github/tools/checks.d.ts.map +1 -0
- package/dist/adapters/github/tools/checks.js +78 -0
- package/dist/adapters/github/tools/checks.js.map +1 -0
- package/dist/adapters/github/tools/issue.d.ts +18 -0
- package/dist/adapters/github/tools/issue.d.ts.map +1 -0
- package/dist/adapters/github/tools/issue.js +44 -0
- package/dist/adapters/github/tools/issue.js.map +1 -0
- package/dist/adapters/github/tools/pr.d.ts +17 -0
- package/dist/adapters/github/tools/pr.d.ts.map +1 -0
- package/dist/adapters/github/tools/pr.js +40 -0
- package/dist/adapters/github/tools/pr.js.map +1 -0
- package/dist/adapters/github/tools/read.d.ts +17 -0
- package/dist/adapters/github/tools/read.d.ts.map +1 -0
- package/dist/adapters/github/tools/read.js +134 -0
- package/dist/adapters/github/tools/read.js.map +1 -0
- package/dist/adapters/github/tools/review-reply.d.ts +14 -0
- package/dist/adapters/github/tools/review-reply.d.ts.map +1 -0
- package/dist/adapters/github/tools/review-reply.js +34 -0
- package/dist/adapters/github/tools/review-reply.js.map +1 -0
- package/dist/adapters/github/types.d.ts +200 -57
- package/dist/adapters/github/types.d.ts.map +1 -1
- package/dist/adapters/github/types.js.map +1 -1
- package/dist/adapters/github/webhook.d.ts +7 -0
- package/dist/adapters/github/webhook.d.ts.map +1 -0
- package/dist/adapters/github/webhook.js +104 -0
- package/dist/adapters/github/webhook.js.map +1 -0
- package/dist/adapters/intake.d.ts +4 -10
- package/dist/adapters/intake.d.ts.map +1 -1
- package/dist/adapters/intake.js +85 -32
- package/dist/adapters/intake.js.map +1 -1
- package/dist/adapters/markdown-tables.d.ts +8 -0
- package/dist/adapters/markdown-tables.d.ts.map +1 -0
- package/dist/adapters/markdown-tables.js +111 -0
- package/dist/adapters/markdown-tables.js.map +1 -0
- package/dist/adapters/messages.d.ts +13 -0
- package/dist/adapters/messages.d.ts.map +1 -0
- package/dist/adapters/messages.js +39 -0
- package/dist/adapters/messages.js.map +1 -0
- package/dist/adapters/progressive-renderer.d.ts +7 -0
- package/dist/adapters/progressive-renderer.d.ts.map +1 -0
- package/dist/adapters/progressive-renderer.js +426 -0
- package/dist/adapters/progressive-renderer.js.map +1 -0
- package/dist/adapters/shared.d.ts +27 -53
- package/dist/adapters/shared.d.ts.map +1 -1
- package/dist/adapters/shared.js +167 -91
- package/dist/adapters/shared.js.map +1 -1
- package/dist/adapters/slack/assistant.d.ts +21 -0
- package/dist/adapters/slack/assistant.d.ts.map +1 -0
- package/dist/adapters/slack/assistant.js +103 -0
- package/dist/adapters/slack/assistant.js.map +1 -0
- package/dist/adapters/slack/auto-reply-context.d.ts +14 -0
- package/dist/adapters/slack/auto-reply-context.d.ts.map +1 -0
- package/dist/adapters/slack/auto-reply-context.js +21 -0
- package/dist/adapters/slack/auto-reply-context.js.map +1 -0
- package/dist/adapters/slack/blocks.d.ts +5 -0
- package/dist/adapters/slack/blocks.d.ts.map +1 -1
- package/dist/adapters/slack/blocks.js +144 -145
- package/dist/adapters/slack/blocks.js.map +1 -1
- package/dist/adapters/slack/bot.d.ts +60 -40
- package/dist/adapters/slack/bot.d.ts.map +1 -1
- package/dist/adapters/slack/bot.js +968 -588
- package/dist/adapters/slack/bot.js.map +1 -1
- package/dist/adapters/slack/context.d.ts +3 -9
- package/dist/adapters/slack/context.d.ts.map +1 -1
- package/dist/adapters/slack/context.js +8 -17
- package/dist/adapters/slack/context.js.map +1 -1
- package/dist/adapters/slack/jev-context.d.ts +17 -0
- package/dist/adapters/slack/jev-context.d.ts.map +1 -0
- package/dist/adapters/slack/jev-context.js +57 -0
- package/dist/adapters/slack/jev-context.js.map +1 -0
- package/dist/adapters/slack/markdown.d.ts +2 -0
- package/dist/adapters/slack/markdown.d.ts.map +1 -0
- package/dist/adapters/slack/markdown.js +43 -0
- package/dist/adapters/slack/markdown.js.map +1 -0
- package/dist/adapters/slack/persona.d.ts +6 -0
- package/dist/adapters/slack/persona.d.ts.map +1 -0
- package/dist/adapters/slack/persona.js +13 -0
- package/dist/adapters/slack/persona.js.map +1 -0
- package/dist/adapters/slack/response-lifecycle.d.ts +3 -4
- package/dist/adapters/slack/response-lifecycle.d.ts.map +1 -1
- package/dist/adapters/slack/response-lifecycle.js +222 -348
- package/dist/adapters/slack/response-lifecycle.js.map +1 -1
- package/dist/adapters/slack/session.d.ts +3 -2
- package/dist/adapters/slack/session.d.ts.map +1 -1
- package/dist/adapters/slack/session.js +9 -13
- package/dist/adapters/slack/session.js.map +1 -1
- package/dist/adapters/slack/stream-limits.d.ts +10 -0
- package/dist/adapters/slack/stream-limits.d.ts.map +1 -0
- package/dist/adapters/slack/stream-limits.js +22 -0
- package/dist/adapters/slack/stream-limits.js.map +1 -0
- package/dist/adapters/slack/task-intent.d.ts +19 -0
- package/dist/adapters/slack/task-intent.d.ts.map +1 -0
- package/dist/adapters/slack/task-intent.js +65 -0
- package/dist/adapters/slack/task-intent.js.map +1 -0
- package/dist/adapters/slack/task-status.d.ts +7 -0
- package/dist/adapters/slack/task-status.d.ts.map +1 -0
- package/dist/adapters/slack/task-status.js +96 -0
- package/dist/adapters/slack/task-status.js.map +1 -0
- package/dist/adapters/slack/tool-pack.d.ts +4 -0
- package/dist/adapters/slack/tool-pack.d.ts.map +1 -0
- package/dist/adapters/slack/tool-pack.js +40 -0
- package/dist/adapters/slack/tool-pack.js.map +1 -0
- package/dist/adapters/slack/tools/blockkit.d.ts +17 -0
- package/dist/adapters/slack/tools/blockkit.d.ts.map +1 -0
- package/dist/adapters/slack/tools/blockkit.js +98 -0
- package/dist/adapters/slack/tools/blockkit.js.map +1 -0
- package/dist/adapters/slack/types.d.ts +91 -5
- package/dist/adapters/slack/types.d.ts.map +1 -1
- package/dist/adapters/slack/types.js.map +1 -1
- package/dist/adapters/slack/update-diagnostics.d.ts +13 -0
- package/dist/adapters/slack/update-diagnostics.d.ts.map +1 -0
- package/dist/adapters/slack/update-diagnostics.js +128 -0
- package/dist/adapters/slack/update-diagnostics.js.map +1 -0
- package/dist/adapters/telegram/bot.d.ts +12 -19
- package/dist/adapters/telegram/bot.d.ts.map +1 -1
- package/dist/adapters/telegram/bot.js +114 -239
- package/dist/adapters/telegram/bot.js.map +1 -1
- package/dist/adapters/telegram/context.d.ts +3 -7
- package/dist/adapters/telegram/context.d.ts.map +1 -1
- package/dist/adapters/telegram/context.js +49 -191
- package/dist/adapters/telegram/context.js.map +1 -1
- package/dist/adapters/telegram/types.d.ts +24 -1
- package/dist/adapters/telegram/types.d.ts.map +1 -1
- package/dist/adapters/telegram/types.js.map +1 -1
- package/dist/adapters/types.d.ts +92 -17
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/adapters/types.js.map +1 -1
- package/dist/adapters/web/admin/client-assets.d.ts +4 -0
- package/dist/adapters/web/admin/client-assets.d.ts.map +1 -0
- package/dist/adapters/web/admin/client-assets.js +1766 -0
- package/dist/adapters/web/admin/client-assets.js.map +1 -0
- package/dist/adapters/web/admin/portal.d.ts +26 -0
- package/dist/adapters/web/admin/portal.d.ts.map +1 -0
- package/dist/adapters/web/admin/portal.js +1490 -0
- package/dist/adapters/web/admin/portal.js.map +1 -0
- package/dist/adapters/web/admin/provider-models.d.ts +10 -0
- package/dist/adapters/web/admin/provider-models.d.ts.map +1 -0
- package/dist/adapters/web/admin/provider-models.js +103 -0
- package/dist/adapters/web/admin/provider-models.js.map +1 -0
- package/dist/adapters/web/admin/types.d.ts +54 -0
- package/dist/adapters/web/admin/types.d.ts.map +1 -0
- package/dist/adapters/web/admin/types.js.map +1 -0
- package/dist/adapters/web/login/oauth.d.ts +4 -0
- package/dist/adapters/web/login/oauth.d.ts.map +1 -0
- package/dist/adapters/web/login/oauth.js +219 -0
- package/dist/adapters/web/login/oauth.js.map +1 -0
- package/dist/adapters/web/login/portal.d.ts +10 -0
- package/dist/adapters/web/login/portal.d.ts.map +1 -0
- package/dist/adapters/web/login/portal.js +1336 -0
- package/dist/adapters/web/login/portal.js.map +1 -0
- package/dist/adapters/web/login/types.d.ts +34 -0
- package/dist/adapters/web/login/types.d.ts.map +1 -0
- package/dist/adapters/web/login/types.js.map +1 -0
- package/dist/adapters/web/portal-shell.d.ts +9 -0
- package/dist/adapters/web/portal-shell.d.ts.map +1 -0
- package/dist/adapters/web/portal-shell.js +428 -0
- package/dist/adapters/web/portal-shell.js.map +1 -0
- package/dist/adapters/web/server.d.ts +35 -0
- package/dist/adapters/web/server.d.ts.map +1 -0
- package/dist/adapters/web/server.js +80 -0
- package/dist/adapters/web/server.js.map +1 -0
- package/dist/adapters/web/session-view/portal.d.ts +19 -0
- package/dist/adapters/web/session-view/portal.d.ts.map +1 -0
- package/dist/adapters/web/session-view/portal.js +1833 -0
- package/dist/adapters/web/session-view/portal.js.map +1 -0
- package/dist/adapters/web/session-view/types.d.ts +45 -0
- package/dist/adapters/web/session-view/types.d.ts.map +1 -0
- package/dist/adapters/web/session-view/types.js.map +1 -0
- package/dist/adapters/web/token-store.d.ts +10 -0
- package/dist/adapters/web/token-store.d.ts.map +1 -0
- package/dist/adapters/web/token-store.js +42 -0
- package/dist/adapters/web/token-store.js.map +1 -0
- package/dist/adapters/web/types.d.ts.map +1 -0
- package/dist/adapters/web/types.js.map +1 -0
- package/dist/cli/arg-grammar.d.ts +8 -0
- package/dist/cli/arg-grammar.d.ts.map +1 -0
- package/dist/cli/arg-grammar.js +47 -0
- package/dist/cli/arg-grammar.js.map +1 -0
- package/dist/cli/boot.d.ts +4 -0
- package/dist/cli/boot.d.ts.map +1 -0
- package/dist/cli/boot.js +79 -0
- package/dist/cli/boot.js.map +1 -0
- package/dist/cli/download.d.ts.map +1 -0
- package/dist/cli/download.js +84 -0
- package/dist/cli/download.js.map +1 -0
- package/dist/cli/migrate.d.ts +3 -0
- package/dist/cli/migrate.d.ts.map +1 -0
- package/dist/cli/migrate.js +74 -0
- package/dist/cli/migrate.js.map +1 -0
- package/dist/cli/office.d.ts +2 -0
- package/dist/cli/office.d.ts.map +1 -0
- package/dist/cli/office.js +30 -0
- package/dist/cli/office.js.map +1 -0
- package/dist/cli/onboard.d.ts +7 -0
- package/dist/cli/onboard.d.ts.map +1 -0
- package/dist/cli/onboard.js +192 -0
- package/dist/cli/onboard.js.map +1 -0
- package/dist/cli/process-lifecycle.d.ts +14 -0
- package/dist/cli/process-lifecycle.d.ts.map +1 -0
- package/dist/cli/process-lifecycle.js +61 -0
- package/dist/cli/process-lifecycle.js.map +1 -0
- package/dist/cli/types.d.ts +20 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/env-manifest.d.ts +14 -0
- package/dist/env-manifest.d.ts.map +1 -0
- package/dist/env-manifest.js +255 -0
- package/dist/env-manifest.js.map +1 -0
- package/dist/events/index.d.ts +105 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +252 -0
- package/dist/events/index.js.map +1 -0
- package/dist/events/scheduler.d.ts +24 -0
- package/dist/events/scheduler.d.ts.map +1 -0
- package/dist/events/scheduler.js +221 -0
- package/dist/events/scheduler.js.map +1 -0
- package/dist/file-guards.d.ts +20 -0
- package/dist/file-guards.d.ts.map +1 -0
- package/dist/file-guards.js +166 -0
- package/dist/file-guards.js.map +1 -0
- package/dist/harness/budget-stop.d.ts +3 -0
- package/dist/harness/budget-stop.d.ts.map +1 -0
- package/dist/harness/budget-stop.js +36 -0
- package/dist/harness/budget-stop.js.map +1 -0
- package/dist/harness/execution-env.d.ts +4 -0
- package/dist/harness/execution-env.d.ts.map +1 -0
- package/dist/harness/execution-env.js +245 -0
- package/dist/harness/execution-env.js.map +1 -0
- package/dist/harness/execution-resolver.d.ts +23 -0
- package/dist/harness/execution-resolver.d.ts.map +1 -0
- package/dist/harness/execution-resolver.js +152 -0
- package/dist/harness/execution-resolver.js.map +1 -0
- package/dist/harness/http.d.ts +0 -12
- package/dist/harness/http.d.ts.map +1 -1
- package/dist/harness/http.js +0 -34
- package/dist/harness/http.js.map +1 -1
- package/dist/harness/index.d.ts +18 -17
- package/dist/harness/index.d.ts.map +1 -1
- package/dist/harness/index.js +11 -15
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/jev.d.ts +67 -0
- package/dist/harness/jev.d.ts.map +1 -0
- package/dist/harness/jev.js +135 -0
- package/dist/harness/jev.js.map +1 -0
- package/dist/harness/loop-guard.d.ts +10 -0
- package/dist/harness/loop-guard.d.ts.map +1 -0
- package/dist/harness/loop-guard.js +111 -0
- package/dist/harness/loop-guard.js.map +1 -0
- package/dist/harness/mcp-result.d.ts +21 -0
- package/dist/harness/mcp-result.d.ts.map +1 -0
- package/dist/harness/mcp-result.js +204 -0
- package/dist/harness/mcp-result.js.map +1 -0
- package/dist/harness/mcp.d.ts +17 -0
- package/dist/harness/mcp.d.ts.map +1 -0
- package/dist/harness/mcp.js +339 -0
- package/dist/harness/mcp.js.map +1 -0
- package/dist/harness/models.d.ts +2 -19
- package/dist/harness/models.d.ts.map +1 -1
- package/dist/harness/models.js +43 -95
- package/dist/harness/models.js.map +1 -1
- package/dist/harness/open-connector.d.ts +3 -0
- package/dist/harness/open-connector.d.ts.map +1 -0
- package/dist/harness/open-connector.js +106 -0
- package/dist/harness/open-connector.js.map +1 -0
- package/dist/harness/presenter.d.ts +11 -0
- package/dist/harness/presenter.d.ts.map +1 -0
- package/dist/harness/presenter.js +867 -0
- package/dist/harness/presenter.js.map +1 -0
- package/dist/harness/prompt.d.ts +17 -0
- package/dist/harness/prompt.d.ts.map +1 -0
- package/dist/harness/prompt.js +348 -0
- package/dist/harness/prompt.js.map +1 -0
- package/dist/harness/run-events.d.ts +10 -0
- package/dist/harness/run-events.d.ts.map +1 -0
- package/dist/harness/run-events.js +126 -0
- package/dist/harness/run-events.js.map +1 -0
- package/dist/harness/runner.d.ts +2 -123
- package/dist/harness/runner.d.ts.map +1 -1
- package/dist/harness/runner.js +570 -414
- package/dist/harness/runner.js.map +1 -1
- package/dist/harness/session.d.ts +102 -0
- package/dist/harness/session.d.ts.map +1 -0
- package/dist/harness/session.js +725 -0
- package/dist/harness/session.js.map +1 -0
- package/dist/harness/skills.d.ts +7 -41
- package/dist/harness/skills.d.ts.map +1 -1
- package/dist/harness/skills.js +120 -69
- package/dist/harness/skills.js.map +1 -1
- package/dist/harness/subagent-profiles.d.ts +3 -0
- package/dist/harness/subagent-profiles.d.ts.map +1 -0
- package/dist/harness/subagent-profiles.js +260 -0
- package/dist/harness/subagent-profiles.js.map +1 -0
- package/dist/harness/subagent.d.ts +39 -0
- package/dist/harness/subagent.d.ts.map +1 -0
- package/dist/harness/subagent.js +613 -0
- package/dist/harness/subagent.js.map +1 -0
- package/dist/harness/tool-args.d.ts +2 -0
- package/dist/harness/tool-args.d.ts.map +1 -0
- package/dist/harness/tool-args.js +20 -0
- package/dist/harness/tool-args.js.map +1 -0
- package/dist/harness/tools/attach.d.ts +13 -0
- package/dist/harness/tools/attach.d.ts.map +1 -0
- package/dist/harness/tools/attach.js +39 -0
- package/dist/harness/tools/attach.js.map +1 -0
- package/dist/harness/tools/codemode.d.ts +5 -0
- package/dist/harness/tools/codemode.d.ts.map +1 -0
- package/dist/harness/tools/codemode.js +229 -0
- package/dist/harness/tools/codemode.js.map +1 -0
- package/dist/harness/tools/event.d.ts +28 -0
- package/dist/harness/tools/event.d.ts.map +1 -0
- package/dist/harness/tools/event.js +183 -0
- package/dist/harness/tools/event.js.map +1 -0
- package/dist/harness/tools/generate-image.d.ts +20 -0
- package/dist/harness/tools/generate-image.d.ts.map +1 -0
- package/dist/harness/tools/generate-image.js +82 -0
- package/dist/harness/tools/generate-image.js.map +1 -0
- package/dist/harness/tools/history.d.ts +20 -0
- package/dist/harness/tools/history.d.ts.map +1 -0
- package/dist/harness/tools/history.js +293 -0
- package/dist/harness/tools/history.js.map +1 -0
- package/dist/harness/tools/host-fn-tool.d.ts +14 -0
- package/dist/harness/tools/host-fn-tool.d.ts.map +1 -0
- package/dist/harness/tools/host-fn-tool.js +39 -0
- package/dist/harness/tools/host-fn-tool.js.map +1 -0
- package/dist/harness/tools/index.d.ts +34 -0
- package/dist/harness/tools/index.d.ts.map +1 -0
- package/dist/harness/tools/index.js +49 -0
- package/dist/harness/tools/index.js.map +1 -0
- package/dist/harness/tools/jev-browser.d.ts +41 -0
- package/dist/harness/tools/jev-browser.d.ts.map +1 -0
- package/dist/harness/tools/jev-browser.js +570 -0
- package/dist/harness/tools/jev-browser.js.map +1 -0
- package/dist/harness/tools/jev.d.ts +15 -0
- package/dist/harness/tools/jev.d.ts.map +1 -0
- package/dist/harness/tools/jev.js +98 -0
- package/dist/harness/tools/jev.js.map +1 -0
- package/dist/harness/tools/pi-tools.d.ts +8 -0
- package/dist/harness/tools/pi-tools.d.ts.map +1 -0
- package/dist/harness/tools/pi-tools.js +83 -0
- package/dist/harness/tools/pi-tools.js.map +1 -0
- package/dist/harness/tools/react.d.ts +12 -0
- package/dist/harness/tools/react.d.ts.map +1 -0
- package/dist/harness/tools/react.js +25 -0
- package/dist/harness/tools/react.js.map +1 -0
- package/dist/harness/tools/sandbox.d.ts +24 -0
- package/dist/harness/tools/sandbox.d.ts.map +1 -0
- package/dist/harness/tools/sandbox.js +79 -0
- package/dist/harness/tools/sandbox.js.map +1 -0
- package/dist/harness/tools/secret-redaction.d.ts +9 -0
- package/dist/harness/tools/secret-redaction.d.ts.map +1 -0
- package/dist/harness/tools/secret-redaction.js +88 -0
- package/dist/harness/tools/secret-redaction.js.map +1 -0
- package/dist/harness/tools/subagent.d.ts +51 -0
- package/dist/harness/tools/subagent.d.ts.map +1 -0
- package/dist/harness/tools/subagent.js +581 -0
- package/dist/harness/tools/subagent.js.map +1 -0
- package/dist/harness/tools/task.d.ts +22 -0
- package/dist/harness/tools/task.d.ts.map +1 -0
- package/dist/harness/tools/task.js +80 -0
- package/dist/harness/tools/task.js.map +1 -0
- package/dist/harness/tools/tool-search.d.ts +6 -0
- package/dist/harness/tools/tool-search.d.ts.map +1 -0
- package/dist/harness/tools/tool-search.js +89 -0
- package/dist/harness/tools/tool-search.js.map +1 -0
- package/dist/harness/tools/types.d.ts +14 -0
- package/dist/harness/tools/types.d.ts.map +1 -0
- package/dist/harness/tools/types.js.map +1 -0
- package/dist/harness/types.d.ts +488 -29
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/index.d.ts +31 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -7
- package/dist/index.js.map +1 -1
- package/dist/log.d.ts +0 -4
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +3 -28
- package/dist/log.js.map +1 -1
- package/dist/main.js +282 -258
- package/dist/main.js.map +1 -1
- package/dist/memory-capture/index.d.ts +15 -0
- package/dist/memory-capture/index.d.ts.map +1 -0
- package/dist/memory-capture/index.js +198 -0
- package/dist/memory-capture/index.js.map +1 -0
- package/dist/memory-capture/types.d.ts +27 -0
- package/dist/memory-capture/types.d.ts.map +1 -0
- package/dist/memory-capture/types.js +2 -0
- package/dist/memory-capture/types.js.map +1 -0
- package/dist/migrations/actor-vaults.d.ts +3 -0
- package/dist/migrations/actor-vaults.d.ts.map +1 -0
- package/dist/migrations/actor-vaults.js +43 -0
- package/dist/migrations/actor-vaults.js.map +1 -0
- package/dist/migrations/conversation-settings.d.ts +3 -0
- package/dist/migrations/conversation-settings.d.ts.map +1 -0
- package/dist/migrations/conversation-settings.js +31 -0
- package/dist/migrations/conversation-settings.js.map +1 -0
- package/dist/migrations/dream-checkpoints.d.ts +3 -0
- package/dist/migrations/dream-checkpoints.d.ts.map +1 -0
- package/dist/migrations/dream-checkpoints.js +23 -0
- package/dist/migrations/dream-checkpoints.js.map +1 -0
- package/dist/migrations/index.d.ts +14 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +105 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/migrations/models-json.d.ts +3 -0
- package/dist/migrations/models-json.d.ts.map +1 -0
- package/dist/migrations/models-json.js +18 -0
- package/dist/migrations/models-json.js.map +1 -0
- package/dist/migrations/office-layout.d.ts +4 -0
- package/dist/migrations/office-layout.d.ts.map +1 -0
- package/dist/migrations/office-layout.js +94 -0
- package/dist/migrations/office-layout.js.map +1 -0
- package/dist/migrations/office-sessions.d.ts +3 -0
- package/dist/migrations/office-sessions.d.ts.map +1 -0
- package/dist/migrations/office-sessions.js +81 -0
- package/dist/migrations/office-sessions.js.map +1 -0
- package/dist/migrations/private-office-dirs.d.ts +3 -0
- package/dist/migrations/private-office-dirs.d.ts.map +1 -0
- package/dist/migrations/private-office-dirs.js +24 -0
- package/dist/migrations/private-office-dirs.js.map +1 -0
- package/dist/migrations/sandbox-containers.d.ts +3 -0
- package/dist/migrations/sandbox-containers.d.ts.map +1 -0
- package/dist/migrations/sandbox-containers.js +36 -0
- package/dist/migrations/sandbox-containers.js.map +1 -0
- package/dist/migrations/session-files.d.ts +28 -0
- package/dist/migrations/session-files.d.ts.map +1 -0
- package/dist/migrations/session-files.js +80 -0
- package/dist/migrations/session-files.js.map +1 -0
- package/dist/migrations/session-v4.d.ts +77 -0
- package/dist/migrations/session-v4.d.ts.map +1 -0
- package/dist/migrations/session-v4.js +177 -0
- package/dist/migrations/session-v4.js.map +1 -0
- package/dist/migrations/sessions-sqlite.d.ts +3 -0
- package/dist/migrations/sessions-sqlite.d.ts.map +1 -0
- package/dist/migrations/sessions-sqlite.js +215 -0
- package/dist/migrations/sessions-sqlite.js.map +1 -0
- package/dist/migrations/sessions-v3.d.ts +8 -0
- package/dist/migrations/sessions-v3.d.ts.map +1 -0
- package/dist/migrations/sessions-v3.js +350 -0
- package/dist/migrations/sessions-v3.js.map +1 -0
- package/dist/migrations/types.d.ts +25 -0
- package/dist/migrations/types.d.ts.map +1 -0
- package/dist/migrations/types.js +2 -0
- package/dist/migrations/types.js.map +1 -0
- package/dist/migrations/workspace-events.d.ts +3 -0
- package/dist/migrations/workspace-events.d.ts.map +1 -0
- package/dist/migrations/workspace-events.js +43 -0
- package/dist/migrations/workspace-events.js.map +1 -0
- package/dist/observability/index.d.ts +30 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +273 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/instrument.js +9 -6
- package/dist/observability/instrument.js.map +1 -1
- package/dist/observability/otel.d.ts +10 -0
- package/dist/observability/otel.d.ts.map +1 -0
- package/dist/observability/otel.js +182 -0
- package/dist/observability/otel.js.map +1 -0
- package/dist/observability/sentry.d.ts +30 -18
- package/dist/observability/sentry.d.ts.map +1 -1
- package/dist/observability/sentry.js +94 -119
- package/dist/observability/sentry.js.map +1 -1
- package/dist/observability/types.d.ts +30 -19
- package/dist/observability/types.d.ts.map +1 -1
- package/dist/observability/types.js.map +1 -1
- package/dist/office/index.d.ts +49 -0
- package/dist/office/index.d.ts.map +1 -0
- package/dist/office/index.js +395 -0
- package/dist/office/index.js.map +1 -0
- package/dist/office/projection.d.ts +11 -0
- package/dist/office/projection.d.ts.map +1 -0
- package/dist/office/projection.js +145 -0
- package/dist/office/projection.js.map +1 -0
- package/dist/office/types.d.ts +44 -0
- package/dist/office/types.d.ts.map +1 -0
- package/dist/office/types.js +2 -0
- package/dist/office/types.js.map +1 -0
- package/dist/runtime/conversation-runtime.d.ts +0 -1
- package/dist/runtime/conversation-runtime.d.ts.map +1 -1
- package/dist/runtime/conversation-runtime.js +365 -155
- package/dist/runtime/conversation-runtime.js.map +1 -1
- package/dist/runtime/session-lifecycle.d.ts +65 -0
- package/dist/runtime/session-lifecycle.d.ts.map +1 -0
- package/dist/runtime/session-lifecycle.js +384 -0
- package/dist/runtime/session-lifecycle.js.map +1 -0
- package/dist/runtime/types.d.ts +42 -20
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js.map +1 -1
- package/dist/sandbox/cloudflare.d.ts +4 -0
- package/dist/sandbox/cloudflare.d.ts.map +1 -1
- package/dist/sandbox/cloudflare.js +59 -55
- package/dist/sandbox/cloudflare.js.map +1 -1
- package/dist/sandbox/container.d.ts +3 -0
- package/dist/sandbox/container.d.ts.map +1 -1
- package/dist/sandbox/container.js +39 -20
- package/dist/sandbox/container.js.map +1 -1
- package/dist/sandbox/host.d.ts +3 -0
- package/dist/sandbox/host.d.ts.map +1 -1
- package/dist/sandbox/host.js +42 -35
- package/dist/sandbox/host.js.map +1 -1
- package/dist/sandbox/identity.d.ts +12 -0
- package/dist/sandbox/identity.d.ts.map +1 -0
- package/dist/sandbox/identity.js +42 -0
- package/dist/sandbox/identity.js.map +1 -0
- package/dist/sandbox/index.d.ts +5 -15
- package/dist/sandbox/index.d.ts.map +1 -1
- package/dist/sandbox/index.js +5 -51
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/layout.d.ts +5 -0
- package/dist/sandbox/layout.d.ts.map +1 -0
- package/dist/sandbox/layout.js +13 -0
- package/dist/sandbox/layout.js.map +1 -0
- package/dist/sandbox/provisioner.d.ts +64 -0
- package/dist/sandbox/provisioner.d.ts.map +1 -0
- package/dist/sandbox/provisioner.js +546 -0
- package/dist/sandbox/provisioner.js.map +1 -0
- package/dist/sandbox/registry.d.ts +12 -0
- package/dist/sandbox/registry.d.ts.map +1 -0
- package/dist/sandbox/registry.js +93 -0
- package/dist/sandbox/registry.js.map +1 -0
- package/dist/sandbox/types.d.ts +23 -25
- package/dist/sandbox/types.d.ts.map +1 -1
- package/dist/sandbox/types.js.map +1 -1
- package/dist/sandbox/utils.d.ts +21 -0
- package/dist/sandbox/utils.d.ts.map +1 -1
- package/dist/sandbox/utils.js +100 -8
- package/dist/sandbox/utils.js.map +1 -1
- package/dist/sessions/chat-history-sync.d.ts +19 -0
- package/dist/sessions/chat-history-sync.d.ts.map +1 -0
- package/dist/sessions/chat-history-sync.js +459 -0
- package/dist/sessions/chat-history-sync.js.map +1 -0
- package/dist/sessions/compaction-summary.d.ts +4 -0
- package/dist/sessions/compaction-summary.d.ts.map +1 -0
- package/dist/sessions/compaction-summary.js +16 -0
- package/dist/sessions/compaction-summary.js.map +1 -0
- package/dist/sessions/history-line.d.ts +10 -0
- package/dist/sessions/history-line.d.ts.map +1 -0
- package/dist/sessions/history-line.js +29 -0
- package/dist/sessions/history-line.js.map +1 -0
- package/dist/sessions/session-key.d.ts +19 -0
- package/dist/sessions/session-key.d.ts.map +1 -0
- package/dist/sessions/session-key.js +91 -0
- package/dist/sessions/session-key.js.map +1 -0
- package/dist/sessions/session-store.d.ts +73 -0
- package/dist/sessions/session-store.d.ts.map +1 -0
- package/dist/sessions/session-store.js +721 -0
- package/dist/sessions/session-store.js.map +1 -0
- package/dist/sessions/types.d.ts +90 -34
- package/dist/sessions/types.d.ts.map +1 -1
- package/dist/sessions/types.js +2 -1
- package/dist/sessions/types.js.map +1 -1
- package/dist/settings/apply.d.ts +9 -0
- package/dist/settings/apply.d.ts.map +1 -0
- package/dist/settings/apply.js +31 -0
- package/dist/settings/apply.js.map +1 -0
- package/dist/settings/index.d.ts +28 -0
- package/dist/settings/index.d.ts.map +1 -0
- package/dist/settings/index.js +322 -0
- package/dist/settings/index.js.map +1 -0
- package/dist/types.d.ts +209 -191
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -3
- package/dist/types.js.map +1 -1
- package/dist/unknown-values.d.ts +3 -0
- package/dist/unknown-values.d.ts.map +1 -0
- package/dist/unknown-values.js +7 -0
- package/dist/unknown-values.js.map +1 -0
- package/dist/vault/index.d.ts +28 -11
- package/dist/vault/index.d.ts.map +1 -1
- package/dist/vault/index.js +291 -118
- package/dist/vault/index.js.map +1 -1
- package/dist/vault/types.d.ts +5 -19
- package/dist/vault/types.d.ts.map +1 -1
- package/dist/vault/types.js.map +1 -1
- package/package.json +87 -41
- package/dist/adapter.d.ts +0 -2
- package/dist/adapter.d.ts.map +0 -1
- package/dist/adapter.js +0 -2
- package/dist/adapter.js.map +0 -1
- package/dist/adapters/github/repo.d.ts +0 -19
- package/dist/adapters/github/repo.d.ts.map +0 -1
- package/dist/adapters/github/repo.js +0 -58
- package/dist/adapters/github/repo.js.map +0 -1
- package/dist/adapters/slack/tools/attach.d.ts +0 -12
- package/dist/adapters/slack/tools/attach.d.ts.map +0 -1
- package/dist/adapters/slack/tools/attach.js +0 -39
- package/dist/adapters/slack/tools/attach.js.map +0 -1
- package/dist/adapters/streaming.d.ts +0 -18
- package/dist/adapters/streaming.d.ts.map +0 -1
- package/dist/adapters/streaming.js +0 -44
- package/dist/adapters/streaming.js.map +0 -1
- package/dist/adapters/telegram/html.d.ts +0 -3
- package/dist/adapters/telegram/html.d.ts.map +0 -1
- package/dist/adapters/telegram/html.js +0 -98
- package/dist/adapters/telegram/html.js.map +0 -1
- package/dist/agent-events.d.ts +0 -5
- package/dist/agent-events.d.ts.map +0 -1
- package/dist/agent-events.js +0 -26
- package/dist/agent-events.js.map +0 -1
- package/dist/agent.d.ts +0 -39
- package/dist/agent.d.ts.map +0 -1
- package/dist/agent.js +0 -1299
- package/dist/agent.js.map +0 -1
- package/dist/cli/ext-git.d.ts +0 -22
- package/dist/cli/ext-git.d.ts.map +0 -1
- package/dist/cli/ext-git.js +0 -76
- package/dist/cli/ext-git.js.map +0 -1
- package/dist/cli/ext.d.ts +0 -2
- package/dist/cli/ext.d.ts.map +0 -1
- package/dist/cli/ext.js +0 -217
- package/dist/cli/ext.js.map +0 -1
- package/dist/commands/admin.d.ts.map +0 -1
- package/dist/commands/admin.js +0 -30
- package/dist/commands/admin.js.map +0 -1
- package/dist/commands/auto-reply.d.ts +0 -8
- package/dist/commands/auto-reply.d.ts.map +0 -1
- package/dist/commands/auto-reply.js +0 -76
- package/dist/commands/auto-reply.js.map +0 -1
- package/dist/commands/extensions.d.ts +0 -14
- package/dist/commands/extensions.d.ts.map +0 -1
- package/dist/commands/extensions.js +0 -55
- package/dist/commands/extensions.js.map +0 -1
- package/dist/commands/login.d.ts +0 -5
- package/dist/commands/login.d.ts.map +0 -1
- package/dist/commands/login.js +0 -115
- package/dist/commands/login.js.map +0 -1
- package/dist/commands/model.d.ts +0 -10
- package/dist/commands/model.d.ts.map +0 -1
- package/dist/commands/model.js +0 -102
- package/dist/commands/model.js.map +0 -1
- package/dist/commands/new.d.ts.map +0 -1
- package/dist/commands/new.js +0 -25
- package/dist/commands/new.js.map +0 -1
- package/dist/commands/parse.d.ts +0 -7
- package/dist/commands/parse.d.ts.map +0 -1
- package/dist/commands/parse.js +0 -14
- package/dist/commands/parse.js.map +0 -1
- package/dist/commands/registry.d.ts +0 -5
- package/dist/commands/registry.d.ts.map +0 -1
- package/dist/commands/registry.js +0 -31
- package/dist/commands/registry.js.map +0 -1
- package/dist/commands/sandbox.d.ts +0 -7
- package/dist/commands/sandbox.d.ts.map +0 -1
- package/dist/commands/sandbox.js +0 -78
- package/dist/commands/sandbox.js.map +0 -1
- package/dist/commands/session-view.d.ts.map +0 -1
- package/dist/commands/session-view.js +0 -41
- package/dist/commands/session-view.js.map +0 -1
- package/dist/commands/types.d.ts +0 -66
- package/dist/commands/types.d.ts.map +0 -1
- package/dist/commands/types.js.map +0 -1
- package/dist/commands/utils.d.ts +0 -11
- package/dist/commands/utils.d.ts.map +0 -1
- package/dist/commands/utils.js +0 -29
- package/dist/commands/utils.js.map +0 -1
- package/dist/config.d.ts +0 -78
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -450
- package/dist/config.js.map +0 -1
- package/dist/download.d.ts.map +0 -1
- package/dist/download.js +0 -89
- package/dist/download.js.map +0 -1
- package/dist/events.d.ts +0 -43
- package/dist/events.d.ts.map +0 -1
- package/dist/events.js +0 -456
- package/dist/events.js.map +0 -1
- package/dist/execution-resolver.d.ts +0 -21
- package/dist/execution-resolver.d.ts.map +0 -1
- package/dist/execution-resolver.js +0 -170
- package/dist/execution-resolver.js.map +0 -1
- package/dist/harness/auth.d.ts +0 -16
- package/dist/harness/auth.d.ts.map +0 -1
- package/dist/harness/auth.js +0 -86
- package/dist/harness/auth.js.map +0 -1
- package/dist/harness/extensions/loader.d.ts +0 -86
- package/dist/harness/extensions/loader.d.ts.map +0 -1
- package/dist/harness/extensions/loader.js +0 -525
- package/dist/harness/extensions/loader.js.map +0 -1
- package/dist/harness/extensions/registry.d.ts +0 -23
- package/dist/harness/extensions/registry.d.ts.map +0 -1
- package/dist/harness/extensions/registry.js +0 -45
- package/dist/harness/extensions/registry.js.map +0 -1
- package/dist/harness/extensions/types.d.ts +0 -248
- package/dist/harness/extensions/types.d.ts.map +0 -1
- package/dist/harness/extensions/types.js.map +0 -1
- package/dist/harness/session-store.d.ts +0 -77
- package/dist/harness/session-store.d.ts.map +0 -1
- package/dist/harness/session-store.js +0 -248
- package/dist/harness/session-store.js.map +0 -1
- package/dist/harness/settings.d.ts +0 -47
- package/dist/harness/settings.d.ts.map +0 -1
- package/dist/harness/settings.js +0 -29
- package/dist/harness/settings.js.map +0 -1
- package/dist/model-registry.d.ts +0 -4
- package/dist/model-registry.d.ts.map +0 -1
- package/dist/model-registry.js +0 -7
- package/dist/model-registry.js.map +0 -1
- package/dist/platform-messages.d.ts +0 -12
- package/dist/platform-messages.d.ts.map +0 -1
- package/dist/platform-messages.js +0 -36
- package/dist/platform-messages.js.map +0 -1
- package/dist/portal-shell.d.ts +0 -4
- package/dist/portal-shell.d.ts.map +0 -1
- package/dist/portal-shell.js +0 -366
- package/dist/portal-shell.js.map +0 -1
- package/dist/provisioner.d.ts +0 -61
- package/dist/provisioner.d.ts.map +0 -1
- package/dist/provisioner.js +0 -517
- package/dist/provisioner.js.map +0 -1
- package/dist/runtime/agent-run-controller.d.ts +0 -31
- package/dist/runtime/agent-run-controller.d.ts.map +0 -1
- package/dist/runtime/agent-run-controller.js +0 -195
- package/dist/runtime/agent-run-controller.js.map +0 -1
- package/dist/sandbox/errors.d.ts +0 -6
- package/dist/sandbox/errors.d.ts.map +0 -1
- package/dist/sandbox/errors.js +0 -11
- package/dist/sandbox/errors.js.map +0 -1
- package/dist/sandbox/firecracker.d.ts +0 -15
- package/dist/sandbox/firecracker.d.ts.map +0 -1
- package/dist/sandbox/firecracker.js +0 -212
- package/dist/sandbox/firecracker.js.map +0 -1
- package/dist/sandbox/image.d.ts +0 -3
- package/dist/sandbox/image.d.ts.map +0 -1
- package/dist/sandbox/image.js +0 -27
- package/dist/sandbox/image.js.map +0 -1
- package/dist/sandbox/path-context.d.ts +0 -3
- package/dist/sandbox/path-context.d.ts.map +0 -1
- package/dist/sandbox/path-context.js +0 -20
- package/dist/sandbox/path-context.js.map +0 -1
- package/dist/sessions/agent-memory-file-manager.d.ts +0 -19
- package/dist/sessions/agent-memory-file-manager.d.ts.map +0 -1
- package/dist/sessions/agent-memory-file-manager.js +0 -484
- package/dist/sessions/agent-memory-file-manager.js.map +0 -1
- package/dist/sessions/metadata.d.ts +0 -3
- package/dist/sessions/metadata.d.ts.map +0 -1
- package/dist/sessions/metadata.js +0 -11
- package/dist/sessions/metadata.js.map +0 -1
- package/dist/sessions/policy.d.ts +0 -6
- package/dist/sessions/policy.d.ts.map +0 -1
- package/dist/sessions/policy.js +0 -24
- package/dist/sessions/policy.js.map +0 -1
- package/dist/sessions/store.d.ts +0 -72
- package/dist/sessions/store.d.ts.map +0 -1
- package/dist/sessions/store.js +0 -193
- package/dist/sessions/store.js.map +0 -1
- package/dist/store.d.ts +0 -46
- package/dist/store.d.ts.map +0 -1
- package/dist/store.js +0 -177
- package/dist/store.js.map +0 -1
- package/dist/tools/bash.d.ts +0 -10
- package/dist/tools/bash.d.ts.map +0 -1
- package/dist/tools/bash.js +0 -80
- package/dist/tools/bash.js.map +0 -1
- package/dist/tools/edit.d.ts +0 -11
- package/dist/tools/edit.d.ts.map +0 -1
- package/dist/tools/edit.js +0 -131
- package/dist/tools/edit.js.map +0 -1
- package/dist/tools/event.d.ts +0 -56
- package/dist/tools/event.d.ts.map +0 -1
- package/dist/tools/event.js +0 -252
- package/dist/tools/event.js.map +0 -1
- package/dist/tools/github-pr.d.ts +0 -22
- package/dist/tools/github-pr.d.ts.map +0 -1
- package/dist/tools/github-pr.js +0 -53
- package/dist/tools/github-pr.js.map +0 -1
- package/dist/tools/index.d.ts +0 -25
- package/dist/tools/index.d.ts.map +0 -1
- package/dist/tools/index.js +0 -35
- package/dist/tools/index.js.map +0 -1
- package/dist/tools/react.d.ts +0 -15
- package/dist/tools/react.d.ts.map +0 -1
- package/dist/tools/react.js +0 -40
- package/dist/tools/react.js.map +0 -1
- package/dist/tools/read.d.ts +0 -11
- package/dist/tools/read.d.ts.map +0 -1
- package/dist/tools/read.js +0 -134
- package/dist/tools/read.js.map +0 -1
- package/dist/tools/sandbox.d.ts +0 -22
- package/dist/tools/sandbox.d.ts.map +0 -1
- package/dist/tools/sandbox.js +0 -73
- package/dist/tools/sandbox.js.map +0 -1
- package/dist/tools/truncate.d.ts +0 -33
- package/dist/tools/truncate.d.ts.map +0 -1
- package/dist/tools/truncate.js +0 -184
- package/dist/tools/truncate.js.map +0 -1
- package/dist/tools/types.d.ts +0 -54
- package/dist/tools/types.d.ts.map +0 -1
- package/dist/tools/types.js.map +0 -1
- package/dist/tools/write.d.ts +0 -10
- package/dist/tools/write.d.ts.map +0 -1
- package/dist/tools/write.js +0 -29
- package/dist/tools/write.js.map +0 -1
- package/dist/trigger.d.ts +0 -22
- package/dist/trigger.d.ts.map +0 -1
- package/dist/trigger.js +0 -100
- package/dist/trigger.js.map +0 -1
- package/dist/utils/date.d.ts +0 -10
- package/dist/utils/date.d.ts.map +0 -1
- package/dist/utils/date.js +0 -23
- package/dist/utils/date.js.map +0 -1
- package/dist/utils/env.d.ts +0 -3
- package/dist/utils/env.d.ts.map +0 -1
- package/dist/utils/env.js +0 -12
- package/dist/utils/env.js.map +0 -1
- package/dist/utils/file-guards.d.ts +0 -9
- package/dist/utils/file-guards.d.ts.map +0 -1
- package/dist/utils/file-guards.js +0 -59
- package/dist/utils/file-guards.js.map +0 -1
- package/dist/utils/fs-atomic.d.ts +0 -10
- package/dist/utils/fs-atomic.d.ts.map +0 -1
- package/dist/utils/fs-atomic.js +0 -45
- package/dist/utils/fs-atomic.js.map +0 -1
- package/dist/utils/html.d.ts +0 -2
- package/dist/utils/html.d.ts.map +0 -1
- package/dist/utils/html.js +0 -4
- package/dist/utils/html.js.map +0 -1
- package/dist/utils/http-body.d.ts +0 -10
- package/dist/utils/http-body.d.ts.map +0 -1
- package/dist/utils/http-body.js +0 -34
- package/dist/utils/http-body.js.map +0 -1
- package/dist/vault/routing.d.ts +0 -3
- package/dist/vault/routing.d.ts.map +0 -1
- package/dist/vault/routing.js +0 -13
- package/dist/vault/routing.js.map +0 -1
- package/dist/web/admin/portal.d.ts +0 -5
- package/dist/web/admin/portal.d.ts.map +0 -1
- package/dist/web/admin/portal.js +0 -2572
- package/dist/web/admin/portal.js.map +0 -1
- package/dist/web/admin/provider-models.d.ts +0 -10
- package/dist/web/admin/provider-models.d.ts.map +0 -1
- package/dist/web/admin/provider-models.js +0 -96
- package/dist/web/admin/provider-models.js.map +0 -1
- package/dist/web/admin/store.d.ts +0 -13
- package/dist/web/admin/store.d.ts.map +0 -1
- package/dist/web/admin/store.js +0 -14
- package/dist/web/admin/store.js.map +0 -1
- package/dist/web/admin/types.d.ts +0 -30
- package/dist/web/admin/types.d.ts.map +0 -1
- package/dist/web/admin/types.js.map +0 -1
- package/dist/web/agent-events/portal.d.ts +0 -3
- package/dist/web/agent-events/portal.d.ts.map +0 -1
- package/dist/web/agent-events/portal.js +0 -18
- package/dist/web/agent-events/portal.js.map +0 -1
- package/dist/web/login/oauth.d.ts +0 -6
- package/dist/web/login/oauth.d.ts.map +0 -1
- package/dist/web/login/oauth.js +0 -258
- package/dist/web/login/oauth.js.map +0 -1
- package/dist/web/login/portal.d.ts +0 -17
- package/dist/web/login/portal.d.ts.map +0 -1
- package/dist/web/login/portal.js +0 -1329
- package/dist/web/login/portal.js.map +0 -1
- package/dist/web/login/store.d.ts +0 -8
- package/dist/web/login/store.d.ts.map +0 -1
- package/dist/web/login/store.js +0 -15
- package/dist/web/login/store.js.map +0 -1
- package/dist/web/login/types.d.ts +0 -50
- package/dist/web/login/types.d.ts.map +0 -1
- package/dist/web/login/types.js.map +0 -1
- package/dist/web/request.d.ts +0 -3
- package/dist/web/request.d.ts.map +0 -1
- package/dist/web/request.js +0 -13
- package/dist/web/request.js.map +0 -1
- package/dist/web/server.d.ts +0 -28
- package/dist/web/server.d.ts.map +0 -1
- package/dist/web/server.js +0 -66
- package/dist/web/server.js.map +0 -1
- package/dist/web/session-view/command.d.ts +0 -4
- package/dist/web/session-view/command.d.ts.map +0 -1
- package/dist/web/session-view/command.js +0 -7
- package/dist/web/session-view/command.js.map +0 -1
- package/dist/web/session-view/portal.d.ts +0 -13
- package/dist/web/session-view/portal.d.ts.map +0 -1
- package/dist/web/session-view/portal.js +0 -1651
- package/dist/web/session-view/portal.js.map +0 -1
- package/dist/web/session-view/service.d.ts +0 -6
- package/dist/web/session-view/service.d.ts.map +0 -1
- package/dist/web/session-view/service.js +0 -498
- package/dist/web/session-view/service.js.map +0 -1
- package/dist/web/session-view/store.d.ts +0 -8
- package/dist/web/session-view/store.d.ts.map +0 -1
- package/dist/web/session-view/store.js +0 -15
- package/dist/web/session-view/store.js.map +0 -1
- package/dist/web/session-view/types.d.ts +0 -50
- package/dist/web/session-view/types.d.ts.map +0 -1
- package/dist/web/session-view/types.js.map +0 -1
- package/dist/web/token-store.d.ts +0 -13
- package/dist/web/token-store.d.ts.map +0 -1
- package/dist/web/token-store.js +0 -44
- package/dist/web/token-store.js.map +0 -1
- package/dist/web/types.d.ts.map +0 -1
- package/dist/web/types.js.map +0 -1
- /package/dist/{commands → adapters/commands}/admin.d.ts +0 -0
- /package/dist/{commands → adapters/commands}/new.d.ts +0 -0
- /package/dist/{commands → adapters/commands}/session-view.d.ts +0 -0
- /package/dist/{commands → adapters/commands}/types.js +0 -0
- /package/dist/{harness/extensions → adapters/web/admin}/types.js +0 -0
- /package/dist/{tools → adapters/web/login}/types.js +0 -0
- /package/dist/{web/admin → adapters/web/session-view}/types.js +0 -0
- /package/dist/{web → adapters/web}/types.d.ts +0 -0
- /package/dist/{web/login → adapters/web}/types.js +0 -0
- /package/dist/{download.d.ts → cli/download.d.ts} +0 -0
- /package/dist/{web/session-view → cli}/types.js +0 -0
- /package/dist/{web → harness/tools}/types.js +0 -0
|
@@ -0,0 +1,1766 @@
|
|
|
1
|
+
import { THINKING_LEVELS } from "../../../settings/index.js";
|
|
2
|
+
export const adminViewFunctionsScript = ` let activeConversationKey = defaultConversationKey;
|
|
3
|
+
function scopeOf(key) {
|
|
4
|
+
const sep = key.indexOf(':');
|
|
5
|
+
return { platform: key.slice(0, sep), conversationId: key.slice(sep + 1) };
|
|
6
|
+
}
|
|
7
|
+
function scopeQuery() {
|
|
8
|
+
const scope = scopeOf(activeConversationKey);
|
|
9
|
+
return 'conversationId=' + encodeURIComponent(scope.conversationId) +
|
|
10
|
+
'&platform=' + encodeURIComponent(scope.platform);
|
|
11
|
+
}
|
|
12
|
+
function scopeBody() {
|
|
13
|
+
const scope = scopeOf(activeConversationKey);
|
|
14
|
+
return { conversationId: scope.conversationId, platform: scope.platform };
|
|
15
|
+
}
|
|
16
|
+
let availableModels = [];
|
|
17
|
+
let modelsLoaded = false;
|
|
18
|
+
let mcpPresets = [];
|
|
19
|
+
let mcpServersByScope = { conversation: {}, global: {} };
|
|
20
|
+
let pendingMcpInstall = null;
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
function escHtml(str) {
|
|
24
|
+
return String(str).replace(/[&<>"']/g, (c) => (
|
|
25
|
+
{'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]
|
|
26
|
+
));
|
|
27
|
+
}
|
|
28
|
+
const escAttr = escHtml;
|
|
29
|
+
async function copyToClipboard(text) {
|
|
30
|
+
try { await navigator.clipboard.writeText(text); } catch { prompt('Copy this link:', text); }
|
|
31
|
+
}
|
|
32
|
+
document.addEventListener('click', (event) => {
|
|
33
|
+
const target = event.target instanceof Element
|
|
34
|
+
? event.target.closest('[data-admin-action]')
|
|
35
|
+
: null;
|
|
36
|
+
if (!target) return;
|
|
37
|
+
switch (target.dataset.adminAction) {
|
|
38
|
+
case 'preview-file':
|
|
39
|
+
void previewFile(target.dataset.filePath || '');
|
|
40
|
+
break;
|
|
41
|
+
case 'copy-link':
|
|
42
|
+
void copyToClipboard(target.dataset.copyText || '');
|
|
43
|
+
break;
|
|
44
|
+
case 'delete-event':
|
|
45
|
+
void deleteEvent(target.dataset.eventName || '', target);
|
|
46
|
+
break;
|
|
47
|
+
case 'select-conversation':
|
|
48
|
+
setActiveConversation(target.dataset.conversationId || '');
|
|
49
|
+
switchTab('conversation');
|
|
50
|
+
break;
|
|
51
|
+
case 'toggle-timeline-filter':
|
|
52
|
+
toggleTimelineFilter(target.dataset.filterKey || '');
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
async function apiGet(path) {
|
|
57
|
+
const url = path + (path.includes('?') ? '&' : '?') + 'token=' + encodeURIComponent(adminToken);
|
|
58
|
+
const r = await fetch(url);
|
|
59
|
+
const data = await r.json();
|
|
60
|
+
if (!r.ok) throw new Error(data.error || ('HTTP ' + r.status));
|
|
61
|
+
return data;
|
|
62
|
+
}
|
|
63
|
+
async function apiPost(path, body) {
|
|
64
|
+
const r = await fetch(path, {
|
|
65
|
+
method: 'POST',
|
|
66
|
+
headers: { 'Content-Type': 'application/json' },
|
|
67
|
+
body: JSON.stringify({ token: adminToken, ...body }),
|
|
68
|
+
});
|
|
69
|
+
const data = await r.json();
|
|
70
|
+
if (!r.ok) throw new Error(data.error || ('HTTP ' + r.status));
|
|
71
|
+
return data;
|
|
72
|
+
}
|
|
73
|
+
async function loadModels() {
|
|
74
|
+
try {
|
|
75
|
+
const data = await apiGet('/admin/api/models');
|
|
76
|
+
availableModels = Array.isArray(data.models) ? data.models : [];
|
|
77
|
+
} catch (err) {
|
|
78
|
+
availableModels = [];
|
|
79
|
+
} finally {
|
|
80
|
+
modelsLoaded = true;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function modelRef(provider, model) {
|
|
84
|
+
return provider && model ? provider + '/' + model : '';
|
|
85
|
+
}
|
|
86
|
+
function parseModelRef(value) {
|
|
87
|
+
const slash = value.indexOf('/');
|
|
88
|
+
if (slash <= 0 || slash === value.length - 1) return { provider: '', model: '' };
|
|
89
|
+
return { provider: value.slice(0, slash), model: value.slice(slash + 1) };
|
|
90
|
+
}
|
|
91
|
+
function renderModelOptions(currentProvider, currentModel) {
|
|
92
|
+
const current = modelRef(currentProvider, currentModel);
|
|
93
|
+
const seen = new Set();
|
|
94
|
+
const groups = {
|
|
95
|
+
available: [],
|
|
96
|
+
unverified: [],
|
|
97
|
+
};
|
|
98
|
+
if (current) {
|
|
99
|
+
seen.add(current);
|
|
100
|
+
groups.available.push('<option value="' + escAttr(current) + '">' + escHtml(current + ' (current)') + '</option>');
|
|
101
|
+
}
|
|
102
|
+
for (const model of availableModels) {
|
|
103
|
+
const ref = modelRef(model.provider, model.id);
|
|
104
|
+
if (!ref || seen.has(ref)) continue;
|
|
105
|
+
seen.add(ref);
|
|
106
|
+
const details = [model.name && model.name !== model.id ? model.name : '', model.reasoning ? 'thinking' : '', Array.isArray(model.input) && model.input.includes('image') ? 'image' : '']
|
|
107
|
+
.filter(Boolean)
|
|
108
|
+
.join(' · ');
|
|
109
|
+
const option = '<option value="' + escAttr(ref) + '">' + escHtml(details ? ref + ' — ' + details : ref) + '</option>';
|
|
110
|
+
if (model.status === 'unverified') groups.unverified.push(option);
|
|
111
|
+
else groups.available.push(option);
|
|
112
|
+
}
|
|
113
|
+
const sections = [];
|
|
114
|
+
if (groups.available.length > 0) sections.push('<optgroup label="Available">' + groups.available.join('') + '</optgroup>');
|
|
115
|
+
if (groups.unverified.length > 0) sections.push('<optgroup label="Configured but unverified">' + groups.unverified.join('') + '</optgroup>');
|
|
116
|
+
if (sections.length === 0) {
|
|
117
|
+
return '<option value="">No available models</option>';
|
|
118
|
+
}
|
|
119
|
+
return sections.join('');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
const scopeBtns = document.querySelectorAll('.rail-scope-btn');
|
|
124
|
+
const tabPanels = document.querySelectorAll('.tab-panel');
|
|
125
|
+
const railNavConversation = document.getElementById('rail-nav-conversation');
|
|
126
|
+
const railNavGlobal = document.getElementById('rail-nav-global');
|
|
127
|
+
|
|
128
|
+
function switchTab(tabId) {
|
|
129
|
+
scopeBtns.forEach((btn) => {
|
|
130
|
+
const active = btn.dataset.tab === tabId;
|
|
131
|
+
btn.classList.toggle('active', active);
|
|
132
|
+
btn.setAttribute('aria-selected', active ? 'true' : 'false');
|
|
133
|
+
});
|
|
134
|
+
tabPanels.forEach((panel) => panel.classList.toggle('active', panel.id === 'panel-' + tabId));
|
|
135
|
+
railNavConversation.hidden = tabId !== 'conversation';
|
|
136
|
+
railNavGlobal.hidden = tabId !== 'global';
|
|
137
|
+
if (tabId === 'global') initGlobal();
|
|
138
|
+
const firstPane = (tabId === 'global' ? railNavGlobal : railNavConversation).querySelector('.rail-link');
|
|
139
|
+
if (firstPane) selectPane(tabId, firstPane.dataset.pane);
|
|
140
|
+
}
|
|
141
|
+
scopeBtns.forEach((btn) => btn.addEventListener('click', () => switchTab(btn.dataset.tab)));
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
function paneLoader(key) {
|
|
145
|
+
switch (key) {
|
|
146
|
+
case 'settings': return loadSettings;
|
|
147
|
+
case 'workspace': return loadWorkspace;
|
|
148
|
+
case 'skills': return loadSkills;
|
|
149
|
+
case 'mcp': return loadMcpServers;
|
|
150
|
+
case 'events': return loadConversationEvents;
|
|
151
|
+
case 'g-overview': return loadAllConversations;
|
|
152
|
+
case 'g-usage': return loadTokenUsage;
|
|
153
|
+
case 'g-settings': return loadGlobalSettings;
|
|
154
|
+
case 'g-mcp': return loadMcpServers;
|
|
155
|
+
case 'g-skills': return loadGlobalSkills;
|
|
156
|
+
case 'g-events': return loadEvents;
|
|
157
|
+
default: return undefined;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const paneLoaded = new Set();
|
|
161
|
+
|
|
162
|
+
function ensurePaneLoaded(key) {
|
|
163
|
+
if (paneLoaded.has(key)) return;
|
|
164
|
+
const loader = paneLoader(key);
|
|
165
|
+
if (!loader) return;
|
|
166
|
+
paneLoaded.add(key);
|
|
167
|
+
loader();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function selectPane(scope, key) {
|
|
171
|
+
const nav = scope === 'global' ? railNavGlobal : railNavConversation;
|
|
172
|
+
const panel = document.getElementById(scope === 'global' ? 'panel-global' : 'panel-conversation');
|
|
173
|
+
nav.querySelectorAll('.rail-link').forEach((btn) => {
|
|
174
|
+
const active = btn.dataset.pane === key;
|
|
175
|
+
btn.classList.toggle('active', active);
|
|
176
|
+
btn.setAttribute('aria-current', active ? 'page' : 'false');
|
|
177
|
+
});
|
|
178
|
+
panel.querySelectorAll('.pane').forEach((pane) => {
|
|
179
|
+
pane.classList.toggle('active', pane.dataset.pane === key);
|
|
180
|
+
});
|
|
181
|
+
ensurePaneLoaded(key);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function initRailNav() {
|
|
185
|
+
document.querySelectorAll('.rail-link').forEach((btn) => {
|
|
186
|
+
btn.addEventListener('click', () => {
|
|
187
|
+
const nav = btn.closest('.rail-nav');
|
|
188
|
+
const scope = nav.dataset.scope;
|
|
189
|
+
selectPane(scope, btn.dataset.pane);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
selectPane('conversation', 'settings');
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
async function initConvSwitcher() {
|
|
197
|
+
const sel = document.getElementById('conv-switcher');
|
|
198
|
+
try {
|
|
199
|
+
const data = await apiGet('/admin/api/conversations');
|
|
200
|
+
sel.innerHTML = data.conversations.map((c) => {
|
|
201
|
+
const key = c.platform + ':' + c.conversationId;
|
|
202
|
+
const label = (c.label || c.conversationId) + (c.running ? ' (running)' : '');
|
|
203
|
+
const selected = key === defaultConversationKey ? ' selected' : '';
|
|
204
|
+
return '<option value="' + escAttr(key) + '"' + selected + '>' + escHtml(label) + '</option>';
|
|
205
|
+
}).join('');
|
|
206
|
+
sel.addEventListener('change', () => setActiveConversation(sel.value));
|
|
207
|
+
} catch (err) {
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function setActiveConversation(key) {
|
|
212
|
+
activeConversationKey = key;
|
|
213
|
+
const sel = document.getElementById('conv-switcher');
|
|
214
|
+
if (sel && sel.value !== key) sel.value = key;
|
|
215
|
+
const activeLink = railNavConversation.querySelector('.rail-link.active');
|
|
216
|
+
['settings', 'workspace', 'skills', 'mcp', 'events'].forEach((key) => paneLoaded.delete(key));
|
|
217
|
+
if (activeLink) ensurePaneLoaded(activeLink.dataset.pane);
|
|
218
|
+
openLogin(true);
|
|
219
|
+
openSessionView(true);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
const loadSettings = () => loadSettingsPanel('settings-content', () => '/admin/api/conversation-state?' + scopeQuery(), renderSettings);
|
|
224
|
+
const loadGlobalSettings = () => loadSettingsPanel('global-settings-content', () => '/admin/api/settings/global', renderGlobalSettings);
|
|
225
|
+
|
|
226
|
+
async function loadSettingsPanel(id, path, render) {
|
|
227
|
+
const container = document.getElementById(id);
|
|
228
|
+
container.innerHTML = '<div class="loading-msg">Loading…</div>';
|
|
229
|
+
if (!modelsLoaded) await loadModels();
|
|
230
|
+
try {
|
|
231
|
+
const data = await apiGet(path());
|
|
232
|
+
container.innerHTML = render(data);
|
|
233
|
+
} catch (err) {
|
|
234
|
+
container.innerHTML = '<div class="err-msg">' + escHtml(err.message) + '</div>';
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function renderConfigCard(title, content, action, buttonLabel, resultId) {
|
|
239
|
+
return '<div class="config-block"><h3 class="card-subtitle">' + title + '</h3>' + content +
|
|
240
|
+
'<button class="primary-action-btn" onclick="' + action + '(this)">' + buttonLabel + '</button>' +
|
|
241
|
+
'<div id="' + resultId + '" class="inline-result" style="display:none"></div></div>';
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function renderOptions(choices, selected) {
|
|
245
|
+
return choices.map(([value, label]) =>
|
|
246
|
+
'<option value="' + escAttr(value) + '"' + (selected === value ? ' selected' : '') + '>' + escHtml(label) + '</option>'
|
|
247
|
+
).join('');
|
|
248
|
+
}
|
|
249
|
+
function renderThinkingOptions(value) {
|
|
250
|
+
return renderOptions(${JSON.stringify(THINKING_LEVELS)}.map((t) => [t, t]), value);
|
|
251
|
+
}
|
|
252
|
+
function renderReplyOptions(slack) {
|
|
253
|
+
return renderOptions(['top-level','thread'].map((m) => [m, m]), (slack && slack.replyMode) || 'top-level');
|
|
254
|
+
}
|
|
255
|
+
function renderSettings(data) {
|
|
256
|
+
const thinkingOpts = renderThinkingOptions(data.thinkingLevel);
|
|
257
|
+
const replyModeOpts = renderReplyOptions(data.slack);
|
|
258
|
+
const globalReplyMode = (data.slack && data.slack.globalReplyMode) || 'top-level';
|
|
259
|
+
const globalModel = [data.globalProvider, data.globalModel].filter(Boolean).join('/');
|
|
260
|
+
const globalModelLabel = globalModel + (data.globalThinkingLevel ? ':' + data.globalThinkingLevel : '');
|
|
261
|
+
return [
|
|
262
|
+
'<div class="config-grid">',
|
|
263
|
+
renderConfigCard('Model', [
|
|
264
|
+
'<div class="config-row config-row-stack"><label>Model</label><select id="m-model-ref">' + renderModelOptions(data.provider, data.model) + '</select></div>',
|
|
265
|
+
'<div class="config-row"><label>Thinking</label><select id="m-thinking">' + thinkingOpts + '</select></div>',
|
|
266
|
+
'<p class="muted-note">Global default: ' + escHtml(globalModelLabel) + '</p>',
|
|
267
|
+
].join(''), 'saveModel', 'Save model', 'model-save-result'),
|
|
268
|
+
|
|
269
|
+
renderVisibilityCard(data),
|
|
270
|
+
renderConfigCard('Slack', [
|
|
271
|
+
'<div class="config-row"><label>Reply mode</label><select id="m-slack-reply-mode">' + replyModeOpts + '</select></div>',
|
|
272
|
+
'<p class="muted-note">Global default: ' + escHtml(globalReplyMode) + '</p>',
|
|
273
|
+
].join(''), 'saveSlack', 'Save Slack', 'slack-save-result'),
|
|
274
|
+
'</div>',
|
|
275
|
+
].join('');
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
async function saveModel(btn) {
|
|
279
|
+
const selectedModel = parseModelRef(document.getElementById('m-model-ref').value.trim());
|
|
280
|
+
const provider = selectedModel.provider;
|
|
281
|
+
const model = selectedModel.model;
|
|
282
|
+
const thinkingLevel = document.getElementById('m-thinking').value;
|
|
283
|
+
const result = document.getElementById('model-save-result');
|
|
284
|
+
if (!provider || !model) {
|
|
285
|
+
result.style.display = 'block'; result.className = 'inline-result err';
|
|
286
|
+
result.textContent = 'Provider and model are required';
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
await saveConversationSetting(btn, result, 'model', { provider, model, thinkingLevel }, 'Save model');
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
async function saveSlack(btn) {
|
|
293
|
+
const replyMode = document.getElementById('m-slack-reply-mode').value;
|
|
294
|
+
const result = document.getElementById('slack-save-result');
|
|
295
|
+
await saveConversationSetting(btn, result, 'slack', { replyMode }, 'Save Slack');
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function renderVisibilityCard(data) {
|
|
299
|
+
const hidden = data.officeVisibilityOverride === 'private';
|
|
300
|
+
const canChoose = data.officeVisibilitySource === 'platform' ? data.officeVisibility === 'public' : hidden;
|
|
301
|
+
if (!canChoose) {
|
|
302
|
+
const why = data.officeVisibilitySource === 'platform'
|
|
303
|
+
? 'This is a DM, a private channel, or a conversation on a platform other than Slack, so its files are hidden from every other office. The platform decides this; it cannot be opened up here.'
|
|
304
|
+
: 'Slack has not reported what kind of conversation this is yet, so it is treated as hidden until it does.';
|
|
305
|
+
return '<div class="config-block"><h3 class="card-subtitle">Who can see the files in this office</h3>' +
|
|
306
|
+
'<p><strong>Hidden</strong> — only this office.</p><p class="muted-note">' + why + '</p></div>';
|
|
307
|
+
}
|
|
308
|
+
return renderConfigCard('Who can see the files in this office', [
|
|
309
|
+
'<div class="config-row"><label><input type="checkbox" id="m-visibility"' + (hidden ? ' checked' : '') + '> Hide the files in this channel from other offices</label></div>',
|
|
310
|
+
'<p>' + (hidden
|
|
311
|
+
? '<strong>Hidden</strong> — other offices cannot read the files in this channel, and it can read shared MEMORY.md and skills but not change them.'
|
|
312
|
+
: '<strong>Shared</strong> — every other office can read the files in this channel (read-only), and this channel may update shared MEMORY.md and skills.') + '</p>',
|
|
313
|
+
'<p class="muted-note">Slack says this is a public channel, which is why sharing is the default. Hiding is the only change allowed; nothing can be made more visible than Slack allows.</p>',
|
|
314
|
+
].join(''), 'saveVisibility', 'Save', 'mount-save-result');
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
async function saveVisibility(btn) {
|
|
318
|
+
const visibility = document.getElementById('m-visibility').checked ? 'private' : 'default';
|
|
319
|
+
const result = document.getElementById('mount-save-result');
|
|
320
|
+
await saveConversationSetting(btn, result, 'visibility', { visibility }, 'Save visibility', loadSettings);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function saveConversationSetting(btn, result, setting, values, label, onSaved) {
|
|
324
|
+
return saveSetting(btn, result, 'conversations/' + setting, { ...scopeBody(), ...values }, label, onSaved);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
async function saveSetting(btn, result, path, values, label, onSaved) {
|
|
328
|
+
btn.disabled = true; btn.textContent = 'Saving…'; result.style.display = 'none';
|
|
329
|
+
try {
|
|
330
|
+
await apiPost('/admin/api/' + path, values);
|
|
331
|
+
result.style.display = 'block'; result.className = 'inline-result ok'; result.textContent = 'Saved ✓';
|
|
332
|
+
if (onSaved) onSaved();
|
|
333
|
+
} catch (err) {
|
|
334
|
+
result.style.display = 'block'; result.className = 'inline-result err'; result.textContent = err.message;
|
|
335
|
+
} finally {
|
|
336
|
+
btn.disabled = false; btn.textContent = label;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
async function loadWorkspace() {
|
|
342
|
+
const treeEl = document.getElementById('workspace-tree');
|
|
343
|
+
const previewEl = document.getElementById('workspace-preview');
|
|
344
|
+
treeEl.innerHTML = '<div class="loading-msg">Loading…</div>';
|
|
345
|
+
previewEl.innerHTML = '<div class="placeholder-msg">Click a file to preview</div>';
|
|
346
|
+
try {
|
|
347
|
+
const data = await apiGet('/admin/api/workspace/tree?' + scopeQuery());
|
|
348
|
+
if (!data.tree) {
|
|
349
|
+
treeEl.innerHTML = '<div class="empty-state">No files</div>';
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
treeEl.innerHTML = '<ul class="tree-root">' + renderTreeChildren(data.tree) + '</ul>';
|
|
353
|
+
} catch (err) {
|
|
354
|
+
treeEl.innerHTML = '<div class="err-msg">' + escHtml(err.message) + '</div>';
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function renderTreeChildren(node) {
|
|
359
|
+
if (node.type === 'file') {
|
|
360
|
+
return '<li><button class="tree-file" data-admin-action="preview-file" data-file-path="' + escAttr(node.path) + '">' + escHtml(node.name) + '</button></li>';
|
|
361
|
+
}
|
|
362
|
+
if (!node.children || node.children.length === 0) {
|
|
363
|
+
return '<li><span class="tree-dir empty">' + escHtml(node.name || '.') + '/</span></li>';
|
|
364
|
+
}
|
|
365
|
+
const inner = node.children.map((c) =>
|
|
366
|
+
c.type === 'file'
|
|
367
|
+
? '<li><button class="tree-file" data-admin-action="preview-file" data-file-path="' + escAttr(c.path) + '">' + escHtml(c.name) + '</button></li>'
|
|
368
|
+
: '<li><details open><summary class="tree-dir">' + escHtml(c.name) + '/</summary><ul>' + renderTreeChildren(c) + '</ul></details></li>'
|
|
369
|
+
).join('');
|
|
370
|
+
return inner;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function renderPreviewFileResult(previewEl, label, data) {
|
|
374
|
+
if (data.binary) {
|
|
375
|
+
previewEl.innerHTML = '<div class="preview-meta">' + escHtml(label) + ' · ' + data.size + ' bytes · binary</div><div class="placeholder-msg">Binary file — preview not available</div>';
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
previewEl.innerHTML =
|
|
379
|
+
'<div class="preview-meta">' + escHtml(label) + ' · ' + data.size + ' bytes</div>' +
|
|
380
|
+
'<pre class="preview-body">' + escHtml(data.content || '') + '</pre>';
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
async function previewFile(path) {
|
|
384
|
+
const previewEl = document.getElementById('workspace-preview');
|
|
385
|
+
previewEl.innerHTML = '<div class="loading-msg">Loading ' + escHtml(path) + '…</div>';
|
|
386
|
+
try {
|
|
387
|
+
const data = await apiGet('/admin/api/workspace/file?' + scopeQuery() + '&path=' + encodeURIComponent(path));
|
|
388
|
+
renderPreviewFileResult(previewEl, path, data);
|
|
389
|
+
} catch (err) {
|
|
390
|
+
previewEl.innerHTML = '<div class="err-msg">' + escHtml(err.message) + '</div>';
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
async function loadScopePanels(prefix, endpoint, render) {
|
|
396
|
+
const convEl = document.getElementById(prefix + '-conv-content');
|
|
397
|
+
const globalEl = document.getElementById(prefix + '-global-content');
|
|
398
|
+
if (convEl) convEl.innerHTML = '<div class="loading-msg">Loading…</div>';
|
|
399
|
+
if (globalEl) globalEl.innerHTML = '<div class="loading-msg">Loading…</div>';
|
|
400
|
+
try {
|
|
401
|
+
const data = await apiGet('/admin/api/' + endpoint + '?' + scopeQuery());
|
|
402
|
+
render(data, convEl, globalEl);
|
|
403
|
+
} catch (err) {
|
|
404
|
+
if (convEl) convEl.innerHTML = '<div class="err-msg">' + escHtml(err.message) + '</div>';
|
|
405
|
+
if (globalEl) globalEl.innerHTML = '<div class="err-msg">' + escHtml(err.message) + '</div>';
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
function mcpMessage(scope, text, kind) {
|
|
411
|
+
const el = document.getElementById(scope === 'global' ? 'mcp-global-msg' : 'mcp-conv-msg');
|
|
412
|
+
if (!el) return;
|
|
413
|
+
el.style.display = 'block';
|
|
414
|
+
el.className = 'status-msg status-msg-' + kind;
|
|
415
|
+
el.textContent = text;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function mcpTransport(server) {
|
|
419
|
+
return server.command
|
|
420
|
+
? server.command + (server.args && server.args.length ? ' ' + server.args.join(' ') : '')
|
|
421
|
+
: (server.url || '');
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function renderMcpServer(scope, name, server) {
|
|
425
|
+
const transport = (server.command ? 'stdio: ' : 'http: ') + mcpTransport(server);
|
|
426
|
+
const keys = [];
|
|
427
|
+
if (server.envKeys && server.envKeys.length) keys.push('env: ' + server.envKeys.join(', '));
|
|
428
|
+
if (server.headerKeys && server.headerKeys.length) keys.push('headers: ' + server.headerKeys.join(', '));
|
|
429
|
+
return '<article class="mcp-preset mcp-installed-card">' +
|
|
430
|
+
'<div class="mcp-preset-top">' +
|
|
431
|
+
'<span class="mcp-preset-category">' + (server.command ? 'STDIO' : 'HTTP') + '</span>' +
|
|
432
|
+
(server.disabled ? '<span class="mcp-badge mcp-badge-warn">disabled</span>' : '<span class="mcp-badge mcp-badge-ok">enabled</span>') +
|
|
433
|
+
'</div>' +
|
|
434
|
+
'<h3>' + escHtml(name) + '</h3>' +
|
|
435
|
+
'<p class="mcp-preset-meta mcp-installed-transport">' + escHtml(transport) + '</p>' +
|
|
436
|
+
(keys.length ? '<div class="mcp-preset-meta">' + escHtml(keys.join(' · ')) + '</div>' : '') +
|
|
437
|
+
'<div class="mcp-preset-actions">' +
|
|
438
|
+
'<button class="mcp-btn" data-mcp-action="test" data-mcp-scope="' + scope + '" data-mcp-name="' + escAttr(name) + '">Test</button>' +
|
|
439
|
+
'<button class="mcp-btn" data-mcp-action="toggle" data-mcp-scope="' + scope + '" data-mcp-name="' + escAttr(name) + '">' + (server.disabled ? 'Enable' : 'Disable') + '</button>' +
|
|
440
|
+
'<button class="mcp-btn mcp-btn-danger" data-mcp-action="remove" data-mcp-scope="' + scope + '" data-mcp-name="' + escAttr(name) + '">Remove</button>' +
|
|
441
|
+
'</div>' +
|
|
442
|
+
'</article>';
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function renderMcpPreset(scope, preset, servers) {
|
|
446
|
+
const installed = Boolean(servers[preset.serverName]);
|
|
447
|
+
const transport = preset.server.command ? 'Runs on host' : 'Remote service';
|
|
448
|
+
return '<article class="mcp-preset">' +
|
|
449
|
+
'<div class="mcp-preset-top">' +
|
|
450
|
+
'<span class="mcp-preset-category">' + escHtml(preset.category) + '</span>' +
|
|
451
|
+
(installed ? '<span class="mcp-badge mcp-badge-ok">Installed here</span>' : '') +
|
|
452
|
+
'</div>' +
|
|
453
|
+
'<h3>' + escHtml(preset.name) + '</h3>' +
|
|
454
|
+
'<p>' + escHtml(preset.description) + '</p>' +
|
|
455
|
+
'<div class="mcp-preset-meta">' + escHtml(transport) + ' · <code>' + escHtml(preset.serverName) + '</code></div>' +
|
|
456
|
+
'<div class="mcp-preset-actions">' +
|
|
457
|
+
'<a href="' + escAttr(preset.sourceUrl) + '" target="_blank" rel="noopener">Source ↗</a>' +
|
|
458
|
+
'<button class="primary-action-btn" data-mcp-action="preset" data-mcp-scope="' + scope + '" data-mcp-preset="' + escAttr(preset.id) + '">' + (installed ? 'Review' : 'Install') + '</button>' +
|
|
459
|
+
'</div>' +
|
|
460
|
+
'</article>';
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function renderMcpScope(el, scope, servers) {
|
|
464
|
+
const presets = mcpPresets.map((preset) => renderMcpPreset(scope, preset, servers)).join('');
|
|
465
|
+
const rows = Object.entries(servers).map(([name, server]) => renderMcpServer(scope, name, server)).join('');
|
|
466
|
+
el.innerHTML =
|
|
467
|
+
'<div class="mcp-market-head"><div><h3>Explore presets</h3><p>Reviewed recipes that install into this scope.</p></div><span>' + mcpPresets.length + ' available</span></div>' +
|
|
468
|
+
'<div class="mcp-preset-grid">' + presets + '</div>' +
|
|
469
|
+
'<details class="mcp-installed" open><summary>Installed in this scope</summary>' +
|
|
470
|
+
'<div class="mcp-preset-grid">' +
|
|
471
|
+
rows +
|
|
472
|
+
'<button type="button" class="mcp-add-card" data-mcp-action="open-custom" data-mcp-scope="' + scope + '">' +
|
|
473
|
+
'<span class="mcp-add-card-plus">+</span><span>新增 server</span>' +
|
|
474
|
+
'</button>' +
|
|
475
|
+
'</div>' +
|
|
476
|
+
'</details>';
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function renderMcpGuidedForm(scope) {
|
|
480
|
+
return '<div class="mcp-guided-grid">' +
|
|
481
|
+
'<label class="mcp-field"><span>Server 名稱</span><input id="mcp-' + scope + '-g-name" class="form-input mcp-json" placeholder="例如 github" autocomplete="off" /></label>' +
|
|
482
|
+
'<div class="mcp-transport-toggle">' +
|
|
483
|
+
'<label><input type="radio" name="mcp-' + scope + '-g-transport" value="stdio" checked /> 本機指令 (stdio)</label>' +
|
|
484
|
+
'<label><input type="radio" name="mcp-' + scope + '-g-transport" value="http" /> 遠端服務 (HTTP)</label>' +
|
|
485
|
+
'</div>' +
|
|
486
|
+
'<div id="mcp-' + scope + '-g-stdio" class="mcp-transport-fields">' +
|
|
487
|
+
'<label class="mcp-field"><span>指令</span><input id="mcp-' + scope + '-g-command" class="form-input mcp-json" placeholder="npx" autocomplete="off" /></label>' +
|
|
488
|
+
'<label class="mcp-field"><span>參數(以逗號分隔)</span><input id="mcp-' + scope + '-g-args" class="form-input mcp-json" placeholder="-y, @modelcontextprotocol/server-github" autocomplete="off" /></label>' +
|
|
489
|
+
'</div>' +
|
|
490
|
+
'<div id="mcp-' + scope + '-g-http" class="mcp-transport-fields" style="display:none">' +
|
|
491
|
+
'<label class="mcp-field"><span>URL</span><input id="mcp-' + scope + '-g-url" class="form-input mcp-json" placeholder="https://mcp.example.com/mcp" autocomplete="off" /></label>' +
|
|
492
|
+
'</div>' +
|
|
493
|
+
'<div class="mcp-kv-block">' +
|
|
494
|
+
'<div class="mcp-kv-head"><span id="mcp-' + scope + '-g-kv-label">環境變數 (env)</span><button type="button" class="mcp-btn" data-mcp-kv-add="' + scope + '">+ 新增一列</button></div>' +
|
|
495
|
+
'<div id="mcp-' + scope + '-g-kv" class="mcp-kv-rows"></div>' +
|
|
496
|
+
'</div>' +
|
|
497
|
+
'</div>';
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
function renderMcpKvRow() {
|
|
501
|
+
return '<div class="mcp-kv-row">' +
|
|
502
|
+
'<input class="form-input mcp-json" placeholder="KEY" data-kv-key autocomplete="off" />' +
|
|
503
|
+
'<input class="form-input mcp-json" type="password" placeholder="value" data-kv-value autocomplete="off" />' +
|
|
504
|
+
'<button type="button" class="mcp-btn mcp-btn-danger" data-mcp-kv-remove>移除</button>' +
|
|
505
|
+
'</div>';
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
function addMcpGuidedRow(scope) {
|
|
509
|
+
const container = document.getElementById('mcp-' + scope + '-g-kv');
|
|
510
|
+
if (container) container.insertAdjacentHTML('beforeend', renderMcpKvRow());
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function updateMcpGuidedTransport(scope) {
|
|
514
|
+
const checked = document.querySelector('input[name="mcp-' + scope + '-g-transport"]:checked');
|
|
515
|
+
const transport = checked ? checked.value : 'stdio';
|
|
516
|
+
const stdioEl = document.getElementById('mcp-' + scope + '-g-stdio');
|
|
517
|
+
const httpEl = document.getElementById('mcp-' + scope + '-g-http');
|
|
518
|
+
const kvLabel = document.getElementById('mcp-' + scope + '-g-kv-label');
|
|
519
|
+
if (stdioEl) stdioEl.style.display = transport === 'stdio' ? '' : 'none';
|
|
520
|
+
if (httpEl) httpEl.style.display = transport === 'http' ? '' : 'none';
|
|
521
|
+
if (kvLabel) kvLabel.textContent = transport === 'stdio' ? '環境變數 (env)' : 'HTTP Headers';
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
let pendingMcpCustomScope = null;
|
|
525
|
+
|
|
526
|
+
function openMcpCustomDialog(scope) {
|
|
527
|
+
pendingMcpCustomScope = scope;
|
|
528
|
+
const content = document.getElementById('mcp-custom-dialog-content');
|
|
529
|
+
content.innerHTML =
|
|
530
|
+
'<div class="mcp-add-mode">' +
|
|
531
|
+
'<button type="button" class="mcp-mode-btn active" data-mcp-mode="guided">引導式表單</button>' +
|
|
532
|
+
'<button type="button" class="mcp-mode-btn" data-mcp-mode="json">貼上 JSON</button>' +
|
|
533
|
+
'</div>' +
|
|
534
|
+
'<div id="mcp-custom-guided-panel" class="mcp-panel">' + renderMcpGuidedForm('custom') + '</div>' +
|
|
535
|
+
'<div id="mcp-custom-json-panel" class="mcp-panel" style="display:none">' +
|
|
536
|
+
'<p class="mcp-manual-hint">貼上 MCP server 文件給的 <code>mcpServers</code> JSON,原樣保存到這個 scope。remote 走 Streamable HTTP,local 走 stdio。</p>' +
|
|
537
|
+
'<textarea id="mcp-custom-json" class="form-input mcp-json" spellcheck="false" rows="9" placeholder="' + escAttr(MCP_JSON_PLACEHOLDER) + '"></textarea>' +
|
|
538
|
+
'</div>';
|
|
539
|
+
const dialogError = document.getElementById('mcp-custom-dialog-error');
|
|
540
|
+
dialogError.style.display = 'none';
|
|
541
|
+
dialogError.textContent = '';
|
|
542
|
+
addMcpGuidedRow('custom');
|
|
543
|
+
document.getElementById('mcp-custom-dialog').showModal();
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function closeMcpCustomDialog() {
|
|
547
|
+
pendingMcpCustomScope = null;
|
|
548
|
+
document.getElementById('mcp-custom-dialog').close();
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
function switchMcpCustomMode(mode) {
|
|
552
|
+
const guidedEl = document.getElementById('mcp-custom-guided-panel');
|
|
553
|
+
const jsonEl = document.getElementById('mcp-custom-json-panel');
|
|
554
|
+
if (guidedEl) guidedEl.style.display = mode === 'guided' ? '' : 'none';
|
|
555
|
+
if (jsonEl) jsonEl.style.display = mode === 'json' ? '' : 'none';
|
|
556
|
+
document.querySelectorAll('#mcp-custom-dialog-content [data-mcp-mode]').forEach((b) => {
|
|
557
|
+
b.classList.toggle('active', b.dataset.mcpMode === mode);
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
async function submitMcpCustomDialog(btn) {
|
|
562
|
+
const scope = pendingMcpCustomScope;
|
|
563
|
+
if (!scope) return;
|
|
564
|
+
const dialogError = document.getElementById('mcp-custom-dialog-error');
|
|
565
|
+
dialogError.style.display = 'none';
|
|
566
|
+
dialogError.textContent = '';
|
|
567
|
+
const jsonMode = document.getElementById('mcp-custom-json-panel').style.display !== 'none';
|
|
568
|
+
let json;
|
|
569
|
+
if (jsonMode) {
|
|
570
|
+
const raw = document.getElementById('mcp-custom-json').value.trim();
|
|
571
|
+
if (!raw) { dialogError.textContent = '請貼上 mcpServers JSON'; dialogError.style.display = 'block'; return; }
|
|
572
|
+
json = raw;
|
|
573
|
+
} else {
|
|
574
|
+
const nameEl = document.getElementById('mcp-custom-g-name');
|
|
575
|
+
const name = nameEl ? nameEl.value.trim() : '';
|
|
576
|
+
if (!name) { dialogError.textContent = '請輸入 server 名稱'; dialogError.style.display = 'block'; return; }
|
|
577
|
+
const checked = document.querySelector('input[name="mcp-custom-g-transport"]:checked');
|
|
578
|
+
const transport = checked ? checked.value : 'stdio';
|
|
579
|
+
const kv = {};
|
|
580
|
+
document.querySelectorAll('#mcp-custom-g-kv .mcp-kv-row').forEach((row) => {
|
|
581
|
+
const keyInput = row.querySelector('[data-kv-key]');
|
|
582
|
+
const valueInput = row.querySelector('[data-kv-value]');
|
|
583
|
+
const key = keyInput ? keyInput.value.trim() : '';
|
|
584
|
+
if (key) kv[key] = valueInput ? valueInput.value : '';
|
|
585
|
+
});
|
|
586
|
+
let entry;
|
|
587
|
+
if (transport === 'stdio') {
|
|
588
|
+
const commandEl = document.getElementById('mcp-custom-g-command');
|
|
589
|
+
const command = commandEl ? commandEl.value.trim() : '';
|
|
590
|
+
if (!command) { dialogError.textContent = '請輸入指令'; dialogError.style.display = 'block'; return; }
|
|
591
|
+
const argsEl = document.getElementById('mcp-custom-g-args');
|
|
592
|
+
const argsRaw = argsEl ? argsEl.value.trim() : '';
|
|
593
|
+
const args = argsRaw ? argsRaw.split(',').map((s) => s.trim()).filter(Boolean) : [];
|
|
594
|
+
entry = Object.assign({ command: command }, args.length ? { args: args } : {}, Object.keys(kv).length ? { env: kv } : {});
|
|
595
|
+
} else {
|
|
596
|
+
const urlEl = document.getElementById('mcp-custom-g-url');
|
|
597
|
+
const url = urlEl ? urlEl.value.trim() : '';
|
|
598
|
+
if (!url) { dialogError.textContent = '請輸入 URL'; dialogError.style.display = 'block'; return; }
|
|
599
|
+
entry = Object.assign({ url: url }, Object.keys(kv).length ? { headers: kv } : {});
|
|
600
|
+
}
|
|
601
|
+
json = JSON.stringify({ mcpServers: { [name]: entry } });
|
|
602
|
+
}
|
|
603
|
+
btn.disabled = true;
|
|
604
|
+
btn.textContent = '儲存中…';
|
|
605
|
+
try {
|
|
606
|
+
const data = await apiPost('/admin/api/mcp-servers/mutate', {
|
|
607
|
+
action: 'import', scope: scope, json: json, ...scopeBody(),
|
|
608
|
+
});
|
|
609
|
+
const results = Array.isArray(data.results) ? data.results : [];
|
|
610
|
+
const failed = results.filter((r) => r.error).length;
|
|
611
|
+
closeMcpCustomDialog();
|
|
612
|
+
mcpMessage(scope, failed ? '已儲存,但 ' + failed + ' 個 server 連線失敗,見上方選項維護。' : '已儲存並連線成功。', failed ? 'err' : 'ok');
|
|
613
|
+
await loadMcpServers();
|
|
614
|
+
} catch (err) {
|
|
615
|
+
dialogError.textContent = err.message;
|
|
616
|
+
dialogError.style.display = 'block';
|
|
617
|
+
} finally {
|
|
618
|
+
btn.disabled = false;
|
|
619
|
+
btn.textContent = '新增並測試連線';
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
const MCP_JSON_PLACEHOLDER = JSON.stringify({
|
|
624
|
+
mcpServers: {
|
|
625
|
+
browserless: {
|
|
626
|
+
type: 'http',
|
|
627
|
+
url: 'https://mcp.browserless.io/mcp',
|
|
628
|
+
headers: { Authorization: 'Bearer YOUR_API_TOKEN' },
|
|
629
|
+
},
|
|
630
|
+
},
|
|
631
|
+
}, null, 2);
|
|
632
|
+
|
|
633
|
+
const loadMcpServers = () => loadScopePanels('mcp', 'mcp-servers', (data, convEl, globalEl) => {
|
|
634
|
+
mcpPresets = Array.isArray(data.presets) ? data.presets : [];
|
|
635
|
+
mcpServersByScope = { conversation: data.conversation || {}, global: data.global || {} };
|
|
636
|
+
if (convEl) renderMcpScope(convEl, 'conversation', mcpServersByScope.conversation);
|
|
637
|
+
if (globalEl) renderMcpScope(globalEl, 'global', mcpServersByScope.global);
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
async function mutateMcpServer(scope, action, name, extra) {
|
|
641
|
+
mcpMessage(scope, action === 'test' ? '連線測試中…' : '儲存並測試連線中…', 'busy');
|
|
642
|
+
try {
|
|
643
|
+
const data = await apiPost('/admin/api/mcp-servers/mutate', {
|
|
644
|
+
action: action,
|
|
645
|
+
scope: scope,
|
|
646
|
+
name: name || undefined,
|
|
647
|
+
...(extra || {}),
|
|
648
|
+
...scopeBody(),
|
|
649
|
+
});
|
|
650
|
+
const results = Array.isArray(data.results) ? data.results : [];
|
|
651
|
+
const failed = results.filter((r) => r.error).length;
|
|
652
|
+
if (action === 'test') {
|
|
653
|
+
mcpMessage(scope, failed ? '✗ ' + name + ': ' + results[0].error : '✓ ' + name + ': ' + results[0].tools + ' tool(s)', failed ? 'err' : 'ok');
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
if (action === 'remove' || action === 'toggle') {
|
|
657
|
+
mcpMessage(scope, '完成。新設定在下一次回應生效。', 'ok');
|
|
658
|
+
} else {
|
|
659
|
+
mcpMessage(scope, failed ? '已儲存,但 ' + failed + ' 個 server 連線失敗,見下方錯誤。' : '已儲存並連線成功。', failed ? 'err' : 'ok');
|
|
660
|
+
}
|
|
661
|
+
await loadMcpServers();
|
|
662
|
+
} catch (err) {
|
|
663
|
+
mcpMessage(scope, err.message, 'err');
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
function openMcpPreset(scope, presetId) {
|
|
668
|
+
const preset = mcpPresets.find((item) => item.id === presetId);
|
|
669
|
+
if (!preset) return;
|
|
670
|
+
pendingMcpInstall = { scope: scope, preset: preset };
|
|
671
|
+
const local = Boolean(preset.server.command);
|
|
672
|
+
const installed = Boolean(mcpServersByScope[scope][preset.serverName]);
|
|
673
|
+
const credentials = preset.credentials.map((credential, index) =>
|
|
674
|
+
'<label class="mcp-credential"><span>' + escHtml(credential.label) + (credential.required ? ' *' : '') + '</span>' +
|
|
675
|
+
'<input data-mcp-credential="' + index + '" type="' + (credential.secret ? 'password' : 'text') + '" autocomplete="off" />' +
|
|
676
|
+
'<small>' + escHtml(credential.description) + '</small></label>'
|
|
677
|
+
).join('');
|
|
678
|
+
document.getElementById('mcp-dialog-title').textContent = preset.name;
|
|
679
|
+
const dialogError = document.getElementById('mcp-dialog-error');
|
|
680
|
+
dialogError.style.display = 'none';
|
|
681
|
+
dialogError.textContent = '';
|
|
682
|
+
document.getElementById('mcp-dialog-content').innerHTML =
|
|
683
|
+
'<p class="mcp-dialog-desc">' + escHtml(preset.description) + '</p>' +
|
|
684
|
+
'<div class="mcp-install-preview"><span>' + (local ? 'Host command' : 'Remote endpoint') + '</span><code>' + escHtml(mcpTransport(preset.server)) + '</code></div>' +
|
|
685
|
+
'<div class="mcp-security-note ' + (local ? 'local' : 'remote') + '">' +
|
|
686
|
+
(local
|
|
687
|
+
? '<strong>Host code execution.</strong> This command runs outside the conversation sandbox with the mikan process user permissions.'
|
|
688
|
+
: '<strong>External service.</strong> Tool calls and selected data will be sent to this remote origin.') +
|
|
689
|
+
'</div>' +
|
|
690
|
+
(installed ? '<div class="mcp-replace-note">Installing again replaces the existing <code>' + escHtml(preset.serverName) + '</code> entry in this scope.</div>' : '') +
|
|
691
|
+
(credentials || '<p class="mcp-no-credentials">No credentials required.</p>') +
|
|
692
|
+
'<p class="mcp-secret-note">These values are stored in host-private settings and are not shown to the model or sandbox.</p>' +
|
|
693
|
+
'<a class="mcp-setup-link" href="' + escAttr(preset.setupUrl) + '" target="_blank" rel="noopener">Setup documentation ↗</a>';
|
|
694
|
+
document.getElementById('mcp-install-dialog').showModal();
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
function closeMcpInstall() {
|
|
698
|
+
pendingMcpInstall = null;
|
|
699
|
+
document.getElementById('mcp-install-dialog').close();
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
async function installMcpPreset(btn) {
|
|
703
|
+
if (!pendingMcpInstall) return;
|
|
704
|
+
const { scope, preset } = pendingMcpInstall;
|
|
705
|
+
const credentials = {};
|
|
706
|
+
document.querySelectorAll('[data-mcp-credential]').forEach((input) => {
|
|
707
|
+
const descriptor = preset.credentials[Number(input.dataset.mcpCredential)];
|
|
708
|
+
if (descriptor) credentials[descriptor.key] = input.value;
|
|
709
|
+
});
|
|
710
|
+
btn.disabled = true;
|
|
711
|
+
btn.textContent = 'Installing…';
|
|
712
|
+
try {
|
|
713
|
+
const data = await apiPost('/admin/api/mcp-servers/mutate', {
|
|
714
|
+
action: 'install', scope: scope, presetId: preset.id, credentials: credentials, ...scopeBody(),
|
|
715
|
+
});
|
|
716
|
+
closeMcpInstall();
|
|
717
|
+
const result = (Array.isArray(data.results) ? data.results : [])[0];
|
|
718
|
+
if (result && result.error) mcpMessage(scope, '✗ ' + preset.name + ' saved but failed to connect: ' + result.error, 'err');
|
|
719
|
+
else mcpMessage(scope, '✓ ' + preset.name + ' installed, ' + (result ? result.tools : 0) + ' tool(s).', 'ok');
|
|
720
|
+
await loadMcpServers();
|
|
721
|
+
} catch (err) {
|
|
722
|
+
const dialogError = document.getElementById('mcp-dialog-error');
|
|
723
|
+
dialogError.textContent = err.message;
|
|
724
|
+
dialogError.style.display = 'block';
|
|
725
|
+
} finally {
|
|
726
|
+
btn.disabled = false;
|
|
727
|
+
btn.textContent = 'Install preset';
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
document.addEventListener('click', (event) => {
|
|
732
|
+
const modeBtn = event.target.closest('#mcp-custom-dialog-content [data-mcp-mode]');
|
|
733
|
+
if (modeBtn) { switchMcpCustomMode(modeBtn.dataset.mcpMode); return; }
|
|
734
|
+
const kvAddBtn = event.target.closest('[data-mcp-kv-add]');
|
|
735
|
+
if (kvAddBtn) { addMcpGuidedRow(kvAddBtn.dataset.mcpKvAdd); return; }
|
|
736
|
+
const kvRemoveBtn = event.target.closest('[data-mcp-kv-remove]');
|
|
737
|
+
if (kvRemoveBtn) { kvRemoveBtn.closest('.mcp-kv-row').remove(); return; }
|
|
738
|
+
const transportRadio = event.target.closest('input[name^="mcp-"][name$="-g-transport"]');
|
|
739
|
+
if (transportRadio) {
|
|
740
|
+
const match = /^mcp-(.+)-g-transport$/.exec(transportRadio.name);
|
|
741
|
+
if (match) updateMcpGuidedTransport(match[1]);
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
const btn = event.target.closest('[data-mcp-action]');
|
|
745
|
+
if (!btn) return;
|
|
746
|
+
if (btn.dataset.mcpAction === 'open-custom') { openMcpCustomDialog(btn.dataset.mcpScope); return; }
|
|
747
|
+
if (btn.dataset.mcpAction === 'preset') { openMcpPreset(btn.dataset.mcpScope, btn.dataset.mcpPreset); return; }
|
|
748
|
+
void mutateMcpServer(btn.dataset.mcpScope, btn.dataset.mcpAction, btn.dataset.mcpName);
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
let skillsCache = [];
|
|
752
|
+
|
|
753
|
+
function renderSkillsInto(containerId, skills, allowedSource) {
|
|
754
|
+
const container = document.getElementById(containerId);
|
|
755
|
+
if (!container) return;
|
|
756
|
+
const filtered = allowedSource ? skills.filter((s) => s.source === allowedSource) : skills;
|
|
757
|
+
if (filtered.length === 0) {
|
|
758
|
+
container.innerHTML = '<div class="empty-state">No skills available</div>';
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
container.innerHTML = '<div class="skills-list">' +
|
|
762
|
+
filtered.map((s) =>
|
|
763
|
+
'<div class="skill-row">' +
|
|
764
|
+
'<button class="skill-row-btn" data-skill-source="' + escAttr(s.source) + '" data-skill-directory="' + escAttr(s.directory) + '" data-skill-name="' + escAttr(s.name) + '">' +
|
|
765
|
+
'<div class="skill-name">' + escHtml(s.name) + '<span class="skill-source skill-source-' + s.source + '">' + s.source + '</span></div>' +
|
|
766
|
+
(s.description ? '<div class="skill-desc">' + escHtml(s.description) + '</div>' : '') +
|
|
767
|
+
'</button>' +
|
|
768
|
+
'<div class="skill-row-actions">' +
|
|
769
|
+
'<button class="mcp-btn" data-skill-edit-source="' + escAttr(s.source) + '" data-skill-edit-directory="' + escAttr(s.directory) + '">Edit</button>' +
|
|
770
|
+
'<button class="mcp-btn mcp-btn-danger" data-skill-delete-source="' + escAttr(s.source) + '" data-skill-delete-directory="' + escAttr(s.directory) + '" data-skill-delete-name="' + escAttr(s.name) + '">Delete</button>' +
|
|
771
|
+
'</div>' +
|
|
772
|
+
'</div>'
|
|
773
|
+
).join('') + '</div>';
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
async function loadSkills() {
|
|
777
|
+
const container = document.getElementById('skills-content');
|
|
778
|
+
const previewEl = document.getElementById('skills-preview');
|
|
779
|
+
container.innerHTML = '<div class="loading-msg">Loading…</div>';
|
|
780
|
+
if (previewEl) previewEl.innerHTML = '<div class="placeholder-msg">Click a skill to preview SKILL.md</div>';
|
|
781
|
+
try {
|
|
782
|
+
const data = await apiGet('/admin/api/skills?' + scopeQuery());
|
|
783
|
+
skillsCache = Array.isArray(data.skills) ? data.skills : [];
|
|
784
|
+
renderSkillsInto('skills-content', skillsCache);
|
|
785
|
+
renderSkillsInto('global-skills-content', skillsCache, 'global');
|
|
786
|
+
} catch (err) {
|
|
787
|
+
container.innerHTML = '<div class="err-msg">' + escHtml(err.message) + '</div>';
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
const loadGlobalSkills = loadSkills;
|
|
792
|
+
|
|
793
|
+
async function previewSkillInto(previewId, source, directory, name) {
|
|
794
|
+
const previewEl = document.getElementById(previewId);
|
|
795
|
+
if (!previewEl) return;
|
|
796
|
+
if (!source || !directory) {
|
|
797
|
+
previewEl.innerHTML = '<div class="err-msg">Missing skill source or directory</div>';
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
previewEl.innerHTML = '<div class="loading-msg">Loading ' + escHtml(name || directory) + '…</div>';
|
|
801
|
+
try {
|
|
802
|
+
const data = await apiGet('/admin/api/skills/file?' + scopeQuery() + '&source=' + encodeURIComponent(source) + '&directory=' + encodeURIComponent(directory));
|
|
803
|
+
renderPreviewFileResult(previewEl, source + '/' + directory + '/SKILL.md', data);
|
|
804
|
+
} catch (err) {
|
|
805
|
+
previewEl.innerHTML = '<div class="err-msg">' + escHtml(err.message) + '</div>';
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
async function deleteSkill(source, directory, name) {
|
|
810
|
+
if (!confirm('Delete skill "' + (name || directory) + '" (' + source + ')?')) return;
|
|
811
|
+
try {
|
|
812
|
+
await apiPost('/admin/api/skills/mutate', { action: 'delete', source: source, directory: directory, ...scopeBody() });
|
|
813
|
+
await loadSkills();
|
|
814
|
+
} catch (err) {
|
|
815
|
+
alert(err.message);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
function bindSkillListEvents(containerId, previewId) {
|
|
820
|
+
const el = document.getElementById(containerId);
|
|
821
|
+
if (!el) return;
|
|
822
|
+
el.addEventListener('click', (event) => {
|
|
823
|
+
const previewBtn = event.target.closest('[data-skill-source]');
|
|
824
|
+
if (previewBtn) {
|
|
825
|
+
previewSkillInto(previewId, previewBtn.dataset.skillSource, previewBtn.dataset.skillDirectory, previewBtn.dataset.skillName);
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
const editBtn = event.target.closest('[data-skill-edit-source]');
|
|
829
|
+
if (editBtn) {
|
|
830
|
+
const skill = skillsCache.find((s) => s.source === editBtn.dataset.skillEditSource && s.directory === editBtn.dataset.skillEditDirectory);
|
|
831
|
+
if (skill) void openSkillDialog(skill.source, skill);
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
const deleteBtn = event.target.closest('[data-skill-delete-source]');
|
|
835
|
+
if (deleteBtn) {
|
|
836
|
+
void deleteSkill(deleteBtn.dataset.skillDeleteSource, deleteBtn.dataset.skillDeleteDirectory, deleteBtn.dataset.skillDeleteName);
|
|
837
|
+
}
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
bindSkillListEvents('skills-content', 'skills-preview');
|
|
841
|
+
bindSkillListEvents('global-skills-content', 'global-skills-preview');
|
|
842
|
+
|
|
843
|
+
let editingSkill = null;
|
|
844
|
+
let pendingSkillScope = null;
|
|
845
|
+
|
|
846
|
+
async function openSkillDialog(scope, existing) {
|
|
847
|
+
editingSkill = existing ? { source: existing.source, directory: existing.directory } : null;
|
|
848
|
+
document.getElementById('skill-dialog-eyebrow').textContent = scope === 'global' ? 'Global skill' : 'Conversation skill';
|
|
849
|
+
document.getElementById('skill-dialog-title').textContent = existing ? 'Edit skill' : 'New skill';
|
|
850
|
+
const dirInput = document.getElementById('skill-dialog-directory');
|
|
851
|
+
dirInput.value = existing ? existing.directory : '';
|
|
852
|
+
dirInput.disabled = Boolean(existing);
|
|
853
|
+
document.getElementById('skill-dialog-name').value = existing ? existing.name : '';
|
|
854
|
+
document.getElementById('skill-dialog-description').value = existing ? existing.description : '';
|
|
855
|
+
const contentEl = document.getElementById('skill-dialog-content');
|
|
856
|
+
contentEl.value = '';
|
|
857
|
+
const dialogError = document.getElementById('skill-dialog-error');
|
|
858
|
+
dialogError.style.display = 'none';
|
|
859
|
+
dialogError.textContent = '';
|
|
860
|
+
pendingSkillScope = scope;
|
|
861
|
+
if (existing) {
|
|
862
|
+
contentEl.value = 'Loading…';
|
|
863
|
+
try {
|
|
864
|
+
const data = await apiGet('/admin/api/skills/file?' + scopeQuery() + '&source=' + encodeURIComponent(existing.source) + '&directory=' + encodeURIComponent(existing.directory));
|
|
865
|
+
contentEl.value = data.binary ? '' : (data.content || '').replace(/^---[\\s\\S]*?---\\n?/, '').trim();
|
|
866
|
+
} catch (err) {
|
|
867
|
+
contentEl.value = '';
|
|
868
|
+
dialogError.textContent = 'Failed to load current content: ' + err.message;
|
|
869
|
+
dialogError.style.display = 'block';
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
document.getElementById('skill-dialog').showModal();
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
function closeSkillDialog() {
|
|
876
|
+
editingSkill = null;
|
|
877
|
+
pendingSkillScope = null;
|
|
878
|
+
document.getElementById('skill-dialog').close();
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
async function submitSkillDialog(btn) {
|
|
882
|
+
const dialogError = document.getElementById('skill-dialog-error');
|
|
883
|
+
dialogError.style.display = 'none';
|
|
884
|
+
dialogError.textContent = '';
|
|
885
|
+
const directory = document.getElementById('skill-dialog-directory').value.trim();
|
|
886
|
+
const name = document.getElementById('skill-dialog-name').value.trim() || directory;
|
|
887
|
+
const description = document.getElementById('skill-dialog-description').value.trim();
|
|
888
|
+
const content = document.getElementById('skill-dialog-content').value;
|
|
889
|
+
if (!directory) { dialogError.textContent = 'Directory is required'; dialogError.style.display = 'block'; return; }
|
|
890
|
+
if (!description) { dialogError.textContent = 'Description is required'; dialogError.style.display = 'block'; return; }
|
|
891
|
+
const source = editingSkill ? editingSkill.source : pendingSkillScope;
|
|
892
|
+
btn.disabled = true;
|
|
893
|
+
btn.textContent = 'Saving…';
|
|
894
|
+
try {
|
|
895
|
+
await apiPost('/admin/api/skills/mutate', {
|
|
896
|
+
action: 'save', source: source, directory: directory, name: name, description: description, content: content, ...scopeBody(),
|
|
897
|
+
});
|
|
898
|
+
closeSkillDialog();
|
|
899
|
+
await loadSkills();
|
|
900
|
+
} catch (err) {
|
|
901
|
+
dialogError.textContent = err.message;
|
|
902
|
+
dialogError.style.display = 'block';
|
|
903
|
+
} finally {
|
|
904
|
+
btn.disabled = false;
|
|
905
|
+
btn.textContent = 'Save';
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
|
|
910
|
+
const openLogin = (silent) => openPortalLink('vault', 'login', silent);
|
|
911
|
+
const openSessionView = (silent) => openPortalLink('session', 'session', silent);
|
|
912
|
+
|
|
913
|
+
async function openPortalLink(resultId, kind, silent) {
|
|
914
|
+
const result = document.getElementById(resultId + '-link-result');
|
|
915
|
+
if (silent) { result.style.display = 'none'; return; }
|
|
916
|
+
result.style.display = 'block'; result.className = 'link-result loading'; result.textContent = 'Generating link…';
|
|
917
|
+
try {
|
|
918
|
+
const data = await apiPost('/admin/api/conversations/' + kind + '-link', scopeBody());
|
|
919
|
+
result.className = 'link-result ok';
|
|
920
|
+
result.innerHTML =
|
|
921
|
+
(kind === 'login' ? '<span class="link-vault">vault: <code>' + escHtml(data.vaultId) + '</code></span>' : '') +
|
|
922
|
+
'<a href="' + escAttr(data.url) + '" target="_blank" rel="noopener">' + escHtml(data.url) + '</a>' +
|
|
923
|
+
'<button class="copy-link-btn" data-admin-action="copy-link" data-copy-text="' + escAttr(data.url) + '">Copy</button>';
|
|
924
|
+
window.open(data.url, '_blank', 'noopener');
|
|
925
|
+
} catch (err) {
|
|
926
|
+
result.className = 'link-result err'; result.textContent = err.message;
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
|
|
931
|
+
const loadConversationEvents = () => loadEventList(true);
|
|
932
|
+
const loadEvents = () => loadEventList(false);
|
|
933
|
+
|
|
934
|
+
async function loadEventList(conversation) {
|
|
935
|
+
const container = document.getElementById(conversation ? 'events-content' : 'global-events-content');
|
|
936
|
+
if (!container) return;
|
|
937
|
+
container.innerHTML = '<div class="loading-msg">Loading…</div>';
|
|
938
|
+
try {
|
|
939
|
+
const data = await apiGet(conversation ? '/admin/api/conversations/events?' + scopeQuery() : '/admin/api/events');
|
|
940
|
+
if (data.events.length === 0) {
|
|
941
|
+
container.innerHTML = '<div class="empty-state">' + (conversation ? '沒有關聯此對話的 event' : 'No events scheduled') + '</div>';
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
container.innerHTML = '<div class="events-list">' +
|
|
945
|
+
data.events.map((e) => renderEventRow(e, conversation)).join('') + '</div>';
|
|
946
|
+
} catch (err) {
|
|
947
|
+
container.innerHTML = '<div class="err-msg">' + escHtml(err.message) + '</div>';
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
function renderEventRow(e, allowDelete) {
|
|
952
|
+
const meta = [e.type, e.platform, e.conversationId, e.schedule || e.at]
|
|
953
|
+
.filter(Boolean).map(escHtml).join(' · ');
|
|
954
|
+
const preview = e.text ? '<div class="event-text">' + escHtml(e.text.length > 240 ? e.text.slice(0, 237) + '…' : e.text) + '</div>' : '';
|
|
955
|
+
const deleteBtn = allowDelete
|
|
956
|
+
? '<button class="event-delete-btn" data-admin-action="delete-event" data-event-name="' + escAttr(e.name) + '">Delete</button>'
|
|
957
|
+
: '';
|
|
958
|
+
return '<div class="event-row">' +
|
|
959
|
+
'<div class="event-row-top">' +
|
|
960
|
+
'<div class="event-name"><code>' + escHtml(e.name) + '</code></div>' +
|
|
961
|
+
deleteBtn +
|
|
962
|
+
'</div>' +
|
|
963
|
+
'<div class="event-meta">' + meta + '</div>' +
|
|
964
|
+
preview +
|
|
965
|
+
'</div>';
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
async function deleteEvent(name, btn) {
|
|
969
|
+
if (!confirm('Delete event "' + name + '"?')) return;
|
|
970
|
+
btn.disabled = true; btn.textContent = 'Deleting…';
|
|
971
|
+
try {
|
|
972
|
+
await apiPost('/admin/api/conversations/events/delete', {
|
|
973
|
+
...scopeBody(), name,
|
|
974
|
+
});
|
|
975
|
+
await loadConversationEvents();
|
|
976
|
+
} catch (err) {
|
|
977
|
+
btn.disabled = false; btn.textContent = 'Delete';
|
|
978
|
+
alert(err.message);
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
|
|
983
|
+
function initGlobal() {}
|
|
984
|
+
|
|
985
|
+
async function loadAllConversations() {
|
|
986
|
+
const container = document.getElementById('all-conv-content');
|
|
987
|
+
container.innerHTML = '<div class="loading-msg">Loading…</div>';
|
|
988
|
+
try {
|
|
989
|
+
const data = await apiGet('/admin/api/conversations');
|
|
990
|
+
if (data.conversations.length === 0) {
|
|
991
|
+
container.innerHTML = '<div class="empty-state">No conversations found</div>';
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
994
|
+
container.innerHTML = '<div class="conv-list">' + data.conversations.map((c) => {
|
|
995
|
+
const last = c.lastActivityAt ? new Date(c.lastActivityAt).toLocaleString() : '—';
|
|
996
|
+
return '<button class="conv-row-btn" data-admin-action="select-conversation" data-conversation-id="' + escAttr(c.conversationId) + '">' +
|
|
997
|
+
'<span class="conv-id">' + escHtml(c.label || c.conversationId) + '</span>' +
|
|
998
|
+
(c.running ? '<span class="status-pill running">running</span>' : '') +
|
|
999
|
+
'<span class="conv-last">' + escHtml(last) + '</span>' +
|
|
1000
|
+
'</button>';
|
|
1001
|
+
}).join('') + '</div>';
|
|
1002
|
+
} catch (err) {
|
|
1003
|
+
container.innerHTML = '<div class="err-msg">' + escHtml(err.message) + '</div>';
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
async function loadSessionUsage() {
|
|
1008
|
+
const container = document.getElementById('session-usage-content');
|
|
1009
|
+
container.innerHTML = '<div class="loading-msg">Loading…</div>';
|
|
1010
|
+
try {
|
|
1011
|
+
const data = await apiGet('/admin/api/session-usage');
|
|
1012
|
+
if (data.sessions.length === 0) {
|
|
1013
|
+
container.innerHTML = '<div class="empty-state">No token usage found</div>';
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
container.innerHTML = '<div class="usage-table-wrap"><table class="usage-table"><thead><tr><th>#</th><th>Channel</th><th>Session</th><th>Updated</th><th>Input</th><th>Output</th><th>Cache Read</th><th>Cache Write</th><th>Total</th><th>Cost</th></tr></thead><tbody>' +
|
|
1017
|
+
data.sessions.map((s, i) => '<tr>' +
|
|
1018
|
+
'<td>' + (i + 1) + '</td>' +
|
|
1019
|
+
'<td>' + escHtml(s.label || s.conversationId) + '</td>' +
|
|
1020
|
+
'<td><code>' + escHtml(s.sessionKey) + '</code></td>' +
|
|
1021
|
+
'<td>' + escHtml(new Date(s.updatedAt).toLocaleString()) + '</td>' +
|
|
1022
|
+
'<td>' + fmtNum(s.input) + '</td>' +
|
|
1023
|
+
'<td>' + fmtNum(s.output) + '</td>' +
|
|
1024
|
+
'<td>' + fmtNum(s.cacheRead) + '</td>' +
|
|
1025
|
+
'<td>' + fmtNum(s.cacheWrite) + '</td>' +
|
|
1026
|
+
'<td><strong>' + fmtNum(s.total) + '</strong></td>' +
|
|
1027
|
+
'<td>' + (s.cost > 0 ? '$' + Number(s.cost).toFixed(4) : '—') + '</td>' +
|
|
1028
|
+
'</tr>').join('') + '</tbody></table></div>';
|
|
1029
|
+
} catch (err) {
|
|
1030
|
+
container.innerHTML = '<div class="err-msg">' + escHtml(err.message) + '</div>';
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
function fmtNum(value) {
|
|
1035
|
+
return Number(value || 0).toLocaleString('en-US');
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
let timelineConvLoaded = false;
|
|
1039
|
+
let timelineData = null;
|
|
1040
|
+
let timelineFilter = null;
|
|
1041
|
+
async function ensureTimelineConvOptions() {
|
|
1042
|
+
if (timelineConvLoaded) return;
|
|
1043
|
+
const sel = document.getElementById('timeline-conv');
|
|
1044
|
+
const prev = sel.value;
|
|
1045
|
+
const data = await apiGet('/admin/api/conversations');
|
|
1046
|
+
if (!data.conversations.length) {
|
|
1047
|
+
sel.innerHTML = '<option value="">No conversations</option>';
|
|
1048
|
+
timelineConvLoaded = true;
|
|
1049
|
+
return;
|
|
1050
|
+
}
|
|
1051
|
+
const want = prev || defaultConversationKey;
|
|
1052
|
+
sel.innerHTML = data.conversations.map((c) => {
|
|
1053
|
+
const key = c.platform + ':' + c.conversationId;
|
|
1054
|
+
return '<option value="' + escAttr(key) + '"' +
|
|
1055
|
+
(key === want ? ' selected' : '') + '>' +
|
|
1056
|
+
escHtml(c.label || c.conversationId) + '</option>';
|
|
1057
|
+
}).join('');
|
|
1058
|
+
timelineConvLoaded = true;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
async function loadTokenUsage() {
|
|
1062
|
+
loadSessionUsage();
|
|
1063
|
+
timelineConvLoaded = false;
|
|
1064
|
+
await loadUsageTimeline();
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
async function loadUsageTimeline() {
|
|
1068
|
+
const container = document.getElementById('usage-timeline-content');
|
|
1069
|
+
try {
|
|
1070
|
+
await ensureTimelineConvOptions();
|
|
1071
|
+
const conv = document.getElementById('timeline-conv').value;
|
|
1072
|
+
if (!conv) {
|
|
1073
|
+
container.innerHTML = '<div class="empty-state">No conversations found</div>';
|
|
1074
|
+
return;
|
|
1075
|
+
}
|
|
1076
|
+
container.innerHTML = '<div class="loading-msg">Loading…</div>';
|
|
1077
|
+
const convScope = scopeOf(conv);
|
|
1078
|
+
const data = await apiGet('/admin/api/conversation-usage?conversationId=' +
|
|
1079
|
+
encodeURIComponent(convScope.conversationId) +
|
|
1080
|
+
'&platform=' + encodeURIComponent(convScope.platform));
|
|
1081
|
+
timelineData = data;
|
|
1082
|
+
container.innerHTML = renderUsageTimeline(data);
|
|
1083
|
+
} catch (err) {
|
|
1084
|
+
container.innerHTML = '<div class="err-msg">' + escHtml(err.message) + '</div>';
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
function tlCard(label, value) {
|
|
1089
|
+
return '<div class="tl-card"><div class="tl-card-label">' + label +
|
|
1090
|
+
'</div><div class="tl-card-value">' + value + '</div></div>';
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
const TL_SERIES = [
|
|
1094
|
+
{ key: 'cacheRead', seg: 'tl-cache-read', sw: 'sw-cache-read', label: 'Cache read' },
|
|
1095
|
+
{ key: 'cacheWrite', seg: 'tl-cache-write', sw: 'sw-cache-write', label: 'Cache write' },
|
|
1096
|
+
{ key: 'input', seg: 'tl-input', sw: 'sw-input', label: 'Input' },
|
|
1097
|
+
{ key: 'output', seg: 'tl-output', sw: 'sw-output', label: 'Output' },
|
|
1098
|
+
];
|
|
1099
|
+
|
|
1100
|
+
function toggleTimelineFilter(key) {
|
|
1101
|
+
timelineFilter = timelineFilter === key ? null : key;
|
|
1102
|
+
if (timelineData) {
|
|
1103
|
+
document.getElementById('usage-timeline-content').innerHTML = renderUsageTimeline(timelineData);
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
function renderUsageTimeline(data) {
|
|
1108
|
+
const buckets = data.buckets || [];
|
|
1109
|
+
const totals = data.totals || { total: 0, cost: 0, cacheRead: 0 };
|
|
1110
|
+
const cacheHit = totals.total > 0 ? Math.round((totals.cacheRead / totals.total) * 100) : 0;
|
|
1111
|
+
const cards = '<div class="tl-cards">' +
|
|
1112
|
+
tlCard('Total cost', totals.cost > 0 ? '$' + Number(totals.cost).toFixed(4) : '—') +
|
|
1113
|
+
tlCard('Total tokens', fmtNum(totals.total)) +
|
|
1114
|
+
tlCard('Cache hit', cacheHit + '%') +
|
|
1115
|
+
'</div>';
|
|
1116
|
+
|
|
1117
|
+
if (totals.total === 0) {
|
|
1118
|
+
const emptyNote = data.hasOlder
|
|
1119
|
+
? '<div class="tl-note">No usage in the last 14 days · earlier activity exists</div>'
|
|
1120
|
+
: '<div class="empty-state">No token usage in the last 14 days</div>';
|
|
1121
|
+
return cards + emptyNote;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
const active = TL_SERIES.find((s) => s.key === timelineFilter) || null;
|
|
1125
|
+
const valueOf = (b) => active ? (b[active.key] || 0) : b.total;
|
|
1126
|
+
const max = Math.max(1, ...buckets.map(valueOf));
|
|
1127
|
+
const px = (v) => Math.round((v / max) * 180);
|
|
1128
|
+
|
|
1129
|
+
const legend = '<div class="tl-legend">' + TL_SERIES.map((s) => {
|
|
1130
|
+
const cls = 'tl-legend-item' +
|
|
1131
|
+
(active && active.key === s.key ? ' active' : (active ? ' dim' : ''));
|
|
1132
|
+
return '<span class="' + cls + '" data-admin-action="toggle-timeline-filter" data-filter-key="' + escAttr(s.key) + '">' +
|
|
1133
|
+
'<i class="sw ' + s.sw + '"></i>' + s.label + '</span>';
|
|
1134
|
+
}).join('') + '</div>';
|
|
1135
|
+
|
|
1136
|
+
const bars = buckets.map((b) => {
|
|
1137
|
+
const val = valueOf(b);
|
|
1138
|
+
const tip = active
|
|
1139
|
+
? b.date + ' · ' + active.label + ': ' + fmtNum(b[active.key] || 0) + ' tokens'
|
|
1140
|
+
: b.date + ' · ' + fmtNum(b.total) + ' tokens' +
|
|
1141
|
+
(b.cost > 0 ? ' · $' + Number(b.cost).toFixed(4) : '');
|
|
1142
|
+
let inner;
|
|
1143
|
+
if (val <= 0) {
|
|
1144
|
+
inner = '<span class="tl-empty"></span>';
|
|
1145
|
+
} else if (active) {
|
|
1146
|
+
inner = '<span class="tl-seg ' + active.seg + '" style="height:' + px(val) + 'px"></span>';
|
|
1147
|
+
} else {
|
|
1148
|
+
inner = '<span class="tl-seg tl-output" style="height:' + px(b.output) + 'px"></span>' +
|
|
1149
|
+
'<span class="tl-seg tl-input" style="height:' + px(b.input) + 'px"></span>' +
|
|
1150
|
+
'<span class="tl-seg tl-cache-write" style="height:' + px(b.cacheWrite) + 'px"></span>' +
|
|
1151
|
+
'<span class="tl-seg tl-cache-read" style="height:' + px(b.cacheRead) + 'px"></span>';
|
|
1152
|
+
}
|
|
1153
|
+
return '<div class="tl-bar">' +
|
|
1154
|
+
'<span class="tl-tip">' + escHtml(tip) + '</span>' +
|
|
1155
|
+
'<div class="tl-fill">' + inner + '</div>' +
|
|
1156
|
+
'</div>';
|
|
1157
|
+
}).join('');
|
|
1158
|
+
|
|
1159
|
+
const axis = buckets.length
|
|
1160
|
+
? '<div class="tl-axis"><span>' + escHtml(buckets[0].date.slice(5)) +
|
|
1161
|
+
'</span><span>' + escHtml(buckets[buckets.length - 1].date.slice(5)) + '</span></div>'
|
|
1162
|
+
: '';
|
|
1163
|
+
const note = data.hasOlder
|
|
1164
|
+
? '<div class="tl-note">Showing last 14 days · earlier activity not shown</div>'
|
|
1165
|
+
: '<div class="tl-note">Showing last 14 days</div>';
|
|
1166
|
+
const peak = '<div class="tl-peak" style="bottom:180px"><span class="tl-peak-label">' +
|
|
1167
|
+
fmtNum(max) + ' tokens</span></div>';
|
|
1168
|
+
return cards + legend + '<div class="tl-chart">' + peak + bars + '</div>' + axis + note;
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
function renderGlobalSettings(data) {
|
|
1172
|
+
const thinkingOpts = renderThinkingOptions(data.thinkingLevel);
|
|
1173
|
+
const replyModeOpts = renderReplyOptions(data.slack);
|
|
1174
|
+
return [
|
|
1175
|
+
'<div class="config-grid">',
|
|
1176
|
+
renderConfigCard('Default model', [
|
|
1177
|
+
'<div class="config-row config-row-stack"><label>Model</label><select id="g-model-ref">' + renderModelOptions(data.provider, data.model) + '</select></div>',
|
|
1178
|
+
'<div class="config-row"><label>Thinking</label><select id="g-thinking">' + thinkingOpts + '</select></div>',
|
|
1179
|
+
].join(''), 'saveGlobalModel', 'Save model', 'g-model-result'),
|
|
1180
|
+
renderConfigCard('Sandbox limits', [
|
|
1181
|
+
'<div class="config-row"><label>CPUs</label><input id="g-cpus" placeholder="0.5" value="' + escAttr(data.sandboxCpus || '') + '"></div>',
|
|
1182
|
+
'<div class="config-row"><label>Memory</label><input id="g-mem" placeholder="1g" value="' + escAttr(data.sandboxMemory || '') + '"></div>',
|
|
1183
|
+
'<div class="config-row"><label>Boost CPUs</label><input id="g-bcpus" placeholder="2" value="' + escAttr(data.sandboxBoostCpus || '') + '"></div>',
|
|
1184
|
+
'<div class="config-row"><label>Boost Mem</label><input id="g-bmem" placeholder="4g" value="' + escAttr(data.sandboxBoostMemory || '') + '"></div>',
|
|
1185
|
+
].join(''), 'saveGlobalSandbox', 'Save sandbox', 'g-sandbox-result'),
|
|
1186
|
+
renderConfigCard('Slack', [
|
|
1187
|
+
'<div class="config-row"><label>Reply mode</label><select id="g-slack-reply-mode">' + replyModeOpts + '</select></div>',
|
|
1188
|
+
].join(''), 'saveGlobalSlack', 'Save Slack', 'g-slack-result'),
|
|
1189
|
+
'</div>',
|
|
1190
|
+
].join('');
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
async function saveGlobalModel(btn) {
|
|
1194
|
+
const selectedModel = parseModelRef(document.getElementById('g-model-ref').value.trim());
|
|
1195
|
+
const provider = selectedModel.provider;
|
|
1196
|
+
const model = selectedModel.model;
|
|
1197
|
+
const thinkingLevel = document.getElementById('g-thinking').value;
|
|
1198
|
+
const result = document.getElementById('g-model-result');
|
|
1199
|
+
if (!provider || !model) {
|
|
1200
|
+
result.style.display = 'block'; result.className = 'inline-result err';
|
|
1201
|
+
result.textContent = 'Provider and model are required'; return;
|
|
1202
|
+
}
|
|
1203
|
+
btn.disabled = true; btn.textContent = 'Saving…'; result.style.display = 'none';
|
|
1204
|
+
try {
|
|
1205
|
+
await apiPost('/admin/api/settings/model', { provider, model, thinkingLevel });
|
|
1206
|
+
result.style.display = 'block'; result.className = 'inline-result ok'; result.textContent = 'Saved ✓';
|
|
1207
|
+
} catch (err) {
|
|
1208
|
+
result.style.display = 'block'; result.className = 'inline-result err'; result.textContent = err.message;
|
|
1209
|
+
} finally {
|
|
1210
|
+
btn.disabled = false; btn.textContent = 'Save model';
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
async function saveGlobalSandbox(btn) {
|
|
1215
|
+
const cpus = document.getElementById('g-cpus').value.trim();
|
|
1216
|
+
const memory = document.getElementById('g-mem').value.trim();
|
|
1217
|
+
const boostCpus = document.getElementById('g-bcpus').value.trim();
|
|
1218
|
+
const boostMemory = document.getElementById('g-bmem').value.trim();
|
|
1219
|
+
const result = document.getElementById('g-sandbox-result');
|
|
1220
|
+
await saveSetting(btn, result, 'settings/sandbox', { cpus, memory, boostCpus, boostMemory }, 'Save sandbox');
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
async function saveGlobalSlack(btn) {
|
|
1224
|
+
const replyMode = document.getElementById('g-slack-reply-mode').value;
|
|
1225
|
+
const result = document.getElementById('g-slack-result');
|
|
1226
|
+
await saveSetting(btn, result, 'settings/slack', { replyMode }, 'Save Slack');
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
`;
|
|
1230
|
+
export const adminViewStartupScript = ` initConvSwitcher();
|
|
1231
|
+
initRailNav();
|
|
1232
|
+
`;
|
|
1233
|
+
export const adminViewStyles = `
|
|
1234
|
+
|
|
1235
|
+
.shell { max-width: 1180px; }
|
|
1236
|
+
|
|
1237
|
+
|
|
1238
|
+
|
|
1239
|
+
.settings-shell {
|
|
1240
|
+
display: grid;
|
|
1241
|
+
grid-template-columns: 216px 1fr;
|
|
1242
|
+
align-items: start;
|
|
1243
|
+
gap: 22px;
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
.settings-rail {
|
|
1247
|
+
position: sticky;
|
|
1248
|
+
top: 28px;
|
|
1249
|
+
display: flex;
|
|
1250
|
+
flex-direction: column;
|
|
1251
|
+
gap: 16px;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
.rail-scope {
|
|
1255
|
+
display: flex;
|
|
1256
|
+
padding: 3px;
|
|
1257
|
+
border: 1px solid var(--border);
|
|
1258
|
+
border-radius: 11px;
|
|
1259
|
+
background: rgba(0,0,0,0.03);
|
|
1260
|
+
gap: 2px;
|
|
1261
|
+
}
|
|
1262
|
+
.rail-scope-btn {
|
|
1263
|
+
flex: 1;
|
|
1264
|
+
padding: 7px 8px;
|
|
1265
|
+
border: none;
|
|
1266
|
+
border-radius: 8px;
|
|
1267
|
+
background: transparent;
|
|
1268
|
+
color: var(--muted);
|
|
1269
|
+
font: 600 0.72rem/1.2 'DM Sans', sans-serif;
|
|
1270
|
+
letter-spacing: 0.01em;
|
|
1271
|
+
cursor: pointer;
|
|
1272
|
+
transition: background 140ms, color 140ms;
|
|
1273
|
+
}
|
|
1274
|
+
.rail-scope-btn:hover { color: var(--text); }
|
|
1275
|
+
.rail-scope-btn.active { background: var(--surface); color: var(--text); box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
|
|
1276
|
+
.rail-scope-btn:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }
|
|
1277
|
+
|
|
1278
|
+
.rail-nav { display: flex; flex-direction: column; gap: 1px; }
|
|
1279
|
+
.rail-nav[hidden] { display: none; }
|
|
1280
|
+
.rail-link {
|
|
1281
|
+
display: flex; align-items: center; gap: 10px;
|
|
1282
|
+
padding: 8px 10px; border: none; border-radius: 9px;
|
|
1283
|
+
background: transparent; color: var(--muted); text-align: left;
|
|
1284
|
+
font: 500 0.86rem/1.2 'DM Sans', sans-serif; cursor: pointer;
|
|
1285
|
+
transition: background 120ms, color 120ms;
|
|
1286
|
+
}
|
|
1287
|
+
.rail-link svg { flex-shrink: 0; opacity: 0.75; }
|
|
1288
|
+
.rail-link:hover { background: rgba(0,0,0,0.045); color: var(--text); }
|
|
1289
|
+
.rail-link:hover svg { opacity: 1; }
|
|
1290
|
+
.rail-link.active {
|
|
1291
|
+
background: var(--text); color: #fafafa; font-weight: 600;
|
|
1292
|
+
}
|
|
1293
|
+
.rail-link.active svg { opacity: 1; }
|
|
1294
|
+
.rail-link:focus-visible { outline: 2px solid var(--text); outline-offset: 1px; }
|
|
1295
|
+
|
|
1296
|
+
.settings-panels { min-width: 0; }
|
|
1297
|
+
.tab-panel { display: none; flex-direction: column; gap: 0; }
|
|
1298
|
+
.tab-panel.active { display: flex; }
|
|
1299
|
+
|
|
1300
|
+
|
|
1301
|
+
|
|
1302
|
+
.pane { display: none; padding: 30px 0; border-bottom: 1px solid var(--border); }
|
|
1303
|
+
.pane:last-child { border-bottom: none; }
|
|
1304
|
+
.pane.active { display: block; animation: pane-in 180ms ease; }
|
|
1305
|
+
@keyframes pane-in { from { opacity: 0; transform: translateY(3px); } to { opacity: 1; transform: none; } }
|
|
1306
|
+
|
|
1307
|
+
.pane-head {
|
|
1308
|
+
display: flex; align-items: flex-start; justify-content: space-between;
|
|
1309
|
+
gap: 16px; margin-bottom: 22px; flex-wrap: wrap;
|
|
1310
|
+
}
|
|
1311
|
+
.pane-title {
|
|
1312
|
+
font-family: 'Lora', Georgia, serif; font-size: 1.32rem; font-weight: 600;
|
|
1313
|
+
letter-spacing: -0.01em; line-height: 1.25; margin-bottom: 5px;
|
|
1314
|
+
}
|
|
1315
|
+
.pane-desc { color: var(--muted); font-size: 0.88rem; line-height: 1.55; max-width: 52ch; }
|
|
1316
|
+
.pane-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
|
|
1317
|
+
.pane-body { display: flex; flex-direction: column; gap: 14px; }
|
|
1318
|
+
|
|
1319
|
+
.card-desc { color: var(--muted); font-size: 0.9rem; line-height: 1.55; margin-bottom: 12px; }
|
|
1320
|
+
|
|
1321
|
+
.link-result {
|
|
1322
|
+
margin-top: 12px; padding: 10px 14px; border-radius: 10px;
|
|
1323
|
+
display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
|
|
1324
|
+
font-size: 0.84rem;
|
|
1325
|
+
}
|
|
1326
|
+
.link-result.ok { background: var(--ok-bg); border: 1px solid var(--ok-border); }
|
|
1327
|
+
.link-result.err { background: var(--err-bg); border: 1px solid var(--err-border); color: var(--err-text); }
|
|
1328
|
+
.link-result.loading { background: rgba(0,0,0,0.025); border: 1px solid var(--border); color: var(--muted); }
|
|
1329
|
+
.link-result a {
|
|
1330
|
+
color: var(--ok-text);
|
|
1331
|
+
font-family: 'JetBrains Mono', ui-monospace, monospace;
|
|
1332
|
+
font-size: 0.78rem; word-break: break-all; flex: 1; min-width: 0;
|
|
1333
|
+
}
|
|
1334
|
+
.link-vault { color: var(--muted); font-size: 0.78rem; flex-shrink: 0; }
|
|
1335
|
+
.copy-link-btn {
|
|
1336
|
+
padding: 5px 12px; border: 1px solid var(--ok-border); border-radius: 7px;
|
|
1337
|
+
background: rgba(255,255,255,0.7); color: var(--ok-text);
|
|
1338
|
+
font: 500 0.78rem/1.2 'DM Sans', sans-serif;
|
|
1339
|
+
cursor: pointer; flex-shrink: 0;
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
.config-grid {
|
|
1343
|
+
display: grid; grid-template-columns: 1fr 1fr; gap: 18px;
|
|
1344
|
+
}
|
|
1345
|
+
.config-block { display: flex; flex-direction: column; gap: 10px; }
|
|
1346
|
+
|
|
1347
|
+
.config-block .primary-action-btn { align-self: flex-start; min-width: 132px; justify-content: center; }
|
|
1348
|
+
.config-row { display: grid; grid-template-columns: 110px 1fr; gap: 10px; align-items: center; }
|
|
1349
|
+
.config-row.config-row-stack { grid-template-columns: 1fr; }
|
|
1350
|
+
.config-row label { font-size: 0.82rem; color: var(--muted); }
|
|
1351
|
+
.config-row input, .config-row select, .config-row textarea {
|
|
1352
|
+
padding: 7px 10px; border: 1px solid var(--border); border-radius: 8px;
|
|
1353
|
+
font-family: inherit; font-size: 0.84rem; width: 100%;
|
|
1354
|
+
}
|
|
1355
|
+
.config-row textarea {
|
|
1356
|
+
font-family: 'JetBrains Mono', ui-monospace, monospace;
|
|
1357
|
+
resize: vertical;
|
|
1358
|
+
}
|
|
1359
|
+
.toggle { display: inline-flex; align-items: center; gap: 8px; font-size: 0.84rem; }
|
|
1360
|
+
|
|
1361
|
+
.inline-result {
|
|
1362
|
+
padding: 8px 12px; border-radius: 8px; font-size: 0.82rem; margin-top: 4px;
|
|
1363
|
+
}
|
|
1364
|
+
.inline-result.ok { background: var(--ok-bg); color: var(--ok-text); border: 1px solid var(--ok-border); }
|
|
1365
|
+
.inline-result.err { background: var(--err-bg); color: var(--err-text); border: 1px solid var(--err-border); }
|
|
1366
|
+
|
|
1367
|
+
.refresh-btn {
|
|
1368
|
+
flex-shrink: 0; padding: 6px 12px;
|
|
1369
|
+
border: 1px solid var(--border); border-radius: 10px;
|
|
1370
|
+
background: rgba(0,0,0,0.025); color: var(--muted);
|
|
1371
|
+
font: 500 0.8rem/1.2 'DM Sans', sans-serif; cursor: pointer;
|
|
1372
|
+
transition: background 120ms, color 120ms;
|
|
1373
|
+
}
|
|
1374
|
+
.refresh-btn:hover { background: rgba(0,0,0,0.06); color: var(--text); }
|
|
1375
|
+
|
|
1376
|
+
|
|
1377
|
+
|
|
1378
|
+
.workspace-split {
|
|
1379
|
+
display: grid; grid-template-columns: 260px 1fr; gap: 14px;
|
|
1380
|
+
min-height: 360px;
|
|
1381
|
+
}
|
|
1382
|
+
.workspace-tree {
|
|
1383
|
+
border: 1px solid var(--border); border-radius: 12px; padding: 10px;
|
|
1384
|
+
background: rgba(0,0,0,0.02); overflow: auto; max-height: 480px;
|
|
1385
|
+
font-family: 'JetBrains Mono', ui-monospace, monospace;
|
|
1386
|
+
font-size: 0.78rem;
|
|
1387
|
+
}
|
|
1388
|
+
.workspace-tree ul { list-style: none; padding-left: 12px; margin: 0; }
|
|
1389
|
+
.workspace-tree .tree-root { padding-left: 0; }
|
|
1390
|
+
.workspace-tree details { margin: 1px 0; }
|
|
1391
|
+
.workspace-tree summary { cursor: pointer; padding: 2px 4px; border-radius: 4px; }
|
|
1392
|
+
.workspace-tree summary:hover { background: rgba(0,0,0,0.05); }
|
|
1393
|
+
.tree-dir { color: var(--text); font-weight: 600; }
|
|
1394
|
+
.tree-dir.empty { color: var(--subtle); font-weight: 400; }
|
|
1395
|
+
.tree-file {
|
|
1396
|
+
display: block; width: 100%; text-align: left;
|
|
1397
|
+
background: transparent; border: none; cursor: pointer;
|
|
1398
|
+
padding: 2px 4px; border-radius: 4px;
|
|
1399
|
+
font-family: inherit; font-size: inherit; color: var(--muted);
|
|
1400
|
+
}
|
|
1401
|
+
.tree-file:hover { background: rgba(0,0,0,0.05); color: var(--text); }
|
|
1402
|
+
|
|
1403
|
+
.workspace-preview {
|
|
1404
|
+
border: 1px solid var(--border); border-radius: 12px;
|
|
1405
|
+
background: #fff; padding: 12px; overflow: auto; max-height: 480px;
|
|
1406
|
+
}
|
|
1407
|
+
.preview-meta {
|
|
1408
|
+
font-size: 0.74rem; color: var(--subtle);
|
|
1409
|
+
margin-bottom: 8px; padding-bottom: 8px; border-bottom: 1px solid var(--border);
|
|
1410
|
+
font-family: 'JetBrains Mono', ui-monospace, monospace;
|
|
1411
|
+
}
|
|
1412
|
+
.preview-body {
|
|
1413
|
+
margin: 0; white-space: pre-wrap; word-break: break-word;
|
|
1414
|
+
font-family: 'JetBrains Mono', ui-monospace, monospace;
|
|
1415
|
+
font-size: 0.78rem; color: var(--text);
|
|
1416
|
+
}
|
|
1417
|
+
.placeholder-msg { color: var(--subtle); font-size: 0.86rem; padding: 24px 8px; text-align: center; }
|
|
1418
|
+
|
|
1419
|
+
|
|
1420
|
+
|
|
1421
|
+
.skills-list { display: flex; flex-direction: column; gap: 8px; }
|
|
1422
|
+
.skill-row {
|
|
1423
|
+
padding: 10px 12px; border: 1px solid var(--border); border-radius: 10px;
|
|
1424
|
+
background: rgba(0,0,0,0.02);
|
|
1425
|
+
display: flex; flex-direction: column; align-items: stretch; gap: 6px;
|
|
1426
|
+
}
|
|
1427
|
+
.skill-row-btn {
|
|
1428
|
+
flex: 1 1 auto; min-width: 0; text-align: left; cursor: pointer; font-family: inherit;
|
|
1429
|
+
background: transparent; border: none; padding: 0;
|
|
1430
|
+
}
|
|
1431
|
+
.skill-row-btn:hover .skill-name { color: var(--accent); }
|
|
1432
|
+
.skill-row-actions { display: flex; gap: 6px; flex-shrink: 0; justify-content: flex-end; }
|
|
1433
|
+
.skill-name {
|
|
1434
|
+
font-weight: 650; font-size: 0.9rem; color: var(--text);
|
|
1435
|
+
display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
|
|
1436
|
+
}
|
|
1437
|
+
.skill-source {
|
|
1438
|
+
padding: 1px 8px; border-radius: 999px; font-size: 0.7rem;
|
|
1439
|
+
font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;
|
|
1440
|
+
}
|
|
1441
|
+
.skill-source-global { background: rgba(59,130,246,0.1); color: #1d4ed8; }
|
|
1442
|
+
.skill-source-conversation { background: rgba(217,119,6,0.1); color: var(--accent); }
|
|
1443
|
+
.skill-desc { color: var(--muted); font-size: 0.82rem; margin-top: 4px; line-height: 1.5; }
|
|
1444
|
+
|
|
1445
|
+
|
|
1446
|
+
|
|
1447
|
+
.form-input {
|
|
1448
|
+
flex: 1 1 240px; min-width: 0; padding: 8px 10px;
|
|
1449
|
+
border: 1px solid var(--border); border-radius: 8px; background: var(--card);
|
|
1450
|
+
font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 0.8rem; color: var(--text);
|
|
1451
|
+
}
|
|
1452
|
+
.status-msg {
|
|
1453
|
+
padding: 8px 12px; border-radius: 8px; margin-bottom: 12px;
|
|
1454
|
+
font-size: 0.82rem; line-height: 1.5; word-break: break-word;
|
|
1455
|
+
}
|
|
1456
|
+
.status-msg-ok { background: rgba(22,163,74,0.1); color: #15803d; }
|
|
1457
|
+
.status-msg-err { background: rgba(220,38,38,0.1); color: #b91c1c; }
|
|
1458
|
+
.status-msg-busy { background: rgba(0,0,0,0.05); color: var(--muted); }
|
|
1459
|
+
.mcp-btn {
|
|
1460
|
+
padding: 4px 10px; border: 1px solid var(--border); border-radius: 7px;
|
|
1461
|
+
background: var(--card); color: var(--text); font-size: 0.76rem; cursor: pointer;
|
|
1462
|
+
}
|
|
1463
|
+
.mcp-btn:hover { background: rgba(0,0,0,0.05); }
|
|
1464
|
+
.mcp-btn-danger { color: #b91c1c; }
|
|
1465
|
+
.mcp-badge {
|
|
1466
|
+
padding: 1px 8px; border-radius: 999px; font-size: 0.7rem;
|
|
1467
|
+
font-weight: 600; letter-spacing: 0.03em;
|
|
1468
|
+
}
|
|
1469
|
+
.mcp-badge-ok { background: rgba(22,163,74,0.1); color: #15803d; }
|
|
1470
|
+
.mcp-badge-warn { background: rgba(217,119,6,0.12); color: var(--accent); }
|
|
1471
|
+
|
|
1472
|
+
.mcp-market-head {
|
|
1473
|
+
display: flex; align-items: end; justify-content: space-between; gap: 16px;
|
|
1474
|
+
margin-bottom: 12px;
|
|
1475
|
+
}
|
|
1476
|
+
.mcp-market-head h3 { margin: 0; font-size: 1rem; }
|
|
1477
|
+
.mcp-market-head p { margin: 3px 0 0; color: var(--muted); font-size: 0.8rem; }
|
|
1478
|
+
.mcp-market-head > span {
|
|
1479
|
+
color: var(--subtle); font: 500 0.72rem/1.2 'JetBrains Mono', ui-monospace, monospace;
|
|
1480
|
+
}
|
|
1481
|
+
.mcp-preset-grid {
|
|
1482
|
+
display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px;
|
|
1483
|
+
}
|
|
1484
|
+
.mcp-preset {
|
|
1485
|
+
min-width: 0; padding: 14px; border: 1px solid var(--border); border-radius: 12px;
|
|
1486
|
+
background:
|
|
1487
|
+
linear-gradient(145deg, rgba(255,255,255,0.85), rgba(247,245,238,0.72)),
|
|
1488
|
+
var(--card);
|
|
1489
|
+
display: flex; flex-direction: column; min-height: 190px;
|
|
1490
|
+
}
|
|
1491
|
+
.mcp-preset-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
|
|
1492
|
+
.mcp-preset-category {
|
|
1493
|
+
color: var(--accent); font-size: 0.66rem; font-weight: 700;
|
|
1494
|
+
letter-spacing: 0.09em; text-transform: uppercase;
|
|
1495
|
+
}
|
|
1496
|
+
.mcp-preset h3 { margin: 14px 0 5px; font-size: 1.06rem; letter-spacing: -0.02em; }
|
|
1497
|
+
.mcp-preset p { margin: 0; color: var(--muted); font-size: 0.8rem; line-height: 1.5; }
|
|
1498
|
+
.mcp-preset-meta {
|
|
1499
|
+
margin-top: 12px; color: var(--subtle); font-size: 0.72rem;
|
|
1500
|
+
}
|
|
1501
|
+
.mcp-preset-meta code { color: var(--text); background: transparent; }
|
|
1502
|
+
.mcp-preset-actions {
|
|
1503
|
+
margin-top: auto; padding-top: 16px; display: flex; align-items: center;
|
|
1504
|
+
justify-content: space-between; gap: 10px;
|
|
1505
|
+
}
|
|
1506
|
+
.mcp-preset-actions a, .mcp-setup-link {
|
|
1507
|
+
color: var(--muted); font-size: 0.76rem; text-decoration: none;
|
|
1508
|
+
}
|
|
1509
|
+
.mcp-preset-actions a:hover, .mcp-setup-link:hover { color: var(--text); text-decoration: underline; }
|
|
1510
|
+
.mcp-preset-actions .primary-action-btn { padding: 6px 12px; }
|
|
1511
|
+
.mcp-installed {
|
|
1512
|
+
margin-top: 14px; border-top: 1px solid var(--border); padding-top: 12px;
|
|
1513
|
+
}
|
|
1514
|
+
.mcp-installed > summary {
|
|
1515
|
+
cursor: pointer; color: var(--muted); font-size: 0.8rem; font-weight: 600;
|
|
1516
|
+
margin-bottom: 10px;
|
|
1517
|
+
}
|
|
1518
|
+
.mcp-installed-card { min-height: 150px; }
|
|
1519
|
+
.mcp-installed-transport {
|
|
1520
|
+
font-family: 'JetBrains Mono', ui-monospace, monospace; word-break: break-all;
|
|
1521
|
+
}
|
|
1522
|
+
.mcp-add-card {
|
|
1523
|
+
min-width: 0; min-height: 190px; border: 1.5px dashed var(--border); border-radius: 12px;
|
|
1524
|
+
background: transparent; color: var(--muted); font-size: 0.86rem; font-weight: 600;
|
|
1525
|
+
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
|
1526
|
+
gap: 8px; cursor: pointer;
|
|
1527
|
+
}
|
|
1528
|
+
.mcp-add-card:hover { background: rgba(0,0,0,0.03); color: var(--text); border-color: var(--text); }
|
|
1529
|
+
.mcp-add-card-plus { font-size: 1.8rem; line-height: 1; font-weight: 400; }
|
|
1530
|
+
.mcp-manual-hint { color: var(--muted); font-size: 0.8rem; margin: 0 0 10px; line-height: 1.5; }
|
|
1531
|
+
.mcp-add-mode { display: flex; gap: 8px; margin: 0 0 12px; }
|
|
1532
|
+
.mcp-mode-btn {
|
|
1533
|
+
padding: 6px 12px; border: 1px solid var(--border); border-radius: 999px;
|
|
1534
|
+
background: var(--card); font-size: 0.8rem; cursor: pointer; color: var(--muted);
|
|
1535
|
+
}
|
|
1536
|
+
.mcp-mode-btn.active { background: var(--text); color: #fafafa; border-color: var(--text); }
|
|
1537
|
+
.mcp-guided-grid { display: grid; gap: 12px; }
|
|
1538
|
+
.mcp-field { display: grid; gap: 5px; }
|
|
1539
|
+
.mcp-field span { font-size: 0.78rem; font-weight: 650; color: var(--muted); }
|
|
1540
|
+
.mcp-transport-toggle { display: flex; gap: 16px; font-size: 0.85rem; align-items: center; }
|
|
1541
|
+
.mcp-transport-toggle label { display: flex; align-items: center; gap: 6px; cursor: pointer; }
|
|
1542
|
+
.mcp-transport-fields { display: grid; gap: 12px; }
|
|
1543
|
+
.mcp-kv-block { display: grid; gap: 8px; }
|
|
1544
|
+
.mcp-kv-head { display: flex; align-items: center; justify-content: space-between; }
|
|
1545
|
+
.mcp-kv-head span { font-size: 0.78rem; font-weight: 650; color: var(--muted); }
|
|
1546
|
+
.mcp-kv-rows { display: grid; gap: 6px; }
|
|
1547
|
+
.mcp-kv-row { display: flex; gap: 8px; }
|
|
1548
|
+
.mcp-kv-row .form-input { flex: 1 1 auto; }
|
|
1549
|
+
.mcp-json {
|
|
1550
|
+
width: 100%; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
1551
|
+
font-size: 0.8rem; line-height: 1.45; resize: vertical;
|
|
1552
|
+
}
|
|
1553
|
+
.mcp-verify { margin-top: 10px; display: grid; gap: 6px; }
|
|
1554
|
+
.mcp-verify .inline-result { word-break: break-word; }
|
|
1555
|
+
|
|
1556
|
+
.mcp-dialog {
|
|
1557
|
+
width: min(620px, calc(100vw - 28px)); max-height: calc(100vh - 40px);
|
|
1558
|
+
border: 1px solid var(--border); border-radius: 18px; padding: 22px;
|
|
1559
|
+
color: var(--text); background: #fbfaf6; box-shadow: 0 28px 90px rgba(18,18,16,0.24);
|
|
1560
|
+
|
|
1561
|
+
position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); margin: 0;
|
|
1562
|
+
}
|
|
1563
|
+
.mcp-dialog::backdrop { background: rgba(20,20,18,0.5); backdrop-filter: blur(3px); }
|
|
1564
|
+
.mcp-dialog-head {
|
|
1565
|
+
display: flex; align-items: flex-start; justify-content: space-between; gap: 18px;
|
|
1566
|
+
padding-bottom: 14px; border-bottom: 1px solid var(--border);
|
|
1567
|
+
}
|
|
1568
|
+
.mcp-dialog-head .card-title { margin: 4px 0 0; }
|
|
1569
|
+
.mcp-dialog-close {
|
|
1570
|
+
border: 0; background: transparent; color: var(--muted); cursor: pointer;
|
|
1571
|
+
font-size: 1.6rem; line-height: 1; padding: 2px 5px;
|
|
1572
|
+
}
|
|
1573
|
+
.mcp-dialog-desc { color: var(--muted); line-height: 1.55; font-size: 0.88rem; }
|
|
1574
|
+
.mcp-install-preview {
|
|
1575
|
+
display: grid; gap: 6px; padding: 12px; border-radius: 10px;
|
|
1576
|
+
background: #1d211f; color: #f5f2e9;
|
|
1577
|
+
}
|
|
1578
|
+
.mcp-install-preview span {
|
|
1579
|
+
color: #aeb8b1; font-size: 0.66rem; font-weight: 700;
|
|
1580
|
+
letter-spacing: 0.08em; text-transform: uppercase;
|
|
1581
|
+
}
|
|
1582
|
+
.mcp-install-preview code {
|
|
1583
|
+
color: #f5f2e9; background: transparent; word-break: break-all; font-size: 0.78rem;
|
|
1584
|
+
}
|
|
1585
|
+
.mcp-security-note, .mcp-replace-note {
|
|
1586
|
+
margin-top: 12px; padding: 10px 12px; border-radius: 9px;
|
|
1587
|
+
font-size: 0.78rem; line-height: 1.5;
|
|
1588
|
+
}
|
|
1589
|
+
.mcp-security-note.local {
|
|
1590
|
+
background: rgba(220,38,38,0.08); border: 1px solid rgba(185,28,28,0.18); color: #991b1b;
|
|
1591
|
+
}
|
|
1592
|
+
.mcp-security-note.remote {
|
|
1593
|
+
background: rgba(59,130,246,0.08); border: 1px solid rgba(29,78,216,0.16); color: #1e40af;
|
|
1594
|
+
}
|
|
1595
|
+
.mcp-replace-note { background: rgba(217,119,6,0.1); color: #92400e; }
|
|
1596
|
+
.mcp-credential { display: grid; gap: 5px; margin-top: 14px; }
|
|
1597
|
+
.mcp-credential span { font-size: 0.78rem; font-weight: 650; }
|
|
1598
|
+
.mcp-credential input {
|
|
1599
|
+
width: 100%; padding: 9px 10px; border: 1px solid var(--border); border-radius: 8px;
|
|
1600
|
+
background: #fff; color: var(--text); font: 0.8rem/1.3 'JetBrains Mono', ui-monospace, monospace;
|
|
1601
|
+
}
|
|
1602
|
+
.mcp-credential small, .mcp-secret-note, .mcp-no-credentials {
|
|
1603
|
+
color: var(--subtle); font-size: 0.72rem; line-height: 1.45;
|
|
1604
|
+
}
|
|
1605
|
+
.mcp-secret-note { margin: 14px 0 8px; }
|
|
1606
|
+
.mcp-no-credentials { margin: 14px 0 0; }
|
|
1607
|
+
#mcp-dialog-error, #mcp-custom-dialog-error { margin-top: 14px; }
|
|
1608
|
+
.mcp-dialog-actions {
|
|
1609
|
+
display: flex; justify-content: flex-end; gap: 8px; margin-top: 20px;
|
|
1610
|
+
padding-top: 14px; border-top: 1px solid var(--border);
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
|
|
1614
|
+
|
|
1615
|
+
.events-list { display: flex; flex-direction: column; gap: 8px; }
|
|
1616
|
+
.event-row {
|
|
1617
|
+
padding: 10px 12px; border: 1px solid var(--border); border-radius: 10px;
|
|
1618
|
+
background: rgba(0,0,0,0.02);
|
|
1619
|
+
}
|
|
1620
|
+
.event-row-top {
|
|
1621
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
1622
|
+
gap: 10px;
|
|
1623
|
+
}
|
|
1624
|
+
.event-name { min-width: 0; flex: 1; word-break: break-all; }
|
|
1625
|
+
.event-name code { font-size: 0.82rem; background: transparent; padding: 0; }
|
|
1626
|
+
.event-meta { font-size: 0.74rem; color: var(--muted); margin-top: 3px; }
|
|
1627
|
+
.event-text {
|
|
1628
|
+
font-size: 0.82rem; color: var(--text); margin-top: 6px;
|
|
1629
|
+
font-family: 'JetBrains Mono', ui-monospace, monospace;
|
|
1630
|
+
white-space: pre-wrap; word-break: break-word;
|
|
1631
|
+
}
|
|
1632
|
+
.event-delete-btn {
|
|
1633
|
+
flex-shrink: 0; padding: 4px 10px;
|
|
1634
|
+
border-radius: 7px; border: 1px solid rgba(185, 28, 28, 0.18);
|
|
1635
|
+
background: rgba(0,0,0,0.03); color: var(--err-text);
|
|
1636
|
+
font: 500 0.76rem/1.2 'DM Sans', sans-serif; cursor: pointer;
|
|
1637
|
+
}
|
|
1638
|
+
.event-delete-btn:hover:not(:disabled) {
|
|
1639
|
+
background: var(--err-bg); border-color: rgba(185, 28, 28, 0.28);
|
|
1640
|
+
}
|
|
1641
|
+
.event-delete-btn:disabled { opacity: 0.5; cursor: wait; }
|
|
1642
|
+
|
|
1643
|
+
|
|
1644
|
+
|
|
1645
|
+
.conv-list { display: flex; flex-direction: column; gap: 6px; }
|
|
1646
|
+
.conv-row-btn {
|
|
1647
|
+
display: flex; align-items: center; gap: 12px;
|
|
1648
|
+
padding: 10px 14px; border: 1px solid var(--border); border-radius: 10px;
|
|
1649
|
+
background: rgba(0,0,0,0.02); cursor: pointer; text-align: left;
|
|
1650
|
+
transition: background 120ms, border-color 120ms;
|
|
1651
|
+
}
|
|
1652
|
+
.conv-row-btn:hover { background: rgba(0,0,0,0.05); border-color: rgba(0,0,0,0.14); }
|
|
1653
|
+
.conv-id { flex: 1; font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 0.84rem; }
|
|
1654
|
+
.conv-last { color: var(--subtle); font-size: 0.78rem; }
|
|
1655
|
+
|
|
1656
|
+
.usage-table-wrap { overflow-x: auto; }
|
|
1657
|
+
.usage-table { width: 100%; border-collapse: collapse; font-size: 0.78rem; }
|
|
1658
|
+
.usage-table th, .usage-table td {
|
|
1659
|
+
padding: 8px 10px; border-bottom: 1px solid var(--border);
|
|
1660
|
+
text-align: left; white-space: nowrap;
|
|
1661
|
+
}
|
|
1662
|
+
.usage-table th {
|
|
1663
|
+
color: var(--subtle); font-size: 0.68rem;
|
|
1664
|
+
text-transform: uppercase; letter-spacing: 0.08em;
|
|
1665
|
+
}
|
|
1666
|
+
.usage-table code { font-size: 0.72rem; }
|
|
1667
|
+
|
|
1668
|
+
.timeline-controls {
|
|
1669
|
+
display: flex; flex-wrap: wrap; gap: 18px; align-items: center; margin-bottom: 16px;
|
|
1670
|
+
}
|
|
1671
|
+
.timeline-controls label {
|
|
1672
|
+
display: flex; align-items: center; gap: 8px;
|
|
1673
|
+
font-size: 0.76rem; color: var(--muted);
|
|
1674
|
+
}
|
|
1675
|
+
.timeline-controls select {
|
|
1676
|
+
padding: 6px 10px; border: 1px solid var(--border); border-radius: 8px;
|
|
1677
|
+
background: #fff; color: var(--text); font-size: 0.8rem; max-width: 240px;
|
|
1678
|
+
}
|
|
1679
|
+
.tl-note { margin-top: 8px; font-size: 0.72rem; color: var(--subtle); }
|
|
1680
|
+
.tl-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-bottom: 16px; }
|
|
1681
|
+
.tl-card { background: rgba(0,0,0,0.025); border-radius: 10px; padding: 10px 12px; }
|
|
1682
|
+
.tl-card-label { font-size: 0.73rem; color: var(--muted); margin-bottom: 4px; }
|
|
1683
|
+
.tl-card-value { font-size: 1.35rem; font-weight: 600; color: var(--text); }
|
|
1684
|
+
.tl-legend { display: flex; gap: 16px; font-size: 0.73rem; color: var(--muted); margin-bottom: 10px; }
|
|
1685
|
+
.tl-legend span { display: inline-flex; align-items: center; gap: 6px; }
|
|
1686
|
+
.tl-legend-item { cursor: pointer; transition: opacity 100ms; }
|
|
1687
|
+
.tl-legend-item:hover { text-decoration: underline; }
|
|
1688
|
+
.tl-legend-item.active { color: var(--text); font-weight: 600; text-decoration: underline; }
|
|
1689
|
+
.tl-legend-item.dim { opacity: 0.4; }
|
|
1690
|
+
.sw { width: 10px; height: 10px; border-radius: 2px; display: inline-block; }
|
|
1691
|
+
.sw-cache-read { background: rgba(0,0,0,0.18); }
|
|
1692
|
+
.sw-cache-write { background: #3b6fb0; }
|
|
1693
|
+
.sw-input { background: var(--accent); }
|
|
1694
|
+
.sw-output { background: var(--ok-text); }
|
|
1695
|
+
.tl-chart {
|
|
1696
|
+
position: relative;
|
|
1697
|
+
display: flex; align-items: flex-end; gap: 6px;
|
|
1698
|
+
height: 216px; border-bottom: 1px solid var(--border);
|
|
1699
|
+
}
|
|
1700
|
+
.tl-peak {
|
|
1701
|
+
position: absolute; left: 0; right: 0; height: 0;
|
|
1702
|
+
border-top: 1px dashed var(--accent); pointer-events: none;
|
|
1703
|
+
}
|
|
1704
|
+
.tl-peak-label {
|
|
1705
|
+
position: absolute; left: 0; top: -15px;
|
|
1706
|
+
font-size: 0.7rem; color: var(--accent); white-space: nowrap;
|
|
1707
|
+
}
|
|
1708
|
+
.tl-bar {
|
|
1709
|
+
position: relative; flex: 1; min-width: 0; height: 180px;
|
|
1710
|
+
display: flex; flex-direction: column; justify-content: flex-end;
|
|
1711
|
+
border-radius: 6px 6px 0 0; transition: background 80ms ease;
|
|
1712
|
+
}
|
|
1713
|
+
.tl-bar:hover { background: rgba(0,0,0,0.06); }
|
|
1714
|
+
.tl-bar:hover .tl-seg { opacity: 0.55; }
|
|
1715
|
+
.tl-fill {
|
|
1716
|
+
display: flex; flex-direction: column; justify-content: flex-end;
|
|
1717
|
+
border-radius: 3px 3px 0 0; overflow: hidden;
|
|
1718
|
+
}
|
|
1719
|
+
.tl-tip {
|
|
1720
|
+
position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%);
|
|
1721
|
+
margin-bottom: 6px; padding: 5px 9px; border-radius: 6px;
|
|
1722
|
+
background: var(--text); color: #fafafa; font-size: 0.7rem; line-height: 1.35;
|
|
1723
|
+
white-space: nowrap; opacity: 0; pointer-events: none; z-index: 5;
|
|
1724
|
+
}
|
|
1725
|
+
.tl-bar:hover .tl-tip { opacity: 1; }
|
|
1726
|
+
.tl-seg { display: block; width: 100%; }
|
|
1727
|
+
.tl-seg.tl-output { background: var(--ok-text); }
|
|
1728
|
+
.tl-seg.tl-input { background: var(--accent); }
|
|
1729
|
+
.tl-seg.tl-cache-write { background: #3b6fb0; }
|
|
1730
|
+
.tl-seg.tl-cache-read { background: rgba(0,0,0,0.18); }
|
|
1731
|
+
.tl-empty { display: block; width: 100%; height: 3px; background: var(--border); }
|
|
1732
|
+
.tl-axis { display: flex; justify-content: space-between; margin-top: 6px; font-size: 0.7rem; color: var(--subtle); }
|
|
1733
|
+
|
|
1734
|
+
.status-pill {
|
|
1735
|
+
display: inline-flex; padding: 2px 9px; border-radius: 999px;
|
|
1736
|
+
font-size: 0.7rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;
|
|
1737
|
+
}
|
|
1738
|
+
.status-pill.running { background: var(--ok-bg); color: var(--ok-text); border: 1px solid var(--ok-border); }
|
|
1739
|
+
|
|
1740
|
+
@media (max-width: 860px) {
|
|
1741
|
+
.settings-shell { grid-template-columns: 1fr; }
|
|
1742
|
+
.settings-rail { position: static; }
|
|
1743
|
+
|
|
1744
|
+
.rail-nav {
|
|
1745
|
+
flex-direction: row; flex-wrap: nowrap; gap: 6px;
|
|
1746
|
+
overflow-x: auto; padding-bottom: 6px;
|
|
1747
|
+
|
|
1748
|
+
min-width: 0; max-width: 100%;
|
|
1749
|
+
scrollbar-width: thin; -webkit-overflow-scrolling: touch;
|
|
1750
|
+
}
|
|
1751
|
+
.settings-rail { min-width: 0; }
|
|
1752
|
+
.rail-nav[hidden] { display: none; }
|
|
1753
|
+
.rail-link { flex: 0 0 auto; padding: 7px 11px; }
|
|
1754
|
+
.rail-link span { white-space: nowrap; }
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
@media (max-width: 640px) {
|
|
1758
|
+
.config-grid { grid-template-columns: 1fr; }
|
|
1759
|
+
.config-row { grid-template-columns: 1fr; gap: 4px; }
|
|
1760
|
+
.workspace-split { grid-template-columns: 1fr; }
|
|
1761
|
+
.workspace-tree, .workspace-preview { max-height: 260px; }
|
|
1762
|
+
.mcp-preset-grid { grid-template-columns: 1fr; }
|
|
1763
|
+
.mcp-dialog { padding: 18px; }
|
|
1764
|
+
}
|
|
1765
|
+
`;
|
|
1766
|
+
//# sourceMappingURL=client-assets.js.map
|