agim-cli 1.4.9 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +415 -402
- package/README.md +4 -4
- package/bin/agim_rpc.py +12 -12
- package/dist/cli-ui/cmd-handlers.d.ts +3 -3
- package/dist/cli-ui/cmd-handlers.d.ts.map +1 -1
- package/dist/cli-ui/cmd-handlers.js +11 -19
- package/dist/cli-ui/cmd-handlers.js.map +1 -1
- package/dist/cli-ui/config-wizard.js +27 -27
- package/dist/cli-ui/config-wizard.js.map +1 -1
- package/dist/cli-ui/env-file.d.ts +4 -4
- package/dist/cli-ui/env-file.js +13 -13
- package/dist/cli-ui/env-file.js.map +1 -1
- package/dist/cli-ui/i18n.d.ts +2 -2
- package/dist/cli-ui/i18n.js +9 -9
- package/dist/cli-ui/i18n.js.map +1 -1
- package/dist/cli-ui/lang-picker.js +1 -1
- package/dist/cli-ui/lang-picker.js.map +1 -1
- package/dist/cli-ui/paths.d.ts.map +1 -1
- package/dist/cli-ui/paths.js +2 -4
- package/dist/cli-ui/paths.js.map +1 -1
- package/dist/cli-ui/service.d.ts +7 -7
- package/dist/cli-ui/service.d.ts.map +1 -1
- package/dist/cli-ui/service.js +57 -72
- package/dist/cli-ui/service.js.map +1 -1
- package/dist/cli-ui/tui/app.js +2 -2
- package/dist/cli-ui/tui/app.js.map +1 -1
- package/dist/cli-ui/tui/index.js +6 -6
- package/dist/cli-ui/tui/index.js.map +1 -1
- package/dist/cli-ui/tui/mouse-stdin.js +1 -1
- package/dist/cli-ui/tui/mouse-stdin.js.map +1 -1
- package/dist/cli-ui/tui/stream-reveal.d.ts +2 -2
- package/dist/cli-ui/tui/stream-reveal.d.ts.map +1 -1
- package/dist/cli-ui/tui/stream-reveal.js +4 -4
- package/dist/cli-ui/tui/stream-reveal.js.map +1 -1
- package/dist/cli.js +24 -45
- package/dist/cli.js.map +1 -1
- package/dist/core/a2a-notify.js +5 -5
- package/dist/core/a2a-notify.js.map +1 -1
- package/dist/core/a2a.d.ts +2 -2
- package/dist/core/a2a.d.ts.map +1 -1
- package/dist/core/a2a.js +12 -12
- package/dist/core/a2a.js.map +1 -1
- package/dist/core/access-token.d.ts +1 -1
- package/dist/core/access-token.js +7 -7
- package/dist/core/access-token.js.map +1 -1
- package/dist/core/acp-server.js +5 -5
- package/dist/core/acp-server.js.map +1 -1
- package/dist/core/admin-allowlist.js +5 -5
- package/dist/core/admin-allowlist.js.map +1 -1
- package/dist/core/agent-base.d.ts +1 -1
- package/dist/core/agent-base.js +3 -3
- package/dist/core/agent-base.js.map +1 -1
- package/dist/core/agent-cwd.d.ts +5 -6
- package/dist/core/agent-cwd.d.ts.map +1 -1
- package/dist/core/agent-cwd.js +15 -16
- package/dist/core/agent-cwd.js.map +1 -1
- package/dist/core/agim-paths.d.ts +1 -4
- package/dist/core/agim-paths.d.ts.map +1 -1
- package/dist/core/agim-paths.js +18 -35
- package/dist/core/agim-paths.js.map +1 -1
- package/dist/core/approval-bus.d.ts +4 -4
- package/dist/core/approval-bus.d.ts.map +1 -1
- package/dist/core/approval-bus.js +14 -14
- package/dist/core/approval-bus.js.map +1 -1
- package/dist/core/approval-router.js +2 -2
- package/dist/core/artifacts.js +3 -3
- package/dist/core/artifacts.js.map +1 -1
- package/dist/core/ask-user-rpc.js +1 -1
- package/dist/core/ask-user-rpc.js.map +1 -1
- package/dist/core/audit-log.js +2 -2
- package/dist/core/audit-log.js.map +1 -1
- package/dist/core/bgjob-reader.d.ts +1 -1
- package/dist/core/bgjob-reader.js +4 -4
- package/dist/core/bgjob-reader.js.map +1 -1
- package/dist/core/commands/approval.js +2 -2
- package/dist/core/commands/approval.js.map +1 -1
- package/dist/core/commands/heartbeat.js +2 -2
- package/dist/core/commands/heartbeat.js.map +1 -1
- package/dist/core/commands/memo.js +1 -1
- package/dist/core/commands/memo.js.map +1 -1
- package/dist/core/commands/model.js +1 -1
- package/dist/core/commands/model.js.map +1 -1
- package/dist/core/commands/plan.js +3 -3
- package/dist/core/commands/plan.js.map +1 -1
- package/dist/core/commands/router-compare.js +3 -3
- package/dist/core/commands/router-compare.js.map +1 -1
- package/dist/core/commands/service.d.ts.map +1 -1
- package/dist/core/commands/service.js +1 -3
- package/dist/core/commands/service.js.map +1 -1
- package/dist/core/commands/sessions.js +4 -4
- package/dist/core/commands/sessions.js.map +1 -1
- package/dist/core/commands/skill.js +1 -1
- package/dist/core/commands/skill.js.map +1 -1
- package/dist/core/commands/stats.js +1 -1
- package/dist/core/commands/stats.js.map +1 -1
- package/dist/core/commands/web.js +5 -5
- package/dist/core/commands/web.js.map +1 -1
- package/dist/core/config-schema.js +1 -1
- package/dist/core/coord-systems.d.ts +1 -1
- package/dist/core/coord-systems.js +4 -4
- package/dist/core/coord-systems.js.map +1 -1
- package/dist/core/event-bus.d.ts +5 -5
- package/dist/core/event-bus.d.ts.map +1 -1
- package/dist/core/event-bus.js +3 -3
- package/dist/core/event-bus.js.map +1 -1
- package/dist/core/feature-flags.d.ts +2 -2
- package/dist/core/feature-flags.js +4 -4
- package/dist/core/feature-flags.js.map +1 -1
- package/dist/core/goal-rpc.js +2 -2
- package/dist/core/goal-rpc.js.map +1 -1
- package/dist/core/goals.d.ts +1 -1
- package/dist/core/goals.js +3 -3
- package/dist/core/goals.js.map +1 -1
- package/dist/core/heartbeat-store.d.ts +1 -1
- package/dist/core/heartbeat-store.d.ts.map +1 -1
- package/dist/core/heartbeat-store.js +3 -3
- package/dist/core/heartbeat-store.js.map +1 -1
- package/dist/core/heartbeat.js +4 -4
- package/dist/core/heartbeat.js.map +1 -1
- package/dist/core/intent-llm.d.ts +2 -2
- package/dist/core/intent-llm.js +5 -5
- package/dist/core/intent-llm.js.map +1 -1
- package/dist/core/job-board.d.ts +5 -5
- package/dist/core/job-board.d.ts.map +1 -1
- package/dist/core/job-board.js +17 -17
- package/dist/core/job-board.js.map +1 -1
- package/dist/core/llm/agent-loop.d.ts +3 -3
- package/dist/core/llm/agent-loop.js +14 -14
- package/dist/core/llm/agent-loop.js.map +1 -1
- package/dist/core/llm/{imhub-dispatcher.d.ts → agim-dispatcher.d.ts} +4 -4
- package/dist/core/llm/agim-dispatcher.d.ts.map +1 -0
- package/dist/core/llm/{imhub-dispatcher.js → agim-dispatcher.js} +43 -43
- package/dist/core/llm/agim-dispatcher.js.map +1 -0
- package/dist/core/llm/agim-rpc-server.js +17 -17
- package/dist/core/llm/agim-rpc-server.js.map +1 -1
- package/dist/core/llm/auto-compact.d.ts +3 -3
- package/dist/core/llm/auto-compact.d.ts.map +1 -1
- package/dist/core/llm/auto-compact.js +5 -5
- package/dist/core/llm/auto-compact.js.map +1 -1
- package/dist/core/llm/builtin-dispatcher.js +3 -3
- package/dist/core/llm/builtin-dispatcher.js.map +1 -1
- package/dist/core/llm/exec-dispatcher.d.ts +2 -2
- package/dist/core/llm/exec-dispatcher.d.ts.map +1 -1
- package/dist/core/llm/exec-dispatcher.js +20 -22
- package/dist/core/llm/exec-dispatcher.js.map +1 -1
- package/dist/core/llm/fs-dispatcher.js +8 -8
- package/dist/core/llm/fs-dispatcher.js.map +1 -1
- package/dist/core/llm/goal-critic.js +4 -4
- package/dist/core/llm/goal-critic.js.map +1 -1
- package/dist/core/llm/hallucination-detector.js +2 -2
- package/dist/core/llm/hallucination-detector.js.map +1 -1
- package/dist/core/llm/mcp-client.d.ts +1 -1
- package/dist/core/llm/mcp-client.js +3 -3
- package/dist/core/llm/mcp-client.js.map +1 -1
- package/dist/core/llm/mcp-registry.js +3 -3
- package/dist/core/llm/mcp-registry.js.map +1 -1
- package/dist/core/llm/openai-compat-provider.d.ts +1 -1
- package/dist/core/llm/openai-compat-provider.js +2 -2
- package/dist/core/llm/openai-compat-provider.js.map +1 -1
- package/dist/core/llm/provider-base.d.ts +1 -1
- package/dist/core/llm/secrets.d.ts +2 -2
- package/dist/core/llm/secrets.d.ts.map +1 -1
- package/dist/core/llm/tool-dispatcher.d.ts +1 -1
- package/dist/core/llm/web-dispatcher.d.ts +1 -1
- package/dist/core/llm/web-dispatcher.js +15 -15
- package/dist/core/llm/web-dispatcher.js.map +1 -1
- package/dist/core/logger.d.ts +1 -1
- package/dist/core/logger.js +3 -3
- package/dist/core/logger.js.map +1 -1
- package/dist/core/memo-rpc.js +3 -3
- package/dist/core/memo-rpc.js.map +1 -1
- package/dist/core/memory-consolidate.js +4 -4
- package/dist/core/memory-consolidate.js.map +1 -1
- package/dist/core/memory-distill.js +4 -4
- package/dist/core/memory-distill.js.map +1 -1
- package/dist/core/memory-distiller.js +9 -9
- package/dist/core/memory-distiller.js.map +1 -1
- package/dist/core/memory-vector.js +9 -9
- package/dist/core/memory-vector.js.map +1 -1
- package/dist/core/memory.js +2 -2
- package/dist/core/memory.js.map +1 -1
- package/dist/core/memos.js +6 -6
- package/dist/core/memos.js.map +1 -1
- package/dist/core/message-sink.js +13 -13
- package/dist/core/message-sink.js.map +1 -1
- package/dist/core/notification-evaluator.d.ts +2 -2
- package/dist/core/notification-evaluator.js +4 -4
- package/dist/core/notification-evaluator.js.map +1 -1
- package/dist/core/onboarding.js +3 -3
- package/dist/core/onboarding.js.map +1 -1
- package/dist/core/outbox.js +2 -2
- package/dist/core/outbox.js.map +1 -1
- package/dist/core/persona.d.ts +1 -1
- package/dist/core/persona.d.ts.map +1 -1
- package/dist/core/persona.js +2 -2
- package/dist/core/persona.js.map +1 -1
- package/dist/core/plan-history.js +1 -1
- package/dist/core/plan-history.js.map +1 -1
- package/dist/core/plan-intent.js +5 -5
- package/dist/core/plan-intent.js.map +1 -1
- package/dist/core/plan-mode-state.d.ts +1 -1
- package/dist/core/plan-mode-state.js +4 -4
- package/dist/core/plan-mode-state.js.map +1 -1
- package/dist/core/push-rpc.d.ts +1 -1
- package/dist/core/push-rpc.js +6 -6
- package/dist/core/push-rpc.js.map +1 -1
- package/dist/core/registry.d.ts +4 -4
- package/dist/core/registry.js +10 -10
- package/dist/core/registry.js.map +1 -1
- package/dist/core/reminders.js +1 -1
- package/dist/core/reminders.js.map +1 -1
- package/dist/core/restart-flow.d.ts.map +1 -1
- package/dist/core/restart-flow.js +5 -7
- package/dist/core/restart-flow.js.map +1 -1
- package/dist/core/router.d.ts +1 -1
- package/dist/core/router.js +5 -5
- package/dist/core/router.js.map +1 -1
- package/dist/core/schedule.d.ts +2 -2
- package/dist/core/schedule.js +4 -4
- package/dist/core/schedule.js.map +1 -1
- package/dist/core/self-protect.js +3 -3
- package/dist/core/self-protect.js.map +1 -1
- package/dist/core/sender-allowlist.js +7 -7
- package/dist/core/sender-allowlist.js.map +1 -1
- package/dist/core/sensitive-paths.d.ts.map +1 -1
- package/dist/core/sensitive-paths.js +1 -2
- package/dist/core/sensitive-paths.js.map +1 -1
- package/dist/core/session.js +2 -2
- package/dist/core/session.js.map +1 -1
- package/dist/core/skills/builtin/ECC_NOTICE.md +1 -1
- package/dist/core/skills/builtin/agim-memory/SKILL.md +1 -1
- package/dist/core/skills/builtin/agim-reminders/SKILL.md +2 -2
- package/dist/core/skills/builtin/agim-self/SKILL.md +9 -9
- package/dist/core/skills/builtin/agim-skill-discovery/SKILL.md +5 -5
- package/dist/core/skills/builtin/image-generation/SKILL.md +2 -2
- package/dist/core/skills/builtin/long-goal/SKILL.md +7 -7
- package/dist/core/skills/builtin/my/SKILL.md +2 -2
- package/dist/core/skills/builtin/skill-creator/SKILL.md +2 -2
- package/dist/core/skills/loader.d.ts +4 -4
- package/dist/core/skills/loader.js +22 -22
- package/dist/core/skills/loader.js.map +1 -1
- package/dist/core/skills-rpc.js +1 -1
- package/dist/core/skills-rpc.js.map +1 -1
- package/dist/core/transcribe.js +13 -13
- package/dist/core/transcribe.js.map +1 -1
- package/dist/core/tunnel.js +1 -1
- package/dist/core/tunnel.js.map +1 -1
- package/dist/core/types.d.ts +2 -2
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/user-coord-prefs.js +1 -1
- package/dist/core/user-coord-prefs.js.map +1 -1
- package/dist/core/viewer-config.d.ts +8 -8
- package/dist/core/viewer-config.js +17 -17
- package/dist/core/viewer-config.js.map +1 -1
- package/dist/core/viewer-local.js +4 -4
- package/dist/core/viewer-local.js.map +1 -1
- package/dist/core/viewer-remote.js +1 -1
- package/dist/core/viewer-remote.js.map +1 -1
- package/dist/plugins/agents/acp/url-guard.d.ts +1 -1
- package/dist/plugins/agents/acp/url-guard.js +2 -2
- package/dist/plugins/agents/acp/url-guard.js.map +1 -1
- package/dist/plugins/agents/antigravity/ensure-mcp-config.d.ts +6 -6
- package/dist/plugins/agents/antigravity/ensure-mcp-config.d.ts.map +1 -1
- package/dist/plugins/agents/antigravity/ensure-mcp-config.js +12 -12
- package/dist/plugins/agents/antigravity/ensure-mcp-config.js.map +1 -1
- package/dist/plugins/agents/antigravity/index.js +10 -10
- package/dist/plugins/agents/antigravity/index.js.map +1 -1
- package/dist/plugins/agents/claude-code/index.d.ts +2 -2
- package/dist/plugins/agents/claude-code/index.js +16 -16
- package/dist/plugins/agents/claude-code/index.js.map +1 -1
- package/dist/plugins/agents/claude-code/mcp-approval-server.js +13 -13
- package/dist/plugins/agents/claude-code/mcp-approval-server.js.map +1 -1
- package/dist/plugins/agents/codex/build-mcp-cli-args.d.ts +4 -4
- package/dist/plugins/agents/codex/build-mcp-cli-args.js +14 -14
- package/dist/plugins/agents/codex/build-mcp-cli-args.js.map +1 -1
- package/dist/plugins/agents/codex/index.d.ts +3 -3
- package/dist/plugins/agents/codex/index.js +14 -14
- package/dist/plugins/agents/codex/index.js.map +1 -1
- package/dist/plugins/agents/cursor/ensure-mcp-config.d.ts +5 -5
- package/dist/plugins/agents/cursor/ensure-mcp-config.d.ts.map +1 -1
- package/dist/plugins/agents/cursor/ensure-mcp-config.js +11 -11
- package/dist/plugins/agents/cursor/ensure-mcp-config.js.map +1 -1
- package/dist/plugins/agents/cursor/index.d.ts +1 -1
- package/dist/plugins/agents/cursor/index.js +12 -12
- package/dist/plugins/agents/cursor/index.js.map +1 -1
- package/dist/plugins/agents/native/index.js +14 -14
- package/dist/plugins/agents/native/index.js.map +1 -1
- package/dist/plugins/agents/native/tool-registry.d.ts +3 -3
- package/dist/plugins/agents/native/tool-registry.d.ts.map +1 -1
- package/dist/plugins/agents/native/tool-registry.js +5 -5
- package/dist/plugins/agents/native/tool-registry.js.map +1 -1
- package/dist/plugins/agents/opencode/ensure-mcp-config.d.ts +1 -1
- package/dist/plugins/agents/opencode/ensure-mcp-config.js +9 -9
- package/dist/plugins/agents/opencode/ensure-mcp-config.js.map +1 -1
- package/dist/plugins/agents/opencode/index.js +3 -3
- package/dist/plugins/agents/opencode/index.js.map +1 -1
- package/dist/plugins/agents/opencode/opencode-http-adapter.d.ts +4 -0
- package/dist/plugins/agents/opencode/opencode-http-adapter.d.ts.map +1 -1
- package/dist/plugins/agents/opencode/opencode-http-adapter.js +16 -12
- package/dist/plugins/agents/opencode/opencode-http-adapter.js.map +1 -1
- package/dist/plugins/agents/opencode/opencode-stdio-adapter.d.ts +2 -2
- package/dist/plugins/agents/opencode/opencode-stdio-adapter.d.ts.map +1 -1
- package/dist/plugins/agents/opencode/opencode-stdio-adapter.js +7 -5
- package/dist/plugins/agents/opencode/opencode-stdio-adapter.js.map +1 -1
- package/dist/plugins/agents/opencode/serve-manager.d.ts +1 -1
- package/dist/plugins/agents/opencode/serve-manager.d.ts.map +1 -1
- package/dist/plugins/agents/opencode/serve-manager.js +10 -10
- package/dist/plugins/agents/opencode/serve-manager.js.map +1 -1
- package/dist/plugins/agents/pi-native/factory.js +10 -10
- package/dist/plugins/agents/pi-native/factory.js.map +1 -1
- package/dist/plugins/agents/pi-native/index.d.ts +3 -3
- package/dist/plugins/agents/pi-native/index.d.ts.map +1 -1
- package/dist/plugins/agents/pi-native/index.js +2 -2
- package/dist/plugins/agents/pi-native/index.js.map +1 -1
- package/dist/plugins/agents/pi-native/tool-bridge.js +1 -1
- package/dist/plugins/agents/pi-native/tool-bridge.js.map +1 -1
- package/dist/plugins/agents/pi-native/tools.js +4 -4
- package/dist/plugins/agents/pi-native/tools.js.map +1 -1
- package/dist/plugins/messengers/dingtalk/dingtalk-adapter.d.ts +1 -1
- package/dist/plugins/messengers/dingtalk/dingtalk-adapter.js +2 -2
- package/dist/plugins/messengers/dingtalk/dingtalk-adapter.js.map +1 -1
- package/dist/plugins/messengers/email/email-adapter.js +15 -15
- package/dist/plugins/messengers/email/email-adapter.js.map +1 -1
- package/dist/plugins/messengers/telegram/media-download.d.ts +1 -1
- package/dist/plugins/messengers/telegram/media-download.js +4 -4
- package/dist/plugins/messengers/telegram/media-download.js.map +1 -1
- package/dist/plugins/messengers/telegram/telegram-adapter.d.ts +1 -1
- package/dist/plugins/messengers/telegram/telegram-adapter.js +3 -3
- package/dist/plugins/messengers/telegram/telegram-adapter.js.map +1 -1
- package/dist/plugins/messengers/wechat/context-store.js +1 -1
- package/dist/plugins/messengers/wechat/context-store.js.map +1 -1
- package/dist/plugins/messengers/wechat/ilink-adapter.js +1 -1
- package/dist/plugins/messengers/wechat/ilink-adapter.js.map +1 -1
- package/dist/plugins/messengers/wechat/ilink-client.js +1 -1
- package/dist/plugins/messengers/wechat/ilink-client.js.map +1 -1
- package/dist/plugins/messengers/wechat/media-download.js +1 -1
- package/dist/plugins/messengers/wechat/media-download.js.map +1 -1
- package/dist/scripts/migrate-gcj02-to-wgs84.js +1 -1
- package/dist/scripts/migrate-gcj02-to-wgs84.js.map +1 -1
- package/dist/web/public/assets/{a2a-CZxwvgvh.js → a2a-D7MoJ1iT.js} +2 -2
- package/dist/web/public/assets/{a2a-CZxwvgvh.js.map → a2a-D7MoJ1iT.js.map} +1 -1
- package/dist/web/public/assets/{activity-BnlFGipw.js → activity-BAgb2WZC.js} +2 -2
- package/dist/web/public/assets/{activity-BnlFGipw.js.map → activity-BAgb2WZC.js.map} +1 -1
- package/dist/web/public/assets/{admins-CH84Rw1d.js → admins-CZYANmhn.js} +2 -2
- package/dist/web/public/assets/{admins-CH84Rw1d.js.map → admins-CZYANmhn.js.map} +1 -1
- package/dist/web/public/assets/{agents-CFB4Uj6b.js → agents-BXThDW6f.js} +2 -2
- package/dist/web/public/assets/agents-BXThDW6f.js.map +1 -0
- package/dist/web/public/assets/{approvals-DnzjbDR6.js → approvals-ByPXIYVl.js} +2 -2
- package/dist/web/public/assets/{approvals-DnzjbDR6.js.map → approvals-ByPXIYVl.js.map} +1 -1
- package/dist/web/public/assets/{arrow-down-DxlRHrs8.js → arrow-down-B8DkdbEY.js} +2 -2
- package/dist/web/public/assets/{arrow-down-DxlRHrs8.js.map → arrow-down-B8DkdbEY.js.map} +1 -1
- package/dist/web/public/assets/{arrow-up-CAiQ2jy-.js → arrow-up-i_dEdXkz.js} +2 -2
- package/dist/web/public/assets/{arrow-up-CAiQ2jy-.js.map → arrow-up-i_dEdXkz.js.map} +1 -1
- package/dist/web/public/assets/{asks-DyUQopay.js → asks-yD_inOnM.js} +2 -2
- package/dist/web/public/assets/{asks-DyUQopay.js.map → asks-yD_inOnM.js.map} +1 -1
- package/dist/web/public/assets/{audit-BVHTMS82.js → audit-teCIRtgN.js} +2 -2
- package/dist/web/public/assets/{audit-BVHTMS82.js.map → audit-teCIRtgN.js.map} +1 -1
- package/dist/web/public/assets/{bell-D7iS7ctN.js → bell-CeWDMs8_.js} +2 -2
- package/dist/web/public/assets/{bell-D7iS7ctN.js.map → bell-CeWDMs8_.js.map} +1 -1
- package/dist/web/public/assets/{bgjobs-BYCQhd_1.js → bgjobs-Rc05aEy9.js} +2 -2
- package/dist/web/public/assets/bgjobs-Rc05aEy9.js.map +1 -0
- package/dist/web/public/assets/{brain-CCF25Egu.js → brain-BQqv0Zhc.js} +2 -2
- package/dist/web/public/assets/{brain-CCF25Egu.js.map → brain-BQqv0Zhc.js.map} +1 -1
- package/dist/web/public/assets/{briefcase-BMLMD8nM.js → briefcase-DUXbR4xs.js} +2 -2
- package/dist/web/public/assets/{briefcase-BMLMD8nM.js.map → briefcase-DUXbR4xs.js.map} +1 -1
- package/dist/web/public/assets/{chat-DPkKy5y_.js → chat-DQpQLW9j.js} +2 -2
- package/dist/web/public/assets/{chat-DPkKy5y_.js.map → chat-DQpQLW9j.js.map} +1 -1
- package/dist/web/public/assets/{chevron-left-BDO3vw8G.js → chevron-left-RC6mMSiX.js} +2 -2
- package/dist/web/public/assets/{chevron-left-BDO3vw8G.js.map → chevron-left-RC6mMSiX.js.map} +1 -1
- package/dist/web/public/assets/{chevron-right-5ZUC2opg.js → chevron-right-DrkYVi19.js} +2 -2
- package/dist/web/public/assets/{chevron-right-5ZUC2opg.js.map → chevron-right-DrkYVi19.js.map} +1 -1
- package/dist/web/public/assets/{circle-check-COhM5JsK.js → circle-check-DZnkaUdk.js} +2 -2
- package/dist/web/public/assets/{circle-check-COhM5JsK.js.map → circle-check-DZnkaUdk.js.map} +1 -1
- package/dist/web/public/assets/{circle-check-big-DHAHqUlS.js → circle-check-big-BC8ntMsz.js} +2 -2
- package/dist/web/public/assets/{circle-check-big-DHAHqUlS.js.map → circle-check-big-BC8ntMsz.js.map} +1 -1
- package/dist/web/public/assets/{circle-x-7VaoZ7dY.js → circle-x-DHK7ypFY.js} +2 -2
- package/dist/web/public/assets/{circle-x-7VaoZ7dY.js.map → circle-x-DHK7ypFY.js.map} +1 -1
- package/dist/web/public/assets/{clock-ZPVXnd6V.js → clock-DXHhWqJH.js} +2 -2
- package/dist/web/public/assets/{clock-ZPVXnd6V.js.map → clock-DXHhWqJH.js.map} +1 -1
- package/dist/web/public/assets/{confirm-dialog-CgpJL9oN.js → confirm-dialog-gPKJnvEW.js} +2 -2
- package/dist/web/public/assets/{confirm-dialog-CgpJL9oN.js.map → confirm-dialog-gPKJnvEW.js.map} +1 -1
- package/dist/web/public/assets/{copy-BaZl52tH.js → copy-DtQxgcR0.js} +2 -2
- package/dist/web/public/assets/{copy-BaZl52tH.js.map → copy-DtQxgcR0.js.map} +1 -1
- package/dist/web/public/assets/{data-table-BLYG79TX.js → data-table-DOKUic1J.js} +2 -2
- package/dist/web/public/assets/{data-table-BLYG79TX.js.map → data-table-DOKUic1J.js.map} +1 -1
- package/dist/web/public/assets/distill-p6P7-1UR.js +7 -0
- package/dist/web/public/assets/distill-p6P7-1UR.js.map +1 -0
- package/dist/web/public/assets/{download-bzCepctg.js → download-CqNiIHa8.js} +2 -2
- package/dist/web/public/assets/{download-bzCepctg.js.map → download-CqNiIHa8.js.map} +1 -1
- package/dist/web/public/assets/email-DwbfTUlV.js +7 -0
- package/dist/web/public/assets/email-DwbfTUlV.js.map +1 -0
- package/dist/web/public/assets/{empty-state-96qpPTNg.js → empty-state-CTwOQemt.js} +2 -2
- package/dist/web/public/assets/{empty-state-96qpPTNg.js.map → empty-state-CTwOQemt.js.map} +1 -1
- package/dist/web/public/assets/{external-link-J4nIlCem.js → external-link-BY7Ye8yi.js} +2 -2
- package/dist/web/public/assets/{external-link-J4nIlCem.js.map → external-link-BY7Ye8yi.js.map} +1 -1
- package/dist/web/public/assets/{eye-BvsBLK42.js → eye-6RUADoDS.js} +2 -2
- package/dist/web/public/assets/{eye-BvsBLK42.js.map → eye-6RUADoDS.js.map} +1 -1
- package/dist/web/public/assets/{facts-DMucDXYd.js → facts-DXE0aJmb.js} +2 -2
- package/dist/web/public/assets/{facts-DMucDXYd.js.map → facts-DXE0aJmb.js.map} +1 -1
- package/dist/web/public/assets/{goals-B9ETHgL0.js → goals-C1LCm3qL.js} +2 -2
- package/dist/web/public/assets/{goals-B9ETHgL0.js.map → goals-C1LCm3qL.js.map} +1 -1
- package/dist/web/public/assets/{health-DLzZ7KHc.js → health-wqCp-K_o.js} +2 -2
- package/dist/web/public/assets/{health-DLzZ7KHc.js.map → health-wqCp-K_o.js.map} +1 -1
- package/dist/web/public/assets/{heart-pulse-CVEeD2sz.js → heart-pulse-DfqI4GF7.js} +2 -2
- package/dist/web/public/assets/{heart-pulse-CVEeD2sz.js.map → heart-pulse-DfqI4GF7.js.map} +1 -1
- package/dist/web/public/assets/{heartbeat-B1BEBHge.js → heartbeat-Bumv4XtQ.js} +2 -2
- package/dist/web/public/assets/{heartbeat-B1BEBHge.js.map → heartbeat-Bumv4XtQ.js.map} +1 -1
- package/dist/web/public/assets/{hot-Yc7iad0D.js → hot-B-CMjQIr.js} +2 -2
- package/dist/web/public/assets/{hot-Yc7iad0D.js.map → hot-B-CMjQIr.js.map} +1 -1
- package/dist/web/public/assets/{index-DY2Zglku.js → index-DHh1LYlA.js} +29 -29
- package/dist/web/public/assets/{index-DY2Zglku.js.map → index-DHh1LYlA.js.map} +1 -1
- package/dist/web/public/assets/{injection-Ca-9gbo0.js → injection-Dn_XqgLG.js} +2 -2
- package/dist/web/public/assets/{injection-Ca-9gbo0.js.map → injection-Dn_XqgLG.js.map} +1 -1
- package/dist/web/public/assets/{installed-Zz34apdi.js → installed-Cet-1M2Q.js} +2 -2
- package/dist/web/public/assets/{installed-Zz34apdi.js.map → installed-Cet-1M2Q.js.map} +1 -1
- package/dist/web/public/assets/{jobs-CtVRpl0r.js → jobs-CfEzOOAC.js} +2 -2
- package/dist/web/public/assets/{jobs-CtVRpl0r.js.map → jobs-CfEzOOAC.js.map} +1 -1
- package/dist/web/public/assets/{layout-DnANw2Q2.js → layout-BX43KyXM.js} +2 -2
- package/dist/web/public/assets/{layout-DnANw2Q2.js.map → layout-BX43KyXM.js.map} +1 -1
- package/dist/web/public/assets/{layout-Cxch59sI.js → layout-BcYZlaqf.js} +2 -2
- package/dist/web/public/assets/{layout-Cxch59sI.js.map → layout-BcYZlaqf.js.map} +1 -1
- package/dist/web/public/assets/{layout-BTCLgkgN.js → layout-Cb7looUv.js} +2 -2
- package/dist/web/public/assets/{layout-BTCLgkgN.js.map → layout-Cb7looUv.js.map} +1 -1
- package/dist/web/public/assets/{layout-yIZG87fq.js → layout-D7xH78OU.js} +2 -2
- package/dist/web/public/assets/{layout-yIZG87fq.js.map → layout-D7xH78OU.js.map} +1 -1
- package/dist/web/public/assets/{layout-CtDc2i7w.js → layout-D_3ZcVG7.js} +2 -2
- package/dist/web/public/assets/{layout-CtDc2i7w.js.map → layout-D_3ZcVG7.js.map} +1 -1
- package/dist/web/public/assets/llm-BZ9qqp-D.js +27 -0
- package/dist/web/public/assets/llm-BZ9qqp-D.js.map +1 -0
- package/dist/web/public/assets/{loader-circle-D8L1w9c1.js → loader-circle-DgdBWYl0.js} +2 -2
- package/dist/web/public/assets/{loader-circle-D8L1w9c1.js.map → loader-circle-DgdBWYl0.js.map} +1 -1
- package/dist/web/public/assets/{map-pin--GMunU9n.js → map-pin-3QS1A0-I.js} +2 -2
- package/dist/web/public/assets/{map-pin--GMunU9n.js.map → map-pin-3QS1A0-I.js.map} +1 -1
- package/dist/web/public/assets/{mcp-DhnXhO9B.js → mcp-DwKZULET.js} +2 -2
- package/dist/web/public/assets/{mcp-DhnXhO9B.js.map → mcp-DwKZULET.js.map} +1 -1
- package/dist/web/public/assets/{memos-DQZc7llR.js → memos-BBtqFcoH.js} +2 -2
- package/dist/web/public/assets/{memos-DQZc7llR.js.map → memos-BBtqFcoH.js.map} +1 -1
- package/dist/web/public/assets/{messengers-DwSmauLs.js → messengers-i7WvNT3o.js} +2 -2
- package/dist/web/public/assets/messengers-i7WvNT3o.js.map +1 -0
- package/dist/web/public/assets/{mobile-CUZ359rQ.js → mobile-Bq0FH9JV.js} +2 -2
- package/dist/web/public/assets/{mobile-CUZ359rQ.js.map → mobile-Bq0FH9JV.js.map} +1 -1
- package/dist/web/public/assets/{network-BBdRdrH_.js → network--s113Jkm.js} +2 -2
- package/dist/web/public/assets/{network-BBdRdrH_.js.map → network--s113Jkm.js.map} +1 -1
- package/dist/web/public/assets/{outbox-CmN0U35l.js → outbox-BbfC5kuG.js} +2 -2
- package/dist/web/public/assets/{outbox-CmN0U35l.js.map → outbox-BbfC5kuG.js.map} +1 -1
- package/dist/web/public/assets/{pagination-DcsgDXXM.js → pagination-DkdCTctJ.js} +2 -2
- package/dist/web/public/assets/{pagination-DcsgDXXM.js.map → pagination-DkdCTctJ.js.map} +1 -1
- package/dist/web/public/assets/{persona-ig2ac4mY.js → persona-BvtcZh6G.js} +2 -2
- package/dist/web/public/assets/{persona-ig2ac4mY.js.map → persona-BvtcZh6G.js.map} +1 -1
- package/dist/web/public/assets/{plans-Bzbk8eUr.js → plans-i3a6lrqF.js} +2 -2
- package/dist/web/public/assets/{plans-Bzbk8eUr.js.map → plans-i3a6lrqF.js.map} +1 -1
- package/dist/web/public/assets/{play-Di1jqulh.js → play-CPoE_JnS.js} +2 -2
- package/dist/web/public/assets/{play-Di1jqulh.js.map → play-CPoE_JnS.js.map} +1 -1
- package/dist/web/public/assets/{plus-C2zyJ1mF.js → plus-CfzKV_0u.js} +2 -2
- package/dist/web/public/assets/{plus-C2zyJ1mF.js.map → plus-CfzKV_0u.js.map} +1 -1
- package/dist/web/public/assets/policy-Cm88P8LO.js +2 -0
- package/dist/web/public/assets/policy-Cm88P8LO.js.map +1 -0
- package/dist/web/public/assets/{qr-code-C-ACsKv_.js → qr-code-DMkV8nv2.js} +2 -2
- package/dist/web/public/assets/{qr-code-C-ACsKv_.js.map → qr-code-DMkV8nv2.js.map} +1 -1
- package/dist/web/public/assets/{refresh-ccw-7HdadG5V.js → refresh-ccw-nBMm5Xal.js} +2 -2
- package/dist/web/public/assets/{refresh-ccw-7HdadG5V.js.map → refresh-ccw-nBMm5Xal.js.map} +1 -1
- package/dist/web/public/assets/{reminders-BDeiVYTC.js → reminders-DjEujanC.js} +2 -2
- package/dist/web/public/assets/{reminders-BDeiVYTC.js.map → reminders-DjEujanC.js.map} +1 -1
- package/dist/web/public/assets/{save-BYFmz9gD.js → save-DbrrCFDM.js} +2 -2
- package/dist/web/public/assets/{save-BYFmz9gD.js.map → save-DbrrCFDM.js.map} +1 -1
- package/dist/web/public/assets/{schedules-BddzBrxI.js → schedules-DzwDWykc.js} +2 -2
- package/dist/web/public/assets/{schedules-BddzBrxI.js.map → schedules-DzwDWykc.js.map} +1 -1
- package/dist/web/public/assets/search-5q3dkINm.js +17 -0
- package/dist/web/public/assets/search-5q3dkINm.js.map +1 -0
- package/dist/web/public/assets/{search-DxkvV-8p.js → search-DbE4VEm9.js} +2 -2
- package/dist/web/public/assets/{search-DxkvV-8p.js.map → search-DbE4VEm9.js.map} +1 -1
- package/dist/web/public/assets/security-BIcnUrAs.js +2 -0
- package/dist/web/public/assets/security-BIcnUrAs.js.map +1 -0
- package/dist/web/public/assets/{service-BsY8CaNG.js → service-CnorFHzZ.js} +2 -2
- package/dist/web/public/assets/{service-BsY8CaNG.js.map → service-CnorFHzZ.js.map} +1 -1
- package/dist/web/public/assets/{shield-alert-DXGk9Rak.js → shield-alert-WOa69jy3.js} +2 -2
- package/dist/web/public/assets/{shield-alert-DXGk9Rak.js.map → shield-alert-WOa69jy3.js.map} +1 -1
- package/dist/web/public/assets/{status-badge-D0nbFSom.js → status-badge-D5xhwquL.js} +2 -2
- package/dist/web/public/assets/{status-badge-D0nbFSom.js.map → status-badge-D5xhwquL.js.map} +1 -1
- package/dist/web/public/assets/{subtasks-DFiAXvDp.js → subtasks-DMRyk6YS.js} +2 -2
- package/dist/web/public/assets/{subtasks-DFiAXvDp.js.map → subtasks-DMRyk6YS.js.map} +1 -1
- package/dist/web/public/assets/{table-_WsrnZ_T.js → table-Dx65w6V0.js} +2 -2
- package/dist/web/public/assets/{table-_WsrnZ_T.js.map → table-Dx65w6V0.js.map} +1 -1
- package/dist/web/public/assets/{topn-C2PHE4tX.js → topn-L7Juczp3.js} +2 -2
- package/dist/web/public/assets/{topn-C2PHE4tX.js.map → topn-L7Juczp3.js.map} +1 -1
- package/dist/web/public/assets/{trash-2-1Km439fW.js → trash-2-7xrfqd-v.js} +2 -2
- package/dist/web/public/assets/{trash-2-1Km439fW.js.map → trash-2-7xrfqd-v.js.map} +1 -1
- package/dist/web/public/assets/{use-agim-skills-COSqZrdH.js → use-agim-skills-pFjfgqMF.js} +2 -2
- package/dist/web/public/assets/{use-agim-skills-COSqZrdH.js.map → use-agim-skills-pFjfgqMF.js.map} +1 -1
- package/dist/web/public/assets/{use-background-tasks-wCL7jn68.js → use-background-tasks-D1--hHjp.js} +2 -2
- package/dist/web/public/assets/{use-background-tasks-wCL7jn68.js.map → use-background-tasks-D1--hHjp.js.map} +1 -1
- package/dist/web/public/assets/{use-memory-B9oRyQC8.js → use-memory-Bz1Zao7g.js} +2 -2
- package/dist/web/public/assets/{use-memory-B9oRyQC8.js.map → use-memory-Bz1Zao7g.js.map} +1 -1
- package/dist/web/public/assets/{use-observability-DGkN80qa.js → use-observability-DtqSWVjM.js} +2 -2
- package/dist/web/public/assets/{use-observability-DGkN80qa.js.map → use-observability-DtqSWVjM.js.map} +1 -1
- package/dist/web/public/assets/{use-settings-Co-iafXD.js → use-settings-DKbDqCEJ.js} +2 -2
- package/dist/web/public/assets/{use-settings-Co-iafXD.js.map → use-settings-DKbDqCEJ.js.map} +1 -1
- package/dist/web/public/assets/{use-workspace-BDXP5XO1.js → use-workspace-CConjEx0.js} +2 -2
- package/dist/web/public/assets/{use-workspace-BDXP5XO1.js.map → use-workspace-CConjEx0.js.map} +1 -1
- package/dist/web/public/assets/vector-D8sEa2W-.js +2 -0
- package/dist/web/public/assets/vector-D8sEa2W-.js.map +1 -0
- package/dist/web/public/assets/viewer-aSIjAKVA.js +12 -0
- package/dist/web/public/assets/viewer-aSIjAKVA.js.map +1 -0
- package/dist/web/public/assets/{workspace-BbCchiHE.js → workspace-BqwWoinI.js} +2 -2
- package/dist/web/public/assets/{workspace-BbCchiHE.js.map → workspace-BqwWoinI.js.map} +1 -1
- package/dist/web/public/assets/{workspaces-5HE7pjdA.js → workspaces-ChsJcrav.js} +2 -2
- package/dist/web/public/assets/{workspaces-5HE7pjdA.js.map → workspaces-ChsJcrav.js.map} +1 -1
- package/dist/web/public/index.html +1 -1
- package/dist/web/public/loc.html +1 -1
- package/dist/web/public/login.html +2 -2
- package/dist/web/server.d.ts +2 -2
- package/dist/web/server.js +118 -119
- package/dist/web/server.js.map +1 -1
- package/package.json +2 -3
- package/dist/core/llm/imhub-dispatcher.d.ts.map +0 -1
- package/dist/core/llm/imhub-dispatcher.js.map +0 -1
- package/dist/web/public/assets/agents-CFB4Uj6b.js.map +0 -1
- package/dist/web/public/assets/bgjobs-BYCQhd_1.js.map +0 -1
- package/dist/web/public/assets/distill-D9p8O8Jf.js +0 -7
- package/dist/web/public/assets/distill-D9p8O8Jf.js.map +0 -1
- package/dist/web/public/assets/email-Douv-rZ5.js +0 -7
- package/dist/web/public/assets/email-Douv-rZ5.js.map +0 -1
- package/dist/web/public/assets/llm-CMMa85Ig.js +0 -27
- package/dist/web/public/assets/llm-CMMa85Ig.js.map +0 -1
- package/dist/web/public/assets/messengers-DwSmauLs.js.map +0 -1
- package/dist/web/public/assets/policy-yD1c2Pcn.js +0 -2
- package/dist/web/public/assets/policy-yD1c2Pcn.js.map +0 -1
- package/dist/web/public/assets/search-B8PlbtLg.js +0 -17
- package/dist/web/public/assets/search-B8PlbtLg.js.map +0 -1
- package/dist/web/public/assets/security-DpOGp3nS.js +0 -2
- package/dist/web/public/assets/security-DpOGp3nS.js.map +0 -1
- package/dist/web/public/assets/vector-BfIEx8xX.js +0 -2
- package/dist/web/public/assets/vector-BfIEx8xX.js.map +0 -1
- package/dist/web/public/assets/viewer-BPMZkT05.js +0 -12
- package/dist/web/public/assets/viewer-BPMZkT05.js.map +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{u as C,j as e,l as n,B as x,L as k,m as i}from"./index-
|
|
2
|
-
//# sourceMappingURL=injection-
|
|
1
|
+
import{u as C,j as e,l as n,B as x,L as k,m as i}from"./index-DHh1LYlA.js";import{r as v}from"./react-DlP5eolq.js";import{f as T,g as A,h as P,a as R}from"./use-agim-skills-pFjfgqMF.js";import{L as p}from"./loader-circle-DgdBWYl0.js";import{R as E}from"./refresh-ccw-nBMm5Xal.js";import{C as z}from"./copy-DtQxgcR0.js";import{S as O}from"./save-DbrrCFDM.js";import{T as B}from"./trash-2-7xrfqd-v.js";const I=1e4;function M(){return e.jsx(W,{})}function W(){const{t:s}=C(["settings","common"]),a=T(),u=A(),h=P(),j=R(),[l,r]=v.useState(""),[f,o]=v.useState(!1);v.useEffect(()=>{a.data&&!f&&r(a.data.override??"")},[a.data,f]);const c=a.data?.auto??"",g=a.data?.maxOverrideChars??4e4,b=a.data?.overrideActive??!1,N=a.data?.overridePath??"~/.agim/skill-injection-override.md",d=l.length,m=d>g;async function w(){if(m){i.error(s("skillInjection.overLimitToast",{len:d,max:g}));return}try{const t=await u.mutateAsync(l);i.success(t.deleted?s("skillInjection.clearedToast"):s("skillInjection.savedToast")),o(!1)}catch(t){i.error(t?.message??String(t))}}async function L(){if(confirm(s("skillInjection.confirmClear")))try{await h.mutateAsync(),r(""),o(!1),i.success(s("skillInjection.clearedToast"))}catch(t){i.error(t?.message??String(t))}}async function S(){try{await j.mutateAsync()}catch(t){i.error(t?.message??String(t));return}await a.refetch(),f||r(a.data?.override??""),i.success(s("skillInjection.rebuiltToast"))}function y(){r(c),o(!0)}return e.jsxs("div",{className:"mx-auto flex max-w-6xl flex-col gap-4",children:[e.jsxs("header",{className:"flex items-center gap-3",children:[e.jsx("h1",{className:"text-xl font-semibold",children:s("skillInjection.title")}),b?e.jsx(n,{variant:"success",children:s("skillInjection.overrideActive")}):e.jsx(n,{variant:"outline",children:s("skillInjection.overrideInactive")}),e.jsxs(x,{variant:"outline",size:"sm",className:"ml-auto",onClick:()=>void S(),disabled:a.isFetching||j.isPending,title:s("skillInjection.rebuildTooltip"),children:[a.isFetching||j.isPending?e.jsx(p,{className:"h-4 w-4 animate-spin"}):e.jsx(E,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:s("skillInjection.rebuild")})]})]}),e.jsx("p",{className:"text-sm text-text-dim",children:s("skillInjection.subtitle")}),e.jsx("p",{className:"text-xs text-text-dim font-mono break-all",children:N}),e.jsxs("section",{className:"flex flex-col gap-2 rounded-md border border-border bg-surface p-3",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(k,{className:"text-sm font-medium",children:s("skillInjection.autoLabel")}),e.jsxs(n,{variant:"outline",children:[c.length.toLocaleString()," chars"]}),c.length>=I&&e.jsx(n,{variant:"warning",children:s("skillInjection.largeWarn")}),e.jsxs(x,{variant:"ghost",size:"sm",className:"ml-auto",onClick:y,disabled:a.isLoading,children:[e.jsx(z,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:s("skillInjection.copyToOverride")})]})]}),e.jsx("textarea",{readOnly:!0,value:a.isLoading?"...":c,className:"h-64 w-full resize-y rounded border border-border bg-surface-2 p-2 font-mono text-xs","aria-label":s("skillInjection.autoLabel")})]}),e.jsxs("section",{className:"flex flex-col gap-2 rounded-md border border-border bg-surface p-3",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(k,{className:"text-sm font-medium",children:s("skillInjection.overrideLabel")}),e.jsxs(n,{variant:m?"danger":"outline",children:[d.toLocaleString()," / ",g.toLocaleString()," chars"]}),d>=I&&!m&&e.jsx(n,{variant:"warning",children:s("skillInjection.largeWarn")})]}),e.jsx("textarea",{value:l,onChange:t=>{r(t.target.value),o(!0)},placeholder:s("skillInjection.overridePlaceholder"),className:"h-72 w-full resize-y rounded border border-border bg-surface-2 p-2 font-mono text-xs","aria-label":s("skillInjection.overrideLabel")}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2 pt-1",children:[e.jsxs(x,{onClick:()=>void w(),disabled:u.isPending||m,children:[u.isPending?e.jsx(p,{className:"h-4 w-4 animate-spin"}):e.jsx(O,{className:"h-4 w-4"}),s("skillInjection.save")]}),e.jsxs(x,{variant:"outline",onClick:()=>void L(),disabled:h.isPending||!b&&l.length===0,children:[h.isPending?e.jsx(p,{className:"h-4 w-4 animate-spin"}):e.jsx(B,{className:"h-4 w-4"}),s("skillInjection.clear")]}),e.jsx("span",{className:"text-xs text-text-dim",children:s("skillInjection.hint")})]})]})]})}export{M as Component,W as default};
|
|
2
|
+
//# sourceMappingURL=injection-Dn_XqgLG.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"injection-Ca-9gbo0.js","sources":["../../src/routes/settings/agim-skills/injection.tsx"],"sourcesContent":["/**\n * /settings/agim-skills/injection — operator-facing editor for the\n * tier-1 system-prompt skill block.\n *\n * v1.2.151 — Background: every agim turn injects an auto-generated\n * skill block at the top of the system prompt so the LLM knows which\n * skills it can call. The block is computed from the loader's bucket\n * + cluster rules. When operators want to nudge it (pin a skill,\n * hide a noisy one, add a routing hint about a custom env), they\n * authoring text here writes a single Markdown file\n * (`~/.agim/skill-injection-override.md`) that REPLACES the auto\n * block at injection time. Empty file == auto behaviour.\n *\n * UI:\n * · Left/top: Auto-generated block (read-only preview).\n * · Right/bottom: Operator override (editable textarea).\n * · Buttons: Save / Clear / Refresh / Copy-auto-into-override.\n * · Counters: char count for both panes + warning at ≥10k chars.\n */\n\nimport { useEffect, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Copy, Loader2, RefreshCcw, Save, Trash2 } from 'lucide-react'\n\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Label } from '@/components/ui/label'\nimport {\n useSkillInjection, useSkillInjectionSave, useSkillInjectionDelete,\n useAgimSkillsRefresh,\n} from '@/hooks/use-agim-skills'\n\nconst TOKEN_WARN_CHARS = 10_000\n\nexport function Component(): JSX.Element {\n return <InjectionEditorRoute />\n}\n\nexport default function InjectionEditorRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const query = useSkillInjection()\n const save = useSkillInjectionSave()\n const del = useSkillInjectionDelete()\n // v1.2.152 — \"Refresh\" 改成\"重建自动注入词\":先让 loader 重扫磁盘\n // (POST /api/agim-skills/refresh 会调用 invalidateSkillsCache 失效 5 分钟\n // TTL 缓存),然后再 refetch GET injection 拿到 fresh auto block。\n // override 字段不受影响。\n const refreshLoader = useAgimSkillsRefresh()\n\n // Local draft state; sync from server on first load + after a save.\n const [draft, setDraft] = useState('')\n const [touched, setTouched] = useState(false)\n\n useEffect(() => {\n if (query.data && !touched) {\n setDraft(query.data.override ?? '')\n }\n }, [query.data, touched])\n\n const auto = query.data?.auto ?? ''\n const maxChars = query.data?.maxOverrideChars ?? 40_000\n const overrideActive = query.data?.overrideActive ?? false\n const overridePath = query.data?.overridePath ?? '~/.agim/skill-injection-override.md'\n\n const draftLen = draft.length\n const overLimit = draftLen > maxChars\n\n async function onSave(): Promise<void> {\n if (overLimit) {\n toast.error(t('skillInjection.overLimitToast', { len: draftLen, max: maxChars }))\n return\n }\n try {\n const r = await save.mutateAsync(draft)\n toast.success(r.deleted ? t('skillInjection.clearedToast') : t('skillInjection.savedToast'))\n setTouched(false)\n } catch (err) {\n toast.error((err as Error)?.message ?? String(err))\n }\n }\n\n async function onClear(): Promise<void> {\n if (!confirm(t('skillInjection.confirmClear'))) return\n try {\n await del.mutateAsync()\n setDraft('')\n setTouched(false)\n toast.success(t('skillInjection.clearedToast'))\n } catch (err) {\n toast.error((err as Error)?.message ?? String(err))\n }\n }\n\n async function onRefresh(): Promise<void> {\n // Two-step: invalidate loader cache (re-scan disk) → refetch injection.\n try {\n await refreshLoader.mutateAsync()\n } catch (err) {\n toast.error((err as Error)?.message ?? String(err))\n return\n }\n await query.refetch()\n if (!touched) setDraft(query.data?.override ?? '')\n toast.success(t('skillInjection.rebuiltToast'))\n }\n\n function onCopyAuto(): void {\n setDraft(auto)\n setTouched(true)\n }\n\n return (\n <div className=\"mx-auto flex max-w-6xl flex-col gap-4\">\n <header className=\"flex items-center gap-3\">\n <h1 className=\"text-xl font-semibold\">{t('skillInjection.title')}</h1>\n {overrideActive\n ? <Badge variant=\"success\">{t('skillInjection.overrideActive')}</Badge>\n : <Badge variant=\"outline\">{t('skillInjection.overrideInactive')}</Badge>}\n <Button\n variant=\"outline\" size=\"sm\" className=\"ml-auto\"\n onClick={() => void onRefresh()}\n disabled={query.isFetching || refreshLoader.isPending}\n title={t('skillInjection.rebuildTooltip')}\n >\n {(query.isFetching || refreshLoader.isPending)\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('skillInjection.rebuild')}</span>\n </Button>\n </header>\n <p className=\"text-sm text-text-dim\">{t('skillInjection.subtitle')}</p>\n <p className=\"text-xs text-text-dim font-mono break-all\">{overridePath}</p>\n\n {/* Auto preview */}\n <section className=\"flex flex-col gap-2 rounded-md border border-border bg-surface p-3\">\n <div className=\"flex items-center gap-2\">\n <Label className=\"text-sm font-medium\">{t('skillInjection.autoLabel')}</Label>\n <Badge variant=\"outline\">{auto.length.toLocaleString()} chars</Badge>\n {auto.length >= TOKEN_WARN_CHARS && (\n <Badge variant=\"warning\">{t('skillInjection.largeWarn')}</Badge>\n )}\n <Button\n variant=\"ghost\" size=\"sm\" className=\"ml-auto\"\n onClick={onCopyAuto}\n disabled={query.isLoading}\n >\n <Copy className=\"h-4 w-4\" />\n <span className=\"hidden sm:inline\">{t('skillInjection.copyToOverride')}</span>\n </Button>\n </div>\n <textarea\n readOnly\n value={query.isLoading ? '...' : auto}\n className=\"h-64 w-full resize-y rounded border border-border bg-surface-2 p-2 font-mono text-xs\"\n aria-label={t('skillInjection.autoLabel')}\n />\n </section>\n\n {/* Override editor */}\n <section className=\"flex flex-col gap-2 rounded-md border border-border bg-surface p-3\">\n <div className=\"flex items-center gap-2\">\n <Label className=\"text-sm font-medium\">{t('skillInjection.overrideLabel')}</Label>\n <Badge variant={overLimit ? 'danger' : 'outline'}>\n {draftLen.toLocaleString()} / {maxChars.toLocaleString()} chars\n </Badge>\n {draftLen >= TOKEN_WARN_CHARS && !overLimit && (\n <Badge variant=\"warning\">{t('skillInjection.largeWarn')}</Badge>\n )}\n </div>\n <textarea\n value={draft}\n onChange={(e) => { setDraft(e.target.value); setTouched(true) }}\n placeholder={t('skillInjection.overridePlaceholder')}\n className=\"h-72 w-full resize-y rounded border border-border bg-surface-2 p-2 font-mono text-xs\"\n aria-label={t('skillInjection.overrideLabel')}\n />\n <div className=\"flex flex-wrap items-center gap-2 pt-1\">\n <Button\n onClick={() => void onSave()}\n disabled={save.isPending || overLimit}\n >\n {save.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Save className=\"h-4 w-4\" />}\n {t('skillInjection.save')}\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => void onClear()}\n disabled={del.isPending || (!overrideActive && draft.length === 0)}\n >\n {del.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Trash2 className=\"h-4 w-4\" />}\n {t('skillInjection.clear')}\n </Button>\n <span className=\"text-xs text-text-dim\">{t('skillInjection.hint')}</span>\n </div>\n </section>\n </div>\n )\n}\n"],"names":["TOKEN_WARN_CHARS","Component","InjectionEditorRoute","t","useTranslation","query","useSkillInjection","save","useSkillInjectionSave","del","useSkillInjectionDelete","refreshLoader","useAgimSkillsRefresh","draft","setDraft","useState","touched","setTouched","useEffect","auto","maxChars","overrideActive","overridePath","draftLen","overLimit","onSave","toast","r","err","onClear","onRefresh","onCopyAuto","jsxs","jsx","Badge","Button","Loader2","RefreshCcw","Label","Copy","e","Save","Trash2"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"injection-Dn_XqgLG.js","sources":["../../src/routes/settings/agim-skills/injection.tsx"],"sourcesContent":["/**\n * /settings/agim-skills/injection — operator-facing editor for the\n * tier-1 system-prompt skill block.\n *\n * v1.2.151 — Background: every agim turn injects an auto-generated\n * skill block at the top of the system prompt so the LLM knows which\n * skills it can call. The block is computed from the loader's bucket\n * + cluster rules. When operators want to nudge it (pin a skill,\n * hide a noisy one, add a routing hint about a custom env), they\n * authoring text here writes a single Markdown file\n * (`~/.agim/skill-injection-override.md`) that REPLACES the auto\n * block at injection time. Empty file == auto behaviour.\n *\n * UI:\n * · Left/top: Auto-generated block (read-only preview).\n * · Right/bottom: Operator override (editable textarea).\n * · Buttons: Save / Clear / Refresh / Copy-auto-into-override.\n * · Counters: char count for both panes + warning at ≥10k chars.\n */\n\nimport { useEffect, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Copy, Loader2, RefreshCcw, Save, Trash2 } from 'lucide-react'\n\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Label } from '@/components/ui/label'\nimport {\n useSkillInjection, useSkillInjectionSave, useSkillInjectionDelete,\n useAgimSkillsRefresh,\n} from '@/hooks/use-agim-skills'\n\nconst TOKEN_WARN_CHARS = 10_000\n\nexport function Component(): JSX.Element {\n return <InjectionEditorRoute />\n}\n\nexport default function InjectionEditorRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const query = useSkillInjection()\n const save = useSkillInjectionSave()\n const del = useSkillInjectionDelete()\n // v1.2.152 — \"Refresh\" 改成\"重建自动注入词\":先让 loader 重扫磁盘\n // (POST /api/agim-skills/refresh 会调用 invalidateSkillsCache 失效 5 分钟\n // TTL 缓存),然后再 refetch GET injection 拿到 fresh auto block。\n // override 字段不受影响。\n const refreshLoader = useAgimSkillsRefresh()\n\n // Local draft state; sync from server on first load + after a save.\n const [draft, setDraft] = useState('')\n const [touched, setTouched] = useState(false)\n\n useEffect(() => {\n if (query.data && !touched) {\n setDraft(query.data.override ?? '')\n }\n }, [query.data, touched])\n\n const auto = query.data?.auto ?? ''\n const maxChars = query.data?.maxOverrideChars ?? 40_000\n const overrideActive = query.data?.overrideActive ?? false\n const overridePath = query.data?.overridePath ?? '~/.agim/skill-injection-override.md'\n\n const draftLen = draft.length\n const overLimit = draftLen > maxChars\n\n async function onSave(): Promise<void> {\n if (overLimit) {\n toast.error(t('skillInjection.overLimitToast', { len: draftLen, max: maxChars }))\n return\n }\n try {\n const r = await save.mutateAsync(draft)\n toast.success(r.deleted ? t('skillInjection.clearedToast') : t('skillInjection.savedToast'))\n setTouched(false)\n } catch (err) {\n toast.error((err as Error)?.message ?? String(err))\n }\n }\n\n async function onClear(): Promise<void> {\n if (!confirm(t('skillInjection.confirmClear'))) return\n try {\n await del.mutateAsync()\n setDraft('')\n setTouched(false)\n toast.success(t('skillInjection.clearedToast'))\n } catch (err) {\n toast.error((err as Error)?.message ?? String(err))\n }\n }\n\n async function onRefresh(): Promise<void> {\n // Two-step: invalidate loader cache (re-scan disk) → refetch injection.\n try {\n await refreshLoader.mutateAsync()\n } catch (err) {\n toast.error((err as Error)?.message ?? String(err))\n return\n }\n await query.refetch()\n if (!touched) setDraft(query.data?.override ?? '')\n toast.success(t('skillInjection.rebuiltToast'))\n }\n\n function onCopyAuto(): void {\n setDraft(auto)\n setTouched(true)\n }\n\n return (\n <div className=\"mx-auto flex max-w-6xl flex-col gap-4\">\n <header className=\"flex items-center gap-3\">\n <h1 className=\"text-xl font-semibold\">{t('skillInjection.title')}</h1>\n {overrideActive\n ? <Badge variant=\"success\">{t('skillInjection.overrideActive')}</Badge>\n : <Badge variant=\"outline\">{t('skillInjection.overrideInactive')}</Badge>}\n <Button\n variant=\"outline\" size=\"sm\" className=\"ml-auto\"\n onClick={() => void onRefresh()}\n disabled={query.isFetching || refreshLoader.isPending}\n title={t('skillInjection.rebuildTooltip')}\n >\n {(query.isFetching || refreshLoader.isPending)\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('skillInjection.rebuild')}</span>\n </Button>\n </header>\n <p className=\"text-sm text-text-dim\">{t('skillInjection.subtitle')}</p>\n <p className=\"text-xs text-text-dim font-mono break-all\">{overridePath}</p>\n\n {/* Auto preview */}\n <section className=\"flex flex-col gap-2 rounded-md border border-border bg-surface p-3\">\n <div className=\"flex items-center gap-2\">\n <Label className=\"text-sm font-medium\">{t('skillInjection.autoLabel')}</Label>\n <Badge variant=\"outline\">{auto.length.toLocaleString()} chars</Badge>\n {auto.length >= TOKEN_WARN_CHARS && (\n <Badge variant=\"warning\">{t('skillInjection.largeWarn')}</Badge>\n )}\n <Button\n variant=\"ghost\" size=\"sm\" className=\"ml-auto\"\n onClick={onCopyAuto}\n disabled={query.isLoading}\n >\n <Copy className=\"h-4 w-4\" />\n <span className=\"hidden sm:inline\">{t('skillInjection.copyToOverride')}</span>\n </Button>\n </div>\n <textarea\n readOnly\n value={query.isLoading ? '...' : auto}\n className=\"h-64 w-full resize-y rounded border border-border bg-surface-2 p-2 font-mono text-xs\"\n aria-label={t('skillInjection.autoLabel')}\n />\n </section>\n\n {/* Override editor */}\n <section className=\"flex flex-col gap-2 rounded-md border border-border bg-surface p-3\">\n <div className=\"flex items-center gap-2\">\n <Label className=\"text-sm font-medium\">{t('skillInjection.overrideLabel')}</Label>\n <Badge variant={overLimit ? 'danger' : 'outline'}>\n {draftLen.toLocaleString()} / {maxChars.toLocaleString()} chars\n </Badge>\n {draftLen >= TOKEN_WARN_CHARS && !overLimit && (\n <Badge variant=\"warning\">{t('skillInjection.largeWarn')}</Badge>\n )}\n </div>\n <textarea\n value={draft}\n onChange={(e) => { setDraft(e.target.value); setTouched(true) }}\n placeholder={t('skillInjection.overridePlaceholder')}\n className=\"h-72 w-full resize-y rounded border border-border bg-surface-2 p-2 font-mono text-xs\"\n aria-label={t('skillInjection.overrideLabel')}\n />\n <div className=\"flex flex-wrap items-center gap-2 pt-1\">\n <Button\n onClick={() => void onSave()}\n disabled={save.isPending || overLimit}\n >\n {save.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Save className=\"h-4 w-4\" />}\n {t('skillInjection.save')}\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => void onClear()}\n disabled={del.isPending || (!overrideActive && draft.length === 0)}\n >\n {del.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Trash2 className=\"h-4 w-4\" />}\n {t('skillInjection.clear')}\n </Button>\n <span className=\"text-xs text-text-dim\">{t('skillInjection.hint')}</span>\n </div>\n </section>\n </div>\n )\n}\n"],"names":["TOKEN_WARN_CHARS","Component","InjectionEditorRoute","t","useTranslation","query","useSkillInjection","save","useSkillInjectionSave","del","useSkillInjectionDelete","refreshLoader","useAgimSkillsRefresh","draft","setDraft","useState","touched","setTouched","useEffect","auto","maxChars","overrideActive","overridePath","draftLen","overLimit","onSave","toast","r","err","onClear","onRefresh","onCopyAuto","jsxs","jsx","Badge","Button","Loader2","RefreshCcw","Label","Copy","e","Save","Trash2"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{o as C,u as v,j as e,l as b,B as y,m as S,L as M,I as L,C as O}from"./index-
|
|
1
|
+
import{o as C,u as v,j as e,l as b,B as y,m as S,L as M,I as L,C as O}from"./index-DHh1LYlA.js";import{r as x}from"./react-DlP5eolq.js";import{u as P,a as R,b as T,c as z,d as F,e as D}from"./use-agim-skills-pFjfgqMF.js";import{L as N}from"./loader-circle-DgdBWYl0.js";import{R as q}from"./refresh-ccw-nBMm5Xal.js";import{S as K}from"./search-DbE4VEm9.js";import{C as W}from"./chevron-right-DrkYVi19.js";import{T as V}from"./trash-2-7xrfqd-v.js";import{S as H}from"./save-DbrrCFDM.js";/**
|
|
2
2
|
* @license lucide-react v0.469.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -28,4 +28,4 @@ Write the body the agent should read when this skill applies.
|
|
|
28
28
|
1. step one
|
|
29
29
|
2. step two
|
|
30
30
|
`;function ne(){const{t:s}=v(["settings","common"]),l=P(),h=R(),[t,a]=x.useState(null);x.useEffect(()=>{!t&&l.data?.skills.length&&a(l.data.skills[0]?.name??null)},[t,l.data]);const u=l.data?.skills??[],p=l.data?.maxBodyChars??32e3;async function g(){try{const o=await h.mutateAsync();S.success(s("agimSkills.reloadedToast",{count:o.count}))}catch(o){S.error(o?.message??String(o))}}return e.jsxs("div",{className:"mx-auto flex max-w-6xl flex-col gap-4",children:[e.jsxs("header",{className:"flex items-center gap-3",children:[e.jsx(I,{className:"h-5 w-5 text-text-dim"}),e.jsx("h1",{className:"text-xl font-semibold",children:s("agimSkills.title")}),e.jsx(b,{variant:"info",children:u.length}),e.jsxs(y,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>void g(),disabled:h.isPending,children:[h.isPending?e.jsx(N,{className:"h-4 w-4 animate-spin"}):e.jsx(q,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:s("agimSkills.reload")})]}),e.jsx(Z,{onCreate:o=>a(o)})]}),e.jsx("p",{className:"text-sm text-text-dim",children:s("agimSkills.subtitle")}),e.jsxs("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-[280px,1fr]",children:[e.jsx($,{skills:u,selected:t,onSelect:a,loading:l.isLoading}),t?e.jsx(G,{name:t,maxBody:p,onDeleted:()=>a(null)},t):e.jsx("section",{className:"flex items-center justify-center rounded-md border border-border bg-surface p-12 text-sm text-text-dim",children:s("agimSkills.selectHint")})]})]})}const w=[{bucket:0,i18nKey:"agimSkills.group.framework",defaultOpen:!0},{bucket:1,i18nKey:"agimSkills.group.builtin",defaultOpen:!0},{bucket:3,i18nKey:"agimSkills.group.workspace",defaultOpen:!1},{bucket:2,i18nKey:"agimSkills.group.eccPicks",defaultOpen:!0},{bucket:4,i18nKey:"agimSkills.group.eccRemainder",defaultOpen:!1}];function U(s){return typeof s.bucket=="number"?s.bucket:s.name.startsWith("agim-")?0:s.source==="builtin"&&s.description.startsWith("[ECC] ")?4:s.source==="workspace"?3:1}function $({skills:s,selected:l,onSelect:h,loading:t}){const{t:a}=v(["settings","common"]),[u,p]=x.useState(""),[g,o]=x.useState(()=>new Set(w.filter(i=>i.defaultOpen).map(i=>i.bucket))),f=x.useMemo(()=>{const i=new Map;for(const d of s){const c=U(d),m=i.get(c)??[];m.push(d),i.set(c,m)}for(const d of i.values())d.sort((c,m)=>c.name.localeCompare(m.name));return i},[s]),k=u.trim().toLowerCase(),r=x.useMemo(()=>{if(!k)return f;const i=new Map;for(const[d,c]of f){const m=c.filter(n=>n.name.toLowerCase().includes(k)||n.description.toLowerCase().includes(k));m.length>0&&i.set(d,m)}return i},[k,f]);function j(i){o(d=>{const c=new Set(d);return c.has(i)?c.delete(i):c.add(i),c})}return t?e.jsx("div",{className:"h-48 rounded-md bg-surface-2 animate-pulse"}):s.length===0?e.jsx("section",{className:"rounded-md border border-border bg-surface p-4 text-sm text-text-dim",children:a("agimSkills.emptyList")}):e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsxs("div",{className:"relative",children:[e.jsx(K,{className:"absolute left-2 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-text-dim"}),e.jsx(L,{value:u,onChange:i=>p(i.target.value),placeholder:a("agimSkills.searchPlaceholder",{defaultValue:"Filter skills..."}),className:"pl-7 text-xs h-8","aria-label":a("agimSkills.searchPlaceholder",{defaultValue:"Filter skills"})})]}),e.jsxs("nav",{className:"rounded-md border border-border bg-surface",children:[w.map(({bucket:i,i18nKey:d})=>{const c=r.get(i)??[];if(c.length===0)return null;const m=k?!0:g.has(i);return e.jsxs("section",{className:"border-b border-border last:border-b-0",children:[e.jsxs("button",{type:"button",onClick:()=>j(i),className:"flex w-full items-center gap-2 px-3 py-2 text-left text-xs font-medium hover:bg-surface-2","aria-expanded":m,children:[m?e.jsx(O,{className:"h-3.5 w-3.5 shrink-0 text-text-dim"}):e.jsx(W,{className:"h-3.5 w-3.5 shrink-0 text-text-dim"}),e.jsx("span",{className:"grow truncate",children:a(d)}),e.jsx(b,{variant:"outline",children:c.length})]}),m&&e.jsx("ul",{className:"divide-y divide-border border-t border-border bg-surface-2/40",children:c.map(n=>{const B=l===n.name,E=n.available?n.always?e.jsx(b,{variant:"success",children:a("agimSkills.alwaysOn")}):null:e.jsx(b,{variant:"outline",title:n.unavailableReason,children:a("agimSkills.unavailable")}),A=n.source==="workspace"?e.jsx(b,{variant:"info",children:a("agimSkills.sourceWs")}):e.jsx(b,{variant:"outline",children:a("agimSkills.sourceBuiltin")});return e.jsx("li",{children:e.jsxs("button",{type:"button",onClick:()=>h(n.name),className:"flex w-full flex-col items-start gap-1 px-3 py-2 text-left text-xs transition hover:bg-surface-2 "+(B?"bg-surface-2 font-semibold":""),children:[e.jsxs("span",{className:"flex w-full items-center gap-2 font-mono text-[12px]",children:[e.jsx("span",{className:"grow truncate",children:n.name}),A,E]}),e.jsx("span",{className:"line-clamp-2 text-[11px] text-text-dim",children:n.description})]})},n.name)})})]},i)}),k&&r.size===0&&e.jsx("div",{className:"px-3 py-4 text-xs text-text-dim",children:a("agimSkills.searchEmpty",{defaultValue:"No matches."})})]})]})}function G({name:s,maxBody:l,onDeleted:h}){const{t}=v(["settings","common"]),a=z(s),u=F(),p=D(),[g,o]=x.useState(""),[f,k]=x.useState("");x.useEffect(()=>{a.data&&f!==s&&(o(a.data.body),k(s))},[a.data,s,f]);const r=a.data?.meta,j=r?.source==="builtin",i=a.data?.body??"",d=x.useMemo(()=>g!==i,[g,i]);async function c(){try{await u.mutateAsync({name:s,body:g}),S.success(t("agimSkills.savedToast",{name:s}))}catch(n){S.error(n?.message??String(n))}}async function m(){if(!j&&confirm(t("agimSkills.deleteConfirm",{name:s})))try{await p.mutateAsync(s),S.success(t("agimSkills.deletedToast",{name:s})),h()}catch(n){S.error(n?.message??String(n))}}return a.isLoading?e.jsx("section",{className:"h-72 rounded-md bg-surface-2 animate-pulse"}):r?e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsxs("header",{className:"flex flex-wrap items-center gap-2 rounded-md border border-border bg-surface px-3 py-2",children:[e.jsx("span",{className:"font-mono text-sm font-semibold",children:r.name}),r.source==="workspace"?e.jsx(b,{variant:"info",children:t("agimSkills.sourceWorkspace")}):e.jsx(b,{variant:"outline",children:t("agimSkills.sourceBuiltinReadonly")}),r.always&&e.jsx(b,{variant:"success",children:t("agimSkills.alwaysOn")}),!r.available&&e.jsx(b,{variant:"outline",title:r.unavailableReason,children:t("agimSkills.unavailable")}),e.jsxs("span",{className:"ml-auto text-[11px] text-text-dim",children:[g.length," / ",l]})]}),e.jsx("textarea",{value:g,onChange:n=>o(n.target.value),disabled:j&&!d,spellCheck:!1,className:"min-h-[500px] w-full rounded-md border border-border bg-surface p-3 font-mono text-xs leading-relaxed focus:border-accent focus:outline-none"}),e.jsxs("div",{className:"text-[11px] text-text-dim",children:[t("agimSkills.pathLabel")," ",e.jsx("code",{children:r.dir})," ·",t("agimSkills.binsLabel")," ",e.jsx("code",{children:r.requiresBins.join(", ")||t("agimSkills.none")})," ·",t("agimSkills.envLabel")," ",e.jsx("code",{children:r.requiresEnv.join(", ")||t("agimSkills.none")})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[j&&e.jsx("span",{className:"text-[11px] text-text-dim",children:t("agimSkills.builtinShadowHint")}),e.jsx("span",{className:"ml-auto"}),!j&&e.jsxs(y,{variant:"ghost",size:"sm",onClick:()=>void m(),disabled:p.isPending,className:"text-danger hover:text-danger",children:[e.jsx(V,{className:"h-4 w-4"}),t("agimSkills.delete")]}),e.jsxs(y,{size:"sm",onClick:()=>void c(),disabled:u.isPending||!d,children:[u.isPending?e.jsx(N,{className:"h-4 w-4 animate-spin"}):e.jsx(H,{className:"h-4 w-4"}),t(j?"agimSkills.saveShadow":"agimSkills.save")]})]})]}):e.jsx("section",{className:"rounded-md border border-border bg-surface p-4 text-sm text-danger",children:t("agimSkills.notFound")})}function Z({onCreate:s}){const{t:l}=v(["settings","common"]),h=T(),[t,a]=x.useState(!1),[u,p]=x.useState("");async function g(o){o.preventDefault();const f=u.trim();if(!f){S.error(l("agimSkills.nameRequired"));return}if(!/^[A-Za-z0-9._-]+$/.test(f)){S.error(l("agimSkills.invalidNameChars"));return}const k=Q.replace("name: my-skill",`name: ${f}`);try{const r=await h.mutateAsync({name:f,body:k});S.success(l("agimSkills.createdToast",{name:r.meta.name})),a(!1),p(""),s(r.meta.name)}catch(r){S.error(r?.message??String(r))}}return t?e.jsxs("form",{onSubmit:o=>void g(o),className:"flex items-center gap-1",children:[e.jsx(M,{className:"sr-only",children:l("agimSkills.newName")}),e.jsx(L,{autoFocus:!0,value:u,onChange:o=>p(o.target.value),placeholder:l("agimSkills.newNamePlaceholder"),className:"h-8 w-44 font-mono text-xs"}),e.jsx(y,{type:"submit",size:"sm",disabled:h.isPending,children:h.isPending?e.jsx(N,{className:"h-4 w-4 animate-spin"}):l("agimSkills.newCreate")}),e.jsx(y,{type:"button",variant:"ghost",size:"sm",onClick:()=>{a(!1),p("")},children:l("actions.cancel",{ns:"common"})})]}):e.jsxs(y,{size:"sm",onClick:()=>a(!0),children:[e.jsx(_,{className:"h-4 w-4"})," ",l("agimSkills.new")]})}export{ne as default};
|
|
31
|
-
//# sourceMappingURL=installed-
|
|
31
|
+
//# sourceMappingURL=installed-Cet-1M2Q.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"installed-Zz34apdi.js","sources":["../../node_modules/lucide-react/dist/esm/icons/book-open.js","../../node_modules/lucide-react/dist/esm/icons/file-plus-2.js","../../src/routes/settings/agim-skills/installed.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.469.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst BookOpen = createLucideIcon(\"BookOpen\", [\n [\"path\", { d: \"M12 7v14\", key: \"1akyts\" }],\n [\n \"path\",\n {\n d: \"M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z\",\n key: \"ruj8y\"\n }\n ]\n]);\n\nexport { BookOpen as default };\n//# sourceMappingURL=book-open.js.map\n","/**\n * @license lucide-react v0.469.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst FilePlus2 = createLucideIcon(\"FilePlus2\", [\n [\"path\", { d: \"M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4\", key: \"1pf5j1\" }],\n [\"path\", { d: \"M14 2v4a2 2 0 0 0 2 2h4\", key: \"tnqrlb\" }],\n [\"path\", { d: \"M3 15h6\", key: \"4e2qda\" }],\n [\"path\", { d: \"M6 12v6\", key: \"1u72j0\" }]\n]);\n\nexport { FilePlus2 as default };\n//# sourceMappingURL=file-plus-2.js.map\n","/**\n * /settings/agim-skills — manage the agim SKILL.md library\n * (P1 follow-up).\n *\n * Two-pane layout:\n * · Left: skill list (source + availability + always-on tags;\n * click to load body into the editor).\n * · Right: SKILL.md editor (textarea) + Save + Delete (workspace\n * skills only) + Create New + Refresh from disk.\n *\n * Builtin skills are read-only here — to override one, just create\n * a workspace skill with the same name; the loader shadows builtins\n * by name (see core/skills/loader.ts § discovery + shadowing).\n */\n\nimport { useEffect, useMemo, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport {\n BookOpen, ChevronDown, ChevronRight, FilePlus2, Loader2, RefreshCcw, Save, Search, Trash2,\n} from 'lucide-react'\n\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport {\n useAgimSkillsList, useAgimSkill,\n useAgimSkillCreate, useAgimSkillUpdate, useAgimSkillDelete,\n useAgimSkillsRefresh,\n type AgimSkillMeta,\n} from '@/hooks/use-agim-skills'\n\nconst STARTER_TEMPLATE = `---\nname: my-skill\ndescription: One-line summary the LLM uses to decide whether to load this skill.\nalways: false\n---\n\n# My Skill\n\nWrite the body the agent should read when this skill applies.\n\n## When to use this skill\n\n- bullet 1\n- bullet 2\n\n## Steps\n\n1. step one\n2. step two\n`\n\nexport default function SettingsAgimSkillsRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const listQuery = useAgimSkillsList()\n const refresh = useAgimSkillsRefresh()\n const [selected, setSelected] = useState<string | null>(null)\n\n // Pre-select the first skill once the list arrives.\n useEffect(() => {\n if (!selected && listQuery.data?.skills.length) {\n setSelected(listQuery.data.skills[0]?.name ?? null)\n }\n }, [selected, listQuery.data])\n\n const skills = listQuery.data?.skills ?? []\n const maxBody = listQuery.data?.maxBodyChars ?? 32_000\n\n async function onRefresh(): Promise<void> {\n try {\n const r = await refresh.mutateAsync()\n toast.success(t('agimSkills.reloadedToast', { count: r.count }))\n } catch (err) {\n toast.error(((err as Error)?.message ?? String(err)))\n }\n }\n\n return (\n <div className=\"mx-auto flex max-w-6xl flex-col gap-4\">\n <header className=\"flex items-center gap-3\">\n <BookOpen className=\"h-5 w-5 text-text-dim\" />\n <h1 className=\"text-xl font-semibold\">{t('agimSkills.title')}</h1>\n <Badge variant=\"info\">{skills.length}</Badge>\n <Button\n variant=\"ghost\" size=\"sm\" className=\"ml-auto\"\n onClick={() => void onRefresh()}\n disabled={refresh.isPending}\n >\n {refresh.isPending\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('agimSkills.reload')}</span>\n </Button>\n <NewSkillButton onCreate={(n) => setSelected(n)} />\n </header>\n <p className=\"text-sm text-text-dim\">{t('agimSkills.subtitle')}</p>\n\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-[280px,1fr]\">\n <SkillsList\n skills={skills}\n selected={selected}\n onSelect={setSelected}\n loading={listQuery.isLoading}\n />\n {selected ? (\n <SkillEditor\n key={selected}\n name={selected}\n maxBody={maxBody}\n onDeleted={() => setSelected(null)}\n />\n ) : (\n <section className=\"flex items-center justify-center rounded-md border border-border bg-surface p-12 text-sm text-text-dim\">\n {t('agimSkills.selectHint')}\n </section>\n )}\n </div>\n </div>\n )\n}\n\n/* ─────────────── List pane ─────────────── */\n\n// v1.2.152 — bucket grouping for the installed list. Maps loader's\n// `rankSkillBucket` (0–4) to a stable display order + i18n key. Default\n// expanded vs collapsed: small curated buckets (framework / builtin /\n// ECC picks) expand on first render; the two large reservoirs (workspace\n// + ECC remainder) collapse so the page renders without throwing 300+\n// rows into the DOM tree on mount.\nconst BUCKET_DEF: ReadonlyArray<{ bucket: 0 | 1 | 2 | 3 | 4; i18nKey: string; defaultOpen: boolean }> = [\n { bucket: 0, i18nKey: 'agimSkills.group.framework', defaultOpen: true },\n { bucket: 1, i18nKey: 'agimSkills.group.builtin', defaultOpen: true },\n { bucket: 3, i18nKey: 'agimSkills.group.workspace', defaultOpen: false },\n { bucket: 2, i18nKey: 'agimSkills.group.eccPicks', defaultOpen: true },\n { bucket: 4, i18nKey: 'agimSkills.group.eccRemainder', defaultOpen: false },\n]\n\nfunction bucketOf(s: AgimSkillMeta): 0 | 1 | 2 | 3 | 4 {\n // Server tells us via the `bucket` field (v1.2.152+); fall back to a\n // best-effort client-side derivation for older agim servers.\n if (typeof s.bucket === 'number') return s.bucket\n if (s.name.startsWith('agim-')) return 0\n const isEcc = s.source === 'builtin' && s.description.startsWith('[ECC] ')\n if (isEcc) return 4\n if (s.source === 'workspace') return 3\n return 1\n}\n\nfunction SkillsList({\n skills, selected, onSelect, loading,\n}: { skills: AgimSkillMeta[]; selected: string | null; onSelect: (n: string) => void; loading: boolean }): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const [query, setQuery] = useState('')\n const [openBuckets, setOpenBuckets] = useState<Set<number>>(\n () => new Set(BUCKET_DEF.filter((d) => d.defaultOpen).map((d) => d.bucket)),\n )\n\n // Group skills by bucket. Each bucket sorted alphabetically.\n const grouped = useMemo(() => {\n const m = new Map<number, AgimSkillMeta[]>()\n for (const s of skills) {\n const b = bucketOf(s)\n const arr = m.get(b) ?? []\n arr.push(s)\n m.set(b, arr)\n }\n for (const arr of m.values()) arr.sort((a, b) => a.name.localeCompare(b.name))\n return m\n }, [skills])\n\n // Active search => filter + flatten. Bucket headers still show with\n // their per-bucket match count; matching groups auto-expand.\n const q = query.trim().toLowerCase()\n const filteredGrouped = useMemo(() => {\n if (!q) return grouped\n const m = new Map<number, AgimSkillMeta[]>()\n for (const [b, arr] of grouped) {\n const hits = arr.filter((s) =>\n s.name.toLowerCase().includes(q) || s.description.toLowerCase().includes(q),\n )\n if (hits.length > 0) m.set(b, hits)\n }\n return m\n }, [q, grouped])\n\n function toggleBucket(b: number): void {\n setOpenBuckets((prev) => {\n const next = new Set(prev)\n if (next.has(b)) next.delete(b)\n else next.add(b)\n return next\n })\n }\n\n if (loading) return <div className=\"h-48 rounded-md bg-surface-2 animate-pulse\" />\n if (skills.length === 0) {\n return (\n <section className=\"rounded-md border border-border bg-surface p-4 text-sm text-text-dim\">\n {t('agimSkills.emptyList')}\n </section>\n )\n }\n\n return (\n <div className=\"flex flex-col gap-2\">\n {/* Search box */}\n <div className=\"relative\">\n <Search className=\"absolute left-2 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-text-dim\" />\n <Input\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder={t('agimSkills.searchPlaceholder', { defaultValue: 'Filter skills...' })}\n className=\"pl-7 text-xs h-8\"\n aria-label={t('agimSkills.searchPlaceholder', { defaultValue: 'Filter skills' })}\n />\n </div>\n\n {/* Bucket groups */}\n <nav className=\"rounded-md border border-border bg-surface\">\n {BUCKET_DEF.map(({ bucket, i18nKey }) => {\n const items = filteredGrouped.get(bucket) ?? []\n if (items.length === 0) return null\n // When searching, force-open buckets that have matches.\n const open = q ? true : openBuckets.has(bucket)\n return (\n <section key={bucket} className=\"border-b border-border last:border-b-0\">\n <button\n type=\"button\"\n onClick={() => toggleBucket(bucket)}\n className=\"flex w-full items-center gap-2 px-3 py-2 text-left text-xs font-medium hover:bg-surface-2\"\n aria-expanded={open}\n >\n {open\n ? <ChevronDown className=\"h-3.5 w-3.5 shrink-0 text-text-dim\" />\n : <ChevronRight className=\"h-3.5 w-3.5 shrink-0 text-text-dim\" />}\n <span className=\"grow truncate\">{t(i18nKey)}</span>\n <Badge variant=\"outline\">{items.length}</Badge>\n </button>\n {open && (\n <ul className=\"divide-y divide-border border-t border-border bg-surface-2/40\">\n {items.map((s) => {\n const isSelected = selected === s.name\n const flag = !s.available\n ? <Badge variant=\"outline\" title={s.unavailableReason}>{t('agimSkills.unavailable')}</Badge>\n : s.always\n ? <Badge variant=\"success\">{t('agimSkills.alwaysOn')}</Badge>\n : null\n const src = s.source === 'workspace'\n ? <Badge variant=\"info\">{t('agimSkills.sourceWs')}</Badge>\n : <Badge variant=\"outline\">{t('agimSkills.sourceBuiltin')}</Badge>\n return (\n <li key={s.name}>\n <button\n type=\"button\"\n onClick={() => onSelect(s.name)}\n className={\n 'flex w-full flex-col items-start gap-1 px-3 py-2 text-left text-xs transition hover:bg-surface-2 '\n + (isSelected ? 'bg-surface-2 font-semibold' : '')\n }\n >\n <span className=\"flex w-full items-center gap-2 font-mono text-[12px]\">\n <span className=\"grow truncate\">{s.name}</span>\n {src}\n {flag}\n </span>\n <span className=\"line-clamp-2 text-[11px] text-text-dim\">{s.description}</span>\n </button>\n </li>\n )\n })}\n </ul>\n )}\n </section>\n )\n })}\n {q && filteredGrouped.size === 0 && (\n <div className=\"px-3 py-4 text-xs text-text-dim\">\n {t('agimSkills.searchEmpty', { defaultValue: 'No matches.' })}\n </div>\n )}\n </nav>\n </div>\n )\n}\n\n/* ─────────────── Editor pane ─────────────── */\n\nfunction SkillEditor({\n name, maxBody, onDeleted,\n}: { name: string; maxBody: number; onDeleted: () => void }): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const detail = useAgimSkill(name)\n const update = useAgimSkillUpdate()\n const remove = useAgimSkillDelete()\n\n const [draft, setDraft] = useState('')\n const [syncedFor, setSyncedFor] = useState<string>('')\n\n useEffect(() => {\n if (detail.data && syncedFor !== name) {\n setDraft(detail.data.body)\n setSyncedFor(name)\n }\n }, [detail.data, name, syncedFor])\n\n const meta = detail.data?.meta\n const isBuiltin = meta?.source === 'builtin'\n const initial = detail.data?.body ?? ''\n const isDirty = useMemo(() => draft !== initial, [draft, initial])\n\n async function onSave(): Promise<void> {\n try {\n await update.mutateAsync({ name, body: draft })\n toast.success(t('agimSkills.savedToast', { name }))\n } catch (err) {\n toast.error(((err as Error)?.message ?? String(err)))\n }\n }\n\n async function onDelete(): Promise<void> {\n if (isBuiltin) return\n if (!confirm(t('agimSkills.deleteConfirm', { name }))) return\n try {\n await remove.mutateAsync(name)\n toast.success(t('agimSkills.deletedToast', { name }))\n onDeleted()\n } catch (err) {\n toast.error(((err as Error)?.message ?? String(err)))\n }\n }\n\n if (detail.isLoading) return <section className=\"h-72 rounded-md bg-surface-2 animate-pulse\" />\n if (!meta) return <section className=\"rounded-md border border-border bg-surface p-4 text-sm text-danger\">{t('agimSkills.notFound')}</section>\n\n return (\n <section className=\"flex flex-col gap-2\">\n <header className=\"flex flex-wrap items-center gap-2 rounded-md border border-border bg-surface px-3 py-2\">\n <span className=\"font-mono text-sm font-semibold\">{meta.name}</span>\n {meta.source === 'workspace'\n ? <Badge variant=\"info\">{t('agimSkills.sourceWorkspace')}</Badge>\n : <Badge variant=\"outline\">{t('agimSkills.sourceBuiltinReadonly')}</Badge>}\n {meta.always && <Badge variant=\"success\">{t('agimSkills.alwaysOn')}</Badge>}\n {!meta.available && <Badge variant=\"outline\" title={meta.unavailableReason}>{t('agimSkills.unavailable')}</Badge>}\n <span className=\"ml-auto text-[11px] text-text-dim\">{draft.length} / {maxBody}</span>\n </header>\n <textarea\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n disabled={isBuiltin && !isDirty}\n spellCheck={false}\n className=\"min-h-[500px] w-full rounded-md border border-border bg-surface p-3 font-mono text-xs leading-relaxed focus:border-accent focus:outline-none\"\n />\n <div className=\"text-[11px] text-text-dim\">\n {t('agimSkills.pathLabel')} <code>{meta.dir}</code> ·\n {t('agimSkills.binsLabel')} <code>{meta.requiresBins.join(', ') || t('agimSkills.none')}</code> ·\n {t('agimSkills.envLabel')} <code>{meta.requiresEnv.join(', ') || t('agimSkills.none')}</code>\n </div>\n <div className=\"flex items-center gap-2\">\n {isBuiltin && (\n <span className=\"text-[11px] text-text-dim\">\n {t('agimSkills.builtinShadowHint')}\n </span>\n )}\n <span className=\"ml-auto\" />\n {!isBuiltin && (\n <Button\n variant=\"ghost\" size=\"sm\"\n onClick={() => void onDelete()}\n disabled={remove.isPending}\n className=\"text-danger hover:text-danger\"\n >\n <Trash2 className=\"h-4 w-4\" />\n {t('agimSkills.delete')}\n </Button>\n )}\n <Button\n size=\"sm\"\n onClick={() => void onSave()}\n disabled={update.isPending || !isDirty}\n >\n {update.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Save className=\"h-4 w-4\" />}\n {isBuiltin ? t('agimSkills.saveShadow') : t('agimSkills.save')}\n </Button>\n </div>\n </section>\n )\n}\n\n/* ─────────────── New skill ─────────────── */\n\nfunction NewSkillButton({ onCreate }: { onCreate: (name: string) => void }): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const create = useAgimSkillCreate()\n const [open, setOpen] = useState(false)\n const [name, setName] = useState('')\n\n async function onSubmit(e: React.FormEvent): Promise<void> {\n e.preventDefault()\n const trimmed = name.trim()\n if (!trimmed) { toast.error(t('agimSkills.nameRequired')); return }\n if (!/^[A-Za-z0-9._-]+$/.test(trimmed)) {\n toast.error(t('agimSkills.invalidNameChars')); return\n }\n const body = STARTER_TEMPLATE.replace('name: my-skill', `name: ${trimmed}`)\n try {\n const r = await create.mutateAsync({ name: trimmed, body })\n toast.success(t('agimSkills.createdToast', { name: r.meta.name }))\n setOpen(false)\n setName('')\n onCreate(r.meta.name)\n } catch (err) {\n toast.error(((err as Error)?.message ?? String(err)))\n }\n }\n\n if (!open) {\n return (\n <Button size=\"sm\" onClick={() => setOpen(true)}>\n <FilePlus2 className=\"h-4 w-4\" /> {t('agimSkills.new')}\n </Button>\n )\n }\n\n return (\n <form onSubmit={(e) => void onSubmit(e)} className=\"flex items-center gap-1\">\n <Label className=\"sr-only\">{t('agimSkills.newName')}</Label>\n <Input\n autoFocus\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={t('agimSkills.newNamePlaceholder')}\n className=\"h-8 w-44 font-mono text-xs\"\n />\n <Button type=\"submit\" size=\"sm\" disabled={create.isPending}>\n {create.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : t('agimSkills.newCreate')}\n </Button>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => { setOpen(false); setName('') }}>\n {t('actions.cancel', { ns: 'common' })}\n </Button>\n </form>\n )\n}\n"],"names":["BookOpen","createLucideIcon","FilePlus2","STARTER_TEMPLATE","SettingsAgimSkillsRoute","t","useTranslation","listQuery","useAgimSkillsList","refresh","useAgimSkillsRefresh","selected","setSelected","useState","useEffect","skills","maxBody","onRefresh","r","toast","err","jsxs","jsx","Badge","Button","Loader2","RefreshCcw","NewSkillButton","n","SkillsList","SkillEditor","BUCKET_DEF","bucketOf","onSelect","loading","query","setQuery","openBuckets","setOpenBuckets","d","grouped","useMemo","m","s","b","arr","a","q","filteredGrouped","hits","toggleBucket","prev","next","Search","Input","e","bucket","i18nKey","items","open","ChevronDown","ChevronRight","isSelected","flag","src","name","onDeleted","detail","useAgimSkill","update","useAgimSkillUpdate","remove","useAgimSkillDelete","draft","setDraft","syncedFor","setSyncedFor","meta","isBuiltin","initial","isDirty","onSave","onDelete","Trash2","Save","onCreate","create","useAgimSkillCreate","setOpen","setName","onSubmit","trimmed","body","Label"],"mappings":"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","x_google_ignoreList":[0,1]}
|
|
1
|
+
{"version":3,"file":"installed-Cet-1M2Q.js","sources":["../../node_modules/lucide-react/dist/esm/icons/book-open.js","../../node_modules/lucide-react/dist/esm/icons/file-plus-2.js","../../src/routes/settings/agim-skills/installed.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.469.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst BookOpen = createLucideIcon(\"BookOpen\", [\n [\"path\", { d: \"M12 7v14\", key: \"1akyts\" }],\n [\n \"path\",\n {\n d: \"M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z\",\n key: \"ruj8y\"\n }\n ]\n]);\n\nexport { BookOpen as default };\n//# sourceMappingURL=book-open.js.map\n","/**\n * @license lucide-react v0.469.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst FilePlus2 = createLucideIcon(\"FilePlus2\", [\n [\"path\", { d: \"M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4\", key: \"1pf5j1\" }],\n [\"path\", { d: \"M14 2v4a2 2 0 0 0 2 2h4\", key: \"tnqrlb\" }],\n [\"path\", { d: \"M3 15h6\", key: \"4e2qda\" }],\n [\"path\", { d: \"M6 12v6\", key: \"1u72j0\" }]\n]);\n\nexport { FilePlus2 as default };\n//# sourceMappingURL=file-plus-2.js.map\n","/**\n * /settings/agim-skills — manage the agim SKILL.md library\n * (P1 follow-up).\n *\n * Two-pane layout:\n * · Left: skill list (source + availability + always-on tags;\n * click to load body into the editor).\n * · Right: SKILL.md editor (textarea) + Save + Delete (workspace\n * skills only) + Create New + Refresh from disk.\n *\n * Builtin skills are read-only here — to override one, just create\n * a workspace skill with the same name; the loader shadows builtins\n * by name (see core/skills/loader.ts § discovery + shadowing).\n */\n\nimport { useEffect, useMemo, useState } from 'react'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport {\n BookOpen, ChevronDown, ChevronRight, FilePlus2, Loader2, RefreshCcw, Save, Search, Trash2,\n} from 'lucide-react'\n\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport {\n useAgimSkillsList, useAgimSkill,\n useAgimSkillCreate, useAgimSkillUpdate, useAgimSkillDelete,\n useAgimSkillsRefresh,\n type AgimSkillMeta,\n} from '@/hooks/use-agim-skills'\n\nconst STARTER_TEMPLATE = `---\nname: my-skill\ndescription: One-line summary the LLM uses to decide whether to load this skill.\nalways: false\n---\n\n# My Skill\n\nWrite the body the agent should read when this skill applies.\n\n## When to use this skill\n\n- bullet 1\n- bullet 2\n\n## Steps\n\n1. step one\n2. step two\n`\n\nexport default function SettingsAgimSkillsRoute(): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const listQuery = useAgimSkillsList()\n const refresh = useAgimSkillsRefresh()\n const [selected, setSelected] = useState<string | null>(null)\n\n // Pre-select the first skill once the list arrives.\n useEffect(() => {\n if (!selected && listQuery.data?.skills.length) {\n setSelected(listQuery.data.skills[0]?.name ?? null)\n }\n }, [selected, listQuery.data])\n\n const skills = listQuery.data?.skills ?? []\n const maxBody = listQuery.data?.maxBodyChars ?? 32_000\n\n async function onRefresh(): Promise<void> {\n try {\n const r = await refresh.mutateAsync()\n toast.success(t('agimSkills.reloadedToast', { count: r.count }))\n } catch (err) {\n toast.error(((err as Error)?.message ?? String(err)))\n }\n }\n\n return (\n <div className=\"mx-auto flex max-w-6xl flex-col gap-4\">\n <header className=\"flex items-center gap-3\">\n <BookOpen className=\"h-5 w-5 text-text-dim\" />\n <h1 className=\"text-xl font-semibold\">{t('agimSkills.title')}</h1>\n <Badge variant=\"info\">{skills.length}</Badge>\n <Button\n variant=\"ghost\" size=\"sm\" className=\"ml-auto\"\n onClick={() => void onRefresh()}\n disabled={refresh.isPending}\n >\n {refresh.isPending\n ? <Loader2 className=\"h-4 w-4 animate-spin\" />\n : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('agimSkills.reload')}</span>\n </Button>\n <NewSkillButton onCreate={(n) => setSelected(n)} />\n </header>\n <p className=\"text-sm text-text-dim\">{t('agimSkills.subtitle')}</p>\n\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-[280px,1fr]\">\n <SkillsList\n skills={skills}\n selected={selected}\n onSelect={setSelected}\n loading={listQuery.isLoading}\n />\n {selected ? (\n <SkillEditor\n key={selected}\n name={selected}\n maxBody={maxBody}\n onDeleted={() => setSelected(null)}\n />\n ) : (\n <section className=\"flex items-center justify-center rounded-md border border-border bg-surface p-12 text-sm text-text-dim\">\n {t('agimSkills.selectHint')}\n </section>\n )}\n </div>\n </div>\n )\n}\n\n/* ─────────────── List pane ─────────────── */\n\n// v1.2.152 — bucket grouping for the installed list. Maps loader's\n// `rankSkillBucket` (0–4) to a stable display order + i18n key. Default\n// expanded vs collapsed: small curated buckets (framework / builtin /\n// ECC picks) expand on first render; the two large reservoirs (workspace\n// + ECC remainder) collapse so the page renders without throwing 300+\n// rows into the DOM tree on mount.\nconst BUCKET_DEF: ReadonlyArray<{ bucket: 0 | 1 | 2 | 3 | 4; i18nKey: string; defaultOpen: boolean }> = [\n { bucket: 0, i18nKey: 'agimSkills.group.framework', defaultOpen: true },\n { bucket: 1, i18nKey: 'agimSkills.group.builtin', defaultOpen: true },\n { bucket: 3, i18nKey: 'agimSkills.group.workspace', defaultOpen: false },\n { bucket: 2, i18nKey: 'agimSkills.group.eccPicks', defaultOpen: true },\n { bucket: 4, i18nKey: 'agimSkills.group.eccRemainder', defaultOpen: false },\n]\n\nfunction bucketOf(s: AgimSkillMeta): 0 | 1 | 2 | 3 | 4 {\n // Server tells us via the `bucket` field (v1.2.152+); fall back to a\n // best-effort client-side derivation for older agim servers.\n if (typeof s.bucket === 'number') return s.bucket\n if (s.name.startsWith('agim-')) return 0\n const isEcc = s.source === 'builtin' && s.description.startsWith('[ECC] ')\n if (isEcc) return 4\n if (s.source === 'workspace') return 3\n return 1\n}\n\nfunction SkillsList({\n skills, selected, onSelect, loading,\n}: { skills: AgimSkillMeta[]; selected: string | null; onSelect: (n: string) => void; loading: boolean }): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const [query, setQuery] = useState('')\n const [openBuckets, setOpenBuckets] = useState<Set<number>>(\n () => new Set(BUCKET_DEF.filter((d) => d.defaultOpen).map((d) => d.bucket)),\n )\n\n // Group skills by bucket. Each bucket sorted alphabetically.\n const grouped = useMemo(() => {\n const m = new Map<number, AgimSkillMeta[]>()\n for (const s of skills) {\n const b = bucketOf(s)\n const arr = m.get(b) ?? []\n arr.push(s)\n m.set(b, arr)\n }\n for (const arr of m.values()) arr.sort((a, b) => a.name.localeCompare(b.name))\n return m\n }, [skills])\n\n // Active search => filter + flatten. Bucket headers still show with\n // their per-bucket match count; matching groups auto-expand.\n const q = query.trim().toLowerCase()\n const filteredGrouped = useMemo(() => {\n if (!q) return grouped\n const m = new Map<number, AgimSkillMeta[]>()\n for (const [b, arr] of grouped) {\n const hits = arr.filter((s) =>\n s.name.toLowerCase().includes(q) || s.description.toLowerCase().includes(q),\n )\n if (hits.length > 0) m.set(b, hits)\n }\n return m\n }, [q, grouped])\n\n function toggleBucket(b: number): void {\n setOpenBuckets((prev) => {\n const next = new Set(prev)\n if (next.has(b)) next.delete(b)\n else next.add(b)\n return next\n })\n }\n\n if (loading) return <div className=\"h-48 rounded-md bg-surface-2 animate-pulse\" />\n if (skills.length === 0) {\n return (\n <section className=\"rounded-md border border-border bg-surface p-4 text-sm text-text-dim\">\n {t('agimSkills.emptyList')}\n </section>\n )\n }\n\n return (\n <div className=\"flex flex-col gap-2\">\n {/* Search box */}\n <div className=\"relative\">\n <Search className=\"absolute left-2 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-text-dim\" />\n <Input\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder={t('agimSkills.searchPlaceholder', { defaultValue: 'Filter skills...' })}\n className=\"pl-7 text-xs h-8\"\n aria-label={t('agimSkills.searchPlaceholder', { defaultValue: 'Filter skills' })}\n />\n </div>\n\n {/* Bucket groups */}\n <nav className=\"rounded-md border border-border bg-surface\">\n {BUCKET_DEF.map(({ bucket, i18nKey }) => {\n const items = filteredGrouped.get(bucket) ?? []\n if (items.length === 0) return null\n // When searching, force-open buckets that have matches.\n const open = q ? true : openBuckets.has(bucket)\n return (\n <section key={bucket} className=\"border-b border-border last:border-b-0\">\n <button\n type=\"button\"\n onClick={() => toggleBucket(bucket)}\n className=\"flex w-full items-center gap-2 px-3 py-2 text-left text-xs font-medium hover:bg-surface-2\"\n aria-expanded={open}\n >\n {open\n ? <ChevronDown className=\"h-3.5 w-3.5 shrink-0 text-text-dim\" />\n : <ChevronRight className=\"h-3.5 w-3.5 shrink-0 text-text-dim\" />}\n <span className=\"grow truncate\">{t(i18nKey)}</span>\n <Badge variant=\"outline\">{items.length}</Badge>\n </button>\n {open && (\n <ul className=\"divide-y divide-border border-t border-border bg-surface-2/40\">\n {items.map((s) => {\n const isSelected = selected === s.name\n const flag = !s.available\n ? <Badge variant=\"outline\" title={s.unavailableReason}>{t('agimSkills.unavailable')}</Badge>\n : s.always\n ? <Badge variant=\"success\">{t('agimSkills.alwaysOn')}</Badge>\n : null\n const src = s.source === 'workspace'\n ? <Badge variant=\"info\">{t('agimSkills.sourceWs')}</Badge>\n : <Badge variant=\"outline\">{t('agimSkills.sourceBuiltin')}</Badge>\n return (\n <li key={s.name}>\n <button\n type=\"button\"\n onClick={() => onSelect(s.name)}\n className={\n 'flex w-full flex-col items-start gap-1 px-3 py-2 text-left text-xs transition hover:bg-surface-2 '\n + (isSelected ? 'bg-surface-2 font-semibold' : '')\n }\n >\n <span className=\"flex w-full items-center gap-2 font-mono text-[12px]\">\n <span className=\"grow truncate\">{s.name}</span>\n {src}\n {flag}\n </span>\n <span className=\"line-clamp-2 text-[11px] text-text-dim\">{s.description}</span>\n </button>\n </li>\n )\n })}\n </ul>\n )}\n </section>\n )\n })}\n {q && filteredGrouped.size === 0 && (\n <div className=\"px-3 py-4 text-xs text-text-dim\">\n {t('agimSkills.searchEmpty', { defaultValue: 'No matches.' })}\n </div>\n )}\n </nav>\n </div>\n )\n}\n\n/* ─────────────── Editor pane ─────────────── */\n\nfunction SkillEditor({\n name, maxBody, onDeleted,\n}: { name: string; maxBody: number; onDeleted: () => void }): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const detail = useAgimSkill(name)\n const update = useAgimSkillUpdate()\n const remove = useAgimSkillDelete()\n\n const [draft, setDraft] = useState('')\n const [syncedFor, setSyncedFor] = useState<string>('')\n\n useEffect(() => {\n if (detail.data && syncedFor !== name) {\n setDraft(detail.data.body)\n setSyncedFor(name)\n }\n }, [detail.data, name, syncedFor])\n\n const meta = detail.data?.meta\n const isBuiltin = meta?.source === 'builtin'\n const initial = detail.data?.body ?? ''\n const isDirty = useMemo(() => draft !== initial, [draft, initial])\n\n async function onSave(): Promise<void> {\n try {\n await update.mutateAsync({ name, body: draft })\n toast.success(t('agimSkills.savedToast', { name }))\n } catch (err) {\n toast.error(((err as Error)?.message ?? String(err)))\n }\n }\n\n async function onDelete(): Promise<void> {\n if (isBuiltin) return\n if (!confirm(t('agimSkills.deleteConfirm', { name }))) return\n try {\n await remove.mutateAsync(name)\n toast.success(t('agimSkills.deletedToast', { name }))\n onDeleted()\n } catch (err) {\n toast.error(((err as Error)?.message ?? String(err)))\n }\n }\n\n if (detail.isLoading) return <section className=\"h-72 rounded-md bg-surface-2 animate-pulse\" />\n if (!meta) return <section className=\"rounded-md border border-border bg-surface p-4 text-sm text-danger\">{t('agimSkills.notFound')}</section>\n\n return (\n <section className=\"flex flex-col gap-2\">\n <header className=\"flex flex-wrap items-center gap-2 rounded-md border border-border bg-surface px-3 py-2\">\n <span className=\"font-mono text-sm font-semibold\">{meta.name}</span>\n {meta.source === 'workspace'\n ? <Badge variant=\"info\">{t('agimSkills.sourceWorkspace')}</Badge>\n : <Badge variant=\"outline\">{t('agimSkills.sourceBuiltinReadonly')}</Badge>}\n {meta.always && <Badge variant=\"success\">{t('agimSkills.alwaysOn')}</Badge>}\n {!meta.available && <Badge variant=\"outline\" title={meta.unavailableReason}>{t('agimSkills.unavailable')}</Badge>}\n <span className=\"ml-auto text-[11px] text-text-dim\">{draft.length} / {maxBody}</span>\n </header>\n <textarea\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n disabled={isBuiltin && !isDirty}\n spellCheck={false}\n className=\"min-h-[500px] w-full rounded-md border border-border bg-surface p-3 font-mono text-xs leading-relaxed focus:border-accent focus:outline-none\"\n />\n <div className=\"text-[11px] text-text-dim\">\n {t('agimSkills.pathLabel')} <code>{meta.dir}</code> ·\n {t('agimSkills.binsLabel')} <code>{meta.requiresBins.join(', ') || t('agimSkills.none')}</code> ·\n {t('agimSkills.envLabel')} <code>{meta.requiresEnv.join(', ') || t('agimSkills.none')}</code>\n </div>\n <div className=\"flex items-center gap-2\">\n {isBuiltin && (\n <span className=\"text-[11px] text-text-dim\">\n {t('agimSkills.builtinShadowHint')}\n </span>\n )}\n <span className=\"ml-auto\" />\n {!isBuiltin && (\n <Button\n variant=\"ghost\" size=\"sm\"\n onClick={() => void onDelete()}\n disabled={remove.isPending}\n className=\"text-danger hover:text-danger\"\n >\n <Trash2 className=\"h-4 w-4\" />\n {t('agimSkills.delete')}\n </Button>\n )}\n <Button\n size=\"sm\"\n onClick={() => void onSave()}\n disabled={update.isPending || !isDirty}\n >\n {update.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Save className=\"h-4 w-4\" />}\n {isBuiltin ? t('agimSkills.saveShadow') : t('agimSkills.save')}\n </Button>\n </div>\n </section>\n )\n}\n\n/* ─────────────── New skill ─────────────── */\n\nfunction NewSkillButton({ onCreate }: { onCreate: (name: string) => void }): JSX.Element {\n const { t } = useTranslation(['settings', 'common'])\n const create = useAgimSkillCreate()\n const [open, setOpen] = useState(false)\n const [name, setName] = useState('')\n\n async function onSubmit(e: React.FormEvent): Promise<void> {\n e.preventDefault()\n const trimmed = name.trim()\n if (!trimmed) { toast.error(t('agimSkills.nameRequired')); return }\n if (!/^[A-Za-z0-9._-]+$/.test(trimmed)) {\n toast.error(t('agimSkills.invalidNameChars')); return\n }\n const body = STARTER_TEMPLATE.replace('name: my-skill', `name: ${trimmed}`)\n try {\n const r = await create.mutateAsync({ name: trimmed, body })\n toast.success(t('agimSkills.createdToast', { name: r.meta.name }))\n setOpen(false)\n setName('')\n onCreate(r.meta.name)\n } catch (err) {\n toast.error(((err as Error)?.message ?? String(err)))\n }\n }\n\n if (!open) {\n return (\n <Button size=\"sm\" onClick={() => setOpen(true)}>\n <FilePlus2 className=\"h-4 w-4\" /> {t('agimSkills.new')}\n </Button>\n )\n }\n\n return (\n <form onSubmit={(e) => void onSubmit(e)} className=\"flex items-center gap-1\">\n <Label className=\"sr-only\">{t('agimSkills.newName')}</Label>\n <Input\n autoFocus\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder={t('agimSkills.newNamePlaceholder')}\n className=\"h-8 w-44 font-mono text-xs\"\n />\n <Button type=\"submit\" size=\"sm\" disabled={create.isPending}>\n {create.isPending ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : t('agimSkills.newCreate')}\n </Button>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => { setOpen(false); setName('') }}>\n {t('actions.cancel', { ns: 'common' })}\n </Button>\n </form>\n )\n}\n"],"names":["BookOpen","createLucideIcon","FilePlus2","STARTER_TEMPLATE","SettingsAgimSkillsRoute","t","useTranslation","listQuery","useAgimSkillsList","refresh","useAgimSkillsRefresh","selected","setSelected","useState","useEffect","skills","maxBody","onRefresh","r","toast","err","jsxs","jsx","Badge","Button","Loader2","RefreshCcw","NewSkillButton","n","SkillsList","SkillEditor","BUCKET_DEF","bucketOf","onSelect","loading","query","setQuery","openBuckets","setOpenBuckets","d","grouped","useMemo","m","s","b","arr","a","q","filteredGrouped","hits","toggleBucket","prev","next","Search","Input","e","bucket","i18nKey","items","open","ChevronDown","ChevronRight","isSelected","flag","src","name","onDeleted","detail","useAgimSkill","update","useAgimSkillUpdate","remove","useAgimSkillDelete","draft","setDraft","syncedFor","setSyncedFor","meta","isBuiltin","initial","isDirty","onSave","onDelete","Trash2","Save","onCreate","create","useAgimSkillCreate","setOpen","setName","onSubmit","trimmed","body","Label"],"mappings":"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","x_google_ignoreList":[0,1]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as D,b as q,d as M,e as I,u as V,f as K,j as t,c as A,B as P,S as Q,g as U,h as z,i as G,k as T,l as X,m as O,n as Y}from"./index-
|
|
2
|
-
//# sourceMappingURL=jobs-
|
|
1
|
+
import{a as D,b as q,d as M,e as I,u as V,f as K,j as t,c as A,B as P,S as Q,g as U,h as z,i as G,k as T,l as X,m as O,n as Y}from"./index-DHh1LYlA.js";import{r as u}from"./react-DlP5eolq.js";import{D as H}from"./data-table-DOKUic1J.js";import{E as W}from"./empty-state-CTwOQemt.js";import{S as Z}from"./status-badge-D5xhwquL.js";import{P as ee}from"./pagination-DkdCTctJ.js";import{C as te}from"./confirm-dialog-gPKJnvEW.js";import{u as se}from"./use-event-stream-I1lMFEfh.js";import{L as ae}from"./loader-circle-DgdBWYl0.js";import{R as ne}from"./refresh-ccw-nBMm5Xal.js";import{C as ie}from"./circle-x-DHK7ypFY.js";import{B as oe}from"./briefcase-DUXbR4xs.js";import"./table-Dx65w6V0.js";import"./arrow-up-i_dEdXkz.js";import"./arrow-down-B8DkdbEY.js";import"./chevron-left-RC6mMSiX.js";import"./chevron-right-DrkYVi19.js";const N={all:["jobs"],list:e=>["jobs","list",e]};function re(e){return q({queryKey:N.list(e),queryFn:()=>M.listJobs(e)})}function le(){const e=D();return()=>e.invalidateQueries({queryKey:N.all})}function ce(){const e=D();return I({mutationFn:a=>M.batchCancelJobs(a),onSuccess:()=>e.invalidateQueries({queryKey:N.all})})}const de=[10,20,50,100],E=20,me=["pending","running","completed","delivered","failed","cancelled","interrupted","replaced","abandoned"],ue={connected:"text-success",connecting:"text-text-dim",reconnecting:"text-warning",closed:"text-text-muted"};function Ae(){const{t:e}=V(["tasks","common"]),[a,i]=K(),d=le(),r=Math.max(1,Number(a.get("page"))||1),l=Number(a.get("per_page"))||E,m=a.get("status")??null,L=u.useMemo(()=>({limit:l,offset:(r-1)*l,...m?{status:m}:{}}),[r,l,m]),{data:S,isLoading:R,isFetching:C,refetch:$}=re(L),h=S?.jobs??[],n=S?.stats,v=se({job:()=>d()}),[p,w]=u.useState(new Set),[B,y]=u.useState(!1),_=ce();async function F(){const s=Array.from(p).map(Number).filter(Number.isFinite);if(s.length!==0)try{await _.mutateAsync({ids:s}),w(new Set),O.success(e("states.saved",{ns:"common"}))}catch(o){const{message:c}=Y(o,e);throw O.error(c),o}}function f(s){const o=new URLSearchParams(a);for(const[c,j]of Object.entries(s))j==null||j===""?o.delete(c):o.set(c,j);Object.keys(s).some(c=>c!=="page")&&o.delete("page"),i(o,{replace:!1})}const g=n?n.pending+n.running+n.completed+n.failed+(n.delivered??0):void 0,k=g?Math.max(1,Math.ceil(g/l)):h.length===l?r+1:r,J=u.useMemo(()=>[{id:"id",header:e("jobs.col.id"),cell:s=>t.jsxs("span",{className:"tabular-nums text-text-dim",children:["#",s.id]}),headClassName:"w-16",hideOnMobile:!1},{id:"agent",header:e("jobs.col.agent"),cell:s=>t.jsx("span",{className:"font-medium",children:s.agent}),headClassName:"w-32"},{id:"prompt",header:e("jobs.col.prompt"),cell:s=>t.jsx("span",{className:"line-clamp-2 text-text-dim",children:s.prompt}),asCardTitle:!0},{id:"status",header:e("jobs.col.status"),cell:s=>t.jsx(Z,{status:s.status,children:e(`jobs.status.${s.status}`,{defaultValue:s.status})}),headClassName:"w-32"},{id:"createdAt",header:e("jobs.col.createdAt"),cell:s=>t.jsx("span",{className:"text-text-dim",children:he(s.created_at)}),headClassName:"w-40",hideOnMobile:!0},{id:"duration",header:e("jobs.col.duration"),cell:s=>t.jsx("span",{className:"tabular-nums text-text-dim",children:pe(s.duration_ms)}),headClassName:"w-24",hideOnMobile:!0},{id:"cost",header:e("jobs.col.cost"),cell:s=>t.jsx("span",{className:"tabular-nums text-text-dim",children:s.cost!=null?`$${s.cost.toFixed(4)}`:"—"}),headClassName:"w-24",hideOnMobile:!0}],[e]),b=p.size;return t.jsxs("div",{className:"mx-auto flex max-w-7xl flex-col gap-4",children:[t.jsxs("header",{className:"flex flex-col gap-1",children:[t.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[t.jsx("h1",{className:"text-xl font-semibold",children:e("jobs.title")}),t.jsx("span",{className:A("text-xs font-medium tabular-nums",ue[v]),children:e(`jobs.live.${v}`)}),t.jsxs(P,{variant:"ghost",size:"sm",className:"ml-auto",onClick:()=>$(),disabled:C,"aria-label":e("actions.refresh",{ns:"common"}),children:[C?t.jsx(ae,{className:"h-4 w-4 animate-spin"}):t.jsx(ne,{className:"h-4 w-4"}),t.jsx("span",{className:"hidden sm:inline",children:e("actions.refresh",{ns:"common"})})]})]}),t.jsx("p",{className:"text-sm text-text-dim",children:e("jobs.subtitle")})]}),n&&t.jsxs("div",{className:"grid grid-cols-2 gap-2 sm:grid-cols-4",children:[t.jsx(x,{label:e("jobs.stats.pending"),value:n.pending,tone:"info"}),t.jsx(x,{label:e("jobs.stats.running"),value:n.running,tone:"warning"}),t.jsx(x,{label:e("jobs.stats.completed"),value:n.completed,tone:"success"}),t.jsx(x,{label:e("jobs.stats.failed"),value:n.failed,tone:"danger"})]}),t.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx("label",{className:"text-sm text-text-dim",htmlFor:"status-filter",children:e("jobs.filter.status")}),t.jsxs(Q,{value:m??"__any__",onValueChange:s=>f({status:s==="__any__"?null:s}),children:[t.jsx(U,{id:"status-filter",className:"w-[160px]",children:t.jsx(z,{})}),t.jsxs(G,{children:[t.jsx(T,{value:"__any__",children:e("jobs.filter.statusAny")}),me.map(s=>t.jsx(T,{value:s,children:e(`jobs.status.${s}`,{defaultValue:s})},s))]})]})]}),b>0&&t.jsxs("div",{className:"ml-auto flex items-center gap-2",children:[t.jsx(X,{variant:"secondary",children:e("jobs.batch.selected",{count:b})}),t.jsxs(P,{variant:"destructive",size:"sm",onClick:()=>y(!0),disabled:_.isPending,children:[t.jsx(ie,{className:"h-4 w-4"}),e("jobs.batch.cancel")]})]})]}),t.jsx(H,{columns:J,rows:h,getRowId:s=>String(s.id),loading:R,selection:p,onSelectionChange:w,emptyState:t.jsx(W,{icon:t.jsx(oe,{}),title:e("jobs.empty.title"),description:e("jobs.empty.description")})}),(h.length>0||r>1)&&t.jsx(ee,{page:r,totalPages:k,totalRows:g,perPage:l,perPageOptions:de,onPageChange:s=>f({page:s===1?null:String(s)}),onPerPageChange:s=>f({per_page:s===E?null:String(s)})}),t.jsx(te,{open:B,onOpenChange:y,title:e("jobs.batch.confirmCancel",{count:b}),description:e("jobs.batch.confirmCancelDesc"),intent:"danger",confirmLabel:e("jobs.batch.cancel"),onConfirm:F})]})}const xe={info:"border-info/30 text-info",success:"border-success/30 text-success",warning:"border-warning/30 text-warning",danger:"border-danger/30 text-danger"};function x({label:e,value:a,tone:i}){return t.jsxs("div",{className:A("rounded-md border bg-surface px-3 py-2",xe[i]),children:[t.jsx("div",{className:"text-xs uppercase tracking-wide text-text-dim",children:e}),t.jsx("div",{className:"text-2xl font-semibold tabular-nums",children:a})]})}function he(e){try{const a=new Date(e);if(Number.isNaN(a.getTime()))return e;const i=new Date;return a.toDateString()===i.toDateString()?a.toLocaleTimeString(void 0,{hour:"2-digit",minute:"2-digit",second:"2-digit"}):a.toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return e}}function pe(e){if(e==null)return"—";if(e<1e3)return`${e}ms`;const a=e/1e3;if(a<60)return`${a.toFixed(1)}s`;const i=Math.floor(a/60),d=Math.round(a-i*60);return`${i}m${d}s`}export{Ae as default};
|
|
2
|
+
//# sourceMappingURL=jobs-CfEzOOAC.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jobs-CtVRpl0r.js","sources":["../../src/hooks/use-jobs.ts","../../src/routes/tasks/jobs.tsx"],"sourcesContent":["/**\n * useJobs — react-query wrappers for the jobs domain.\n *\n * useJobs(query) — list with filter / pagination\n * useBatchCancelJobs() — bulk cancel mutation\n * useBatchRunJobs() — bulk re-run mutation\n *\n * Query keys: `['jobs', 'list', stableQuery]` so SSE invalidation\n * via useEventStream({ job: () => qc.invalidateQueries(['jobs']) })\n * clears every list view at once. The serialised query object is\n * stable across renders (react-query handles deep equality), so\n * keying on it directly is safe.\n *\n * Why hooks not raw `useQuery`: every route hits the same listJobs\n * endpoint with similar shapes; centralising the key + error toast\n * (caller-supplied) here keeps the route files focused on layout.\n */\n\nimport { useQueryClient, useMutation, useQuery } from '@tanstack/react-query'\nimport { api } from '@/lib/api/endpoints'\nimport type { BatchJobBody, ListJobsQuery, ListJobsResponse } from '@/types/api'\n\nexport const jobsKeys = {\n all: ['jobs'] as const,\n list: (q: ListJobsQuery) => ['jobs', 'list', q] as const,\n}\n\nexport function useJobs(query: ListJobsQuery) {\n return useQuery<ListJobsResponse>({\n queryKey: jobsKeys.list(query),\n queryFn: () => api.listJobs(query),\n })\n}\n\n/** Force-refresh every jobs list view. Call this from the SSE\n * `job` handler in route files. */\nexport function useInvalidateJobs() {\n const qc = useQueryClient()\n return () => qc.invalidateQueries({ queryKey: jobsKeys.all })\n}\n\nexport function useBatchCancelJobs() {\n const qc = useQueryClient()\n return useMutation({\n mutationFn: (body: BatchJobBody) => api.batchCancelJobs(body),\n onSuccess: () => qc.invalidateQueries({ queryKey: jobsKeys.all }),\n })\n}\n\nexport function useBatchRunJobs() {\n const qc = useQueryClient()\n return useMutation({\n mutationFn: (body: BatchJobBody) => api.batchRunJobs(body),\n onSuccess: () => qc.invalidateQueries({ queryKey: jobsKeys.all }),\n })\n}\n","/**\n * /tasks/jobs — the long-running agent invocations list.\n *\n * Composes every PR-8/9 primitive: DataTable + StatusBadge + Pagination\n * + ConfirmDialog + EmptyState + useEventStream. The route is a thin\n * presenter: data via useJobs (react-query), URL state via useSearchParams,\n * live refresh via the SSE `job` event invalidating the jobs query key.\n *\n * URL contract (all params optional):\n * ?page=2&per_page=20&status=running\n *\n * Why URL state rather than zustand:\n * * deep-link friendly (\"show me failed jobs page 3\")\n * * back/forward browser history navigates filter state\n * * no risk of a leftover filter showing wrong rows after route swap\n *\n * Mobile: the DataTable already swaps to a card view below md. The\n * stats strip wraps; the filter row stacks vertically.\n */\n\nimport { useMemo, useState } from 'react'\nimport { useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Briefcase, Loader2, RefreshCcw, XCircle } from 'lucide-react'\n\nimport { DataTable, type DataTableColumn } from '@/components/common/data-table'\nimport { EmptyState } from '@/components/common/empty-state'\nimport { StatusBadge } from '@/components/common/status-badge'\nimport { Pagination } from '@/components/common/pagination'\nimport { ConfirmDialog } from '@/components/common/confirm-dialog'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport {\n useJobs,\n useInvalidateJobs,\n useBatchCancelJobs,\n} from '@/hooks/use-jobs'\nimport { useEventStream, type SseStatus } from '@/hooks/use-event-stream'\nimport type { Job, JobStatus, ListJobsQuery } from '@/types/api'\nimport { describeError } from '@/lib/api/errors'\nimport { cn } from '@/lib/utils'\n\nconst PER_PAGE_OPTIONS = [10, 20, 50, 100]\nconst DEFAULT_PER_PAGE = 20\n\nconst STATUS_OPTIONS: JobStatus[] = [\n 'pending',\n 'running',\n 'completed',\n 'delivered',\n 'failed',\n 'cancelled',\n 'interrupted',\n 'replaced',\n 'abandoned',\n]\n\nconst LIVE_STATUS_CLASS: Record<SseStatus, string> = {\n connected: 'text-success',\n connecting: 'text-text-dim',\n reconnecting: 'text-warning',\n closed: 'text-text-muted',\n}\n\nexport default function JobsRoute(): JSX.Element {\n const { t } = useTranslation(['tasks', 'common'])\n const [params, setParams] = useSearchParams()\n const invalidateJobs = useInvalidateJobs()\n\n // ─── URL state ───\n const page = Math.max(1, Number(params.get('page')) || 1)\n const perPage = Number(params.get('per_page')) || DEFAULT_PER_PAGE\n const status = (params.get('status') as JobStatus | null) ?? null\n\n const query: ListJobsQuery = useMemo(\n () => ({\n limit: perPage,\n offset: (page - 1) * perPage,\n ...(status ? { status } : {}),\n }),\n [page, perPage, status],\n )\n\n const { data, isLoading, isFetching, refetch } = useJobs(query)\n const jobs = data?.jobs ?? []\n const stats = data?.stats\n\n // ─── Live refresh via SSE ───\n const live = useEventStream({\n job: () => invalidateJobs(),\n })\n\n // ─── Selection ───\n const [selection, setSelection] = useState<Set<string>>(new Set())\n\n // ─── Confirm dialog ───\n const [confirmCancelOpen, setConfirmCancelOpen] = useState(false)\n const batchCancel = useBatchCancelJobs()\n\n async function onConfirmBatchCancel(): Promise<void> {\n const ids = Array.from(selection).map(Number).filter(Number.isFinite)\n if (ids.length === 0) return\n try {\n await batchCancel.mutateAsync({ ids })\n setSelection(new Set())\n toast.success(t('states.saved', { ns: 'common' }))\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n throw err // keep dialog open\n }\n }\n\n // ─── URL writers (single source of truth for filter state) ───\n function patchParams(patch: Record<string, string | null>): void {\n const next = new URLSearchParams(params)\n for (const [k, v] of Object.entries(patch)) {\n if (v == null || v === '') next.delete(k)\n else next.set(k, v)\n }\n // Any filter change implicitly resets to page 1.\n if (Object.keys(patch).some((k) => k !== 'page')) next.delete('page')\n setParams(next, { replace: false })\n }\n\n // ─── Derived ───\n // The backend doesn't ship a true total-count field. Until it does\n // we infer pagination from the page itself: if a page returns a\n // full page, assume there's at least one more; otherwise this is\n // the last one. Stats give an exact total of pending/running but\n // not \"all kinds\", so the page label stays \"Page X of N\" with N\n // derived conservatively.\n const totalRows = stats\n ? (stats.pending + stats.running + stats.completed + stats.failed + (stats.delivered ?? 0))\n : undefined\n const totalPages = totalRows\n ? Math.max(1, Math.ceil(totalRows / perPage))\n : jobs.length === perPage ? page + 1 : page\n\n // ─── Columns ───\n const columns: DataTableColumn<Job>[] = useMemo(\n () => [\n {\n id: 'id',\n header: t('jobs.col.id'),\n cell: (r) => <span className=\"tabular-nums text-text-dim\">#{r.id}</span>,\n headClassName: 'w-16',\n hideOnMobile: false,\n },\n {\n id: 'agent',\n header: t('jobs.col.agent'),\n cell: (r) => <span className=\"font-medium\">{r.agent}</span>,\n headClassName: 'w-32',\n },\n {\n id: 'prompt',\n header: t('jobs.col.prompt'),\n cell: (r) => (\n <span className=\"line-clamp-2 text-text-dim\">{r.prompt}</span>\n ),\n asCardTitle: true,\n },\n {\n id: 'status',\n header: t('jobs.col.status'),\n cell: (r) => (\n <StatusBadge status={r.status}>\n {t(`jobs.status.${r.status}`, { defaultValue: r.status })}\n </StatusBadge>\n ),\n headClassName: 'w-32',\n },\n {\n id: 'createdAt',\n header: t('jobs.col.createdAt'),\n cell: (r) => <span className=\"text-text-dim\">{formatTime(r.created_at)}</span>,\n headClassName: 'w-40',\n hideOnMobile: true,\n },\n {\n id: 'duration',\n header: t('jobs.col.duration'),\n cell: (r) => (\n <span className=\"tabular-nums text-text-dim\">{formatDuration(r.duration_ms)}</span>\n ),\n headClassName: 'w-24',\n hideOnMobile: true,\n },\n {\n id: 'cost',\n header: t('jobs.col.cost'),\n cell: (r) => (\n <span className=\"tabular-nums text-text-dim\">\n {r.cost != null ? `$${r.cost.toFixed(4)}` : '—'}\n </span>\n ),\n headClassName: 'w-24',\n hideOnMobile: true,\n },\n ],\n [t],\n )\n\n const selectedCount = selection.size\n\n return (\n <div className=\"mx-auto flex max-w-7xl flex-col gap-4\">\n {/* Page header */}\n <header className=\"flex flex-col gap-1\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <h1 className=\"text-xl font-semibold\">{t('jobs.title')}</h1>\n <span className={cn('text-xs font-medium tabular-nums', LIVE_STATUS_CLASS[live])}>\n {t(`jobs.live.${live}`)}\n </span>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => refetch()}\n disabled={isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {isFetching ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('actions.refresh', { ns: 'common' })}</span>\n </Button>\n </div>\n <p className=\"text-sm text-text-dim\">{t('jobs.subtitle')}</p>\n </header>\n\n {/* Stats KPI strip */}\n {stats && (\n <div className=\"grid grid-cols-2 gap-2 sm:grid-cols-4\">\n <StatCard label={t('jobs.stats.pending')} value={stats.pending} tone=\"info\" />\n <StatCard label={t('jobs.stats.running')} value={stats.running} tone=\"warning\" />\n <StatCard label={t('jobs.stats.completed')} value={stats.completed} tone=\"success\" />\n <StatCard label={t('jobs.stats.failed')} value={stats.failed} tone=\"danger\" />\n </div>\n )}\n\n {/* Filter row */}\n <div className=\"flex flex-wrap items-center gap-2\">\n <div className=\"flex items-center gap-2\">\n <label className=\"text-sm text-text-dim\" htmlFor=\"status-filter\">\n {t('jobs.filter.status')}\n </label>\n <Select\n value={status ?? '__any__'}\n onValueChange={(v) => patchParams({ status: v === '__any__' ? null : v })}\n >\n <SelectTrigger id=\"status-filter\" className=\"w-[160px]\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"__any__\">{t('jobs.filter.statusAny')}</SelectItem>\n {STATUS_OPTIONS.map((s) => (\n <SelectItem key={s} value={s}>\n {t(`jobs.status.${s}`, { defaultValue: s })}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {/* Bulk action bar — appears when rows are selected. */}\n {selectedCount > 0 && (\n <div className=\"ml-auto flex items-center gap-2\">\n <Badge variant=\"secondary\">\n {t('jobs.batch.selected', { count: selectedCount })}\n </Badge>\n <Button\n variant=\"destructive\"\n size=\"sm\"\n onClick={() => setConfirmCancelOpen(true)}\n disabled={batchCancel.isPending}\n >\n <XCircle className=\"h-4 w-4\" />\n {t('jobs.batch.cancel')}\n </Button>\n </div>\n )}\n </div>\n\n {/* Table */}\n <DataTable\n columns={columns}\n rows={jobs}\n getRowId={(r) => String(r.id)}\n loading={isLoading}\n selection={selection}\n onSelectionChange={setSelection}\n emptyState={\n <EmptyState\n icon={<Briefcase />}\n title={t('jobs.empty.title')}\n description={t('jobs.empty.description')}\n />\n }\n />\n\n {/* Footer pagination */}\n {(jobs.length > 0 || page > 1) && (\n <Pagination\n page={page}\n totalPages={totalPages}\n totalRows={totalRows}\n perPage={perPage}\n perPageOptions={PER_PAGE_OPTIONS}\n onPageChange={(p) => patchParams({ page: p === 1 ? null : String(p) })}\n onPerPageChange={(pp) => patchParams({ per_page: pp === DEFAULT_PER_PAGE ? null : String(pp) })}\n />\n )}\n\n <ConfirmDialog\n open={confirmCancelOpen}\n onOpenChange={setConfirmCancelOpen}\n title={t('jobs.batch.confirmCancel', { count: selectedCount })}\n description={t('jobs.batch.confirmCancelDesc')}\n intent=\"danger\"\n confirmLabel={t('jobs.batch.cancel')}\n onConfirm={onConfirmBatchCancel}\n />\n </div>\n )\n}\n\n// ─── Helpers ───\n\ninterface StatCardProps {\n label: string\n value: number\n tone: 'info' | 'success' | 'warning' | 'danger'\n}\n\nconst TONE_STYLES: Record<StatCardProps['tone'], string> = {\n info: 'border-info/30 text-info',\n success: 'border-success/30 text-success',\n warning: 'border-warning/30 text-warning',\n danger: 'border-danger/30 text-danger',\n}\n\nfunction StatCard({ label, value, tone }: StatCardProps): JSX.Element {\n return (\n <div\n className={cn(\n 'rounded-md border bg-surface px-3 py-2',\n TONE_STYLES[tone],\n )}\n >\n <div className=\"text-xs uppercase tracking-wide text-text-dim\">{label}</div>\n <div className=\"text-2xl font-semibold tabular-nums\">{value}</div>\n </div>\n )\n}\n\nfunction formatTime(iso: string): string {\n try {\n const d = new Date(iso)\n if (Number.isNaN(d.getTime())) return iso\n const now = new Date()\n const sameDay = d.toDateString() === now.toDateString()\n if (sameDay) {\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' })\n }\n return d.toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })\n } catch {\n return iso\n }\n}\n\nfunction formatDuration(ms: number | undefined): string {\n if (ms == null) return '—'\n if (ms < 1000) return `${ms}ms`\n const s = ms / 1000\n if (s < 60) return `${s.toFixed(1)}s`\n const m = Math.floor(s / 60)\n const rs = Math.round(s - m * 60)\n return `${m}m${rs}s`\n}\n"],"names":["jobsKeys","q","useJobs","query","useQuery","api","useInvalidateJobs","qc","useQueryClient","useBatchCancelJobs","useMutation","body","PER_PAGE_OPTIONS","DEFAULT_PER_PAGE","STATUS_OPTIONS","LIVE_STATUS_CLASS","JobsRoute","t","useTranslation","params","setParams","useSearchParams","invalidateJobs","page","perPage","status","useMemo","data","isLoading","isFetching","refetch","jobs","stats","live","useEventStream","selection","setSelection","useState","confirmCancelOpen","setConfirmCancelOpen","batchCancel","onConfirmBatchCancel","ids","toast","err","message","describeError","patchParams","patch","next","k","v","totalRows","totalPages","columns","r","jsxs","jsx","StatusBadge","formatTime","formatDuration","selectedCount","cn","Button","Loader2","RefreshCcw","StatCard","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","Badge","XCircle","DataTable","EmptyState","Briefcase","Pagination","p","pp","ConfirmDialog","TONE_STYLES","label","value","tone","iso","d","now","ms","s","m","rs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"jobs-CfEzOOAC.js","sources":["../../src/hooks/use-jobs.ts","../../src/routes/tasks/jobs.tsx"],"sourcesContent":["/**\n * useJobs — react-query wrappers for the jobs domain.\n *\n * useJobs(query) — list with filter / pagination\n * useBatchCancelJobs() — bulk cancel mutation\n * useBatchRunJobs() — bulk re-run mutation\n *\n * Query keys: `['jobs', 'list', stableQuery]` so SSE invalidation\n * via useEventStream({ job: () => qc.invalidateQueries(['jobs']) })\n * clears every list view at once. The serialised query object is\n * stable across renders (react-query handles deep equality), so\n * keying on it directly is safe.\n *\n * Why hooks not raw `useQuery`: every route hits the same listJobs\n * endpoint with similar shapes; centralising the key + error toast\n * (caller-supplied) here keeps the route files focused on layout.\n */\n\nimport { useQueryClient, useMutation, useQuery } from '@tanstack/react-query'\nimport { api } from '@/lib/api/endpoints'\nimport type { BatchJobBody, ListJobsQuery, ListJobsResponse } from '@/types/api'\n\nexport const jobsKeys = {\n all: ['jobs'] as const,\n list: (q: ListJobsQuery) => ['jobs', 'list', q] as const,\n}\n\nexport function useJobs(query: ListJobsQuery) {\n return useQuery<ListJobsResponse>({\n queryKey: jobsKeys.list(query),\n queryFn: () => api.listJobs(query),\n })\n}\n\n/** Force-refresh every jobs list view. Call this from the SSE\n * `job` handler in route files. */\nexport function useInvalidateJobs() {\n const qc = useQueryClient()\n return () => qc.invalidateQueries({ queryKey: jobsKeys.all })\n}\n\nexport function useBatchCancelJobs() {\n const qc = useQueryClient()\n return useMutation({\n mutationFn: (body: BatchJobBody) => api.batchCancelJobs(body),\n onSuccess: () => qc.invalidateQueries({ queryKey: jobsKeys.all }),\n })\n}\n\nexport function useBatchRunJobs() {\n const qc = useQueryClient()\n return useMutation({\n mutationFn: (body: BatchJobBody) => api.batchRunJobs(body),\n onSuccess: () => qc.invalidateQueries({ queryKey: jobsKeys.all }),\n })\n}\n","/**\n * /tasks/jobs — the long-running agent invocations list.\n *\n * Composes every PR-8/9 primitive: DataTable + StatusBadge + Pagination\n * + ConfirmDialog + EmptyState + useEventStream. The route is a thin\n * presenter: data via useJobs (react-query), URL state via useSearchParams,\n * live refresh via the SSE `job` event invalidating the jobs query key.\n *\n * URL contract (all params optional):\n * ?page=2&per_page=20&status=running\n *\n * Why URL state rather than zustand:\n * * deep-link friendly (\"show me failed jobs page 3\")\n * * back/forward browser history navigates filter state\n * * no risk of a leftover filter showing wrong rows after route swap\n *\n * Mobile: the DataTable already swaps to a card view below md. The\n * stats strip wraps; the filter row stacks vertically.\n */\n\nimport { useMemo, useState } from 'react'\nimport { useSearchParams } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { toast } from 'sonner'\nimport { Briefcase, Loader2, RefreshCcw, XCircle } from 'lucide-react'\n\nimport { DataTable, type DataTableColumn } from '@/components/common/data-table'\nimport { EmptyState } from '@/components/common/empty-state'\nimport { StatusBadge } from '@/components/common/status-badge'\nimport { Pagination } from '@/components/common/pagination'\nimport { ConfirmDialog } from '@/components/common/confirm-dialog'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/components/ui/select'\nimport {\n useJobs,\n useInvalidateJobs,\n useBatchCancelJobs,\n} from '@/hooks/use-jobs'\nimport { useEventStream, type SseStatus } from '@/hooks/use-event-stream'\nimport type { Job, JobStatus, ListJobsQuery } from '@/types/api'\nimport { describeError } from '@/lib/api/errors'\nimport { cn } from '@/lib/utils'\n\nconst PER_PAGE_OPTIONS = [10, 20, 50, 100]\nconst DEFAULT_PER_PAGE = 20\n\nconst STATUS_OPTIONS: JobStatus[] = [\n 'pending',\n 'running',\n 'completed',\n 'delivered',\n 'failed',\n 'cancelled',\n 'interrupted',\n 'replaced',\n 'abandoned',\n]\n\nconst LIVE_STATUS_CLASS: Record<SseStatus, string> = {\n connected: 'text-success',\n connecting: 'text-text-dim',\n reconnecting: 'text-warning',\n closed: 'text-text-muted',\n}\n\nexport default function JobsRoute(): JSX.Element {\n const { t } = useTranslation(['tasks', 'common'])\n const [params, setParams] = useSearchParams()\n const invalidateJobs = useInvalidateJobs()\n\n // ─── URL state ───\n const page = Math.max(1, Number(params.get('page')) || 1)\n const perPage = Number(params.get('per_page')) || DEFAULT_PER_PAGE\n const status = (params.get('status') as JobStatus | null) ?? null\n\n const query: ListJobsQuery = useMemo(\n () => ({\n limit: perPage,\n offset: (page - 1) * perPage,\n ...(status ? { status } : {}),\n }),\n [page, perPage, status],\n )\n\n const { data, isLoading, isFetching, refetch } = useJobs(query)\n const jobs = data?.jobs ?? []\n const stats = data?.stats\n\n // ─── Live refresh via SSE ───\n const live = useEventStream({\n job: () => invalidateJobs(),\n })\n\n // ─── Selection ───\n const [selection, setSelection] = useState<Set<string>>(new Set())\n\n // ─── Confirm dialog ───\n const [confirmCancelOpen, setConfirmCancelOpen] = useState(false)\n const batchCancel = useBatchCancelJobs()\n\n async function onConfirmBatchCancel(): Promise<void> {\n const ids = Array.from(selection).map(Number).filter(Number.isFinite)\n if (ids.length === 0) return\n try {\n await batchCancel.mutateAsync({ ids })\n setSelection(new Set())\n toast.success(t('states.saved', { ns: 'common' }))\n } catch (err) {\n const { message } = describeError(err, t)\n toast.error(message)\n throw err // keep dialog open\n }\n }\n\n // ─── URL writers (single source of truth for filter state) ───\n function patchParams(patch: Record<string, string | null>): void {\n const next = new URLSearchParams(params)\n for (const [k, v] of Object.entries(patch)) {\n if (v == null || v === '') next.delete(k)\n else next.set(k, v)\n }\n // Any filter change implicitly resets to page 1.\n if (Object.keys(patch).some((k) => k !== 'page')) next.delete('page')\n setParams(next, { replace: false })\n }\n\n // ─── Derived ───\n // The backend doesn't ship a true total-count field. Until it does\n // we infer pagination from the page itself: if a page returns a\n // full page, assume there's at least one more; otherwise this is\n // the last one. Stats give an exact total of pending/running but\n // not \"all kinds\", so the page label stays \"Page X of N\" with N\n // derived conservatively.\n const totalRows = stats\n ? (stats.pending + stats.running + stats.completed + stats.failed + (stats.delivered ?? 0))\n : undefined\n const totalPages = totalRows\n ? Math.max(1, Math.ceil(totalRows / perPage))\n : jobs.length === perPage ? page + 1 : page\n\n // ─── Columns ───\n const columns: DataTableColumn<Job>[] = useMemo(\n () => [\n {\n id: 'id',\n header: t('jobs.col.id'),\n cell: (r) => <span className=\"tabular-nums text-text-dim\">#{r.id}</span>,\n headClassName: 'w-16',\n hideOnMobile: false,\n },\n {\n id: 'agent',\n header: t('jobs.col.agent'),\n cell: (r) => <span className=\"font-medium\">{r.agent}</span>,\n headClassName: 'w-32',\n },\n {\n id: 'prompt',\n header: t('jobs.col.prompt'),\n cell: (r) => (\n <span className=\"line-clamp-2 text-text-dim\">{r.prompt}</span>\n ),\n asCardTitle: true,\n },\n {\n id: 'status',\n header: t('jobs.col.status'),\n cell: (r) => (\n <StatusBadge status={r.status}>\n {t(`jobs.status.${r.status}`, { defaultValue: r.status })}\n </StatusBadge>\n ),\n headClassName: 'w-32',\n },\n {\n id: 'createdAt',\n header: t('jobs.col.createdAt'),\n cell: (r) => <span className=\"text-text-dim\">{formatTime(r.created_at)}</span>,\n headClassName: 'w-40',\n hideOnMobile: true,\n },\n {\n id: 'duration',\n header: t('jobs.col.duration'),\n cell: (r) => (\n <span className=\"tabular-nums text-text-dim\">{formatDuration(r.duration_ms)}</span>\n ),\n headClassName: 'w-24',\n hideOnMobile: true,\n },\n {\n id: 'cost',\n header: t('jobs.col.cost'),\n cell: (r) => (\n <span className=\"tabular-nums text-text-dim\">\n {r.cost != null ? `$${r.cost.toFixed(4)}` : '—'}\n </span>\n ),\n headClassName: 'w-24',\n hideOnMobile: true,\n },\n ],\n [t],\n )\n\n const selectedCount = selection.size\n\n return (\n <div className=\"mx-auto flex max-w-7xl flex-col gap-4\">\n {/* Page header */}\n <header className=\"flex flex-col gap-1\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <h1 className=\"text-xl font-semibold\">{t('jobs.title')}</h1>\n <span className={cn('text-xs font-medium tabular-nums', LIVE_STATUS_CLASS[live])}>\n {t(`jobs.live.${live}`)}\n </span>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={() => refetch()}\n disabled={isFetching}\n aria-label={t('actions.refresh', { ns: 'common' })}\n >\n {isFetching ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <RefreshCcw className=\"h-4 w-4\" />}\n <span className=\"hidden sm:inline\">{t('actions.refresh', { ns: 'common' })}</span>\n </Button>\n </div>\n <p className=\"text-sm text-text-dim\">{t('jobs.subtitle')}</p>\n </header>\n\n {/* Stats KPI strip */}\n {stats && (\n <div className=\"grid grid-cols-2 gap-2 sm:grid-cols-4\">\n <StatCard label={t('jobs.stats.pending')} value={stats.pending} tone=\"info\" />\n <StatCard label={t('jobs.stats.running')} value={stats.running} tone=\"warning\" />\n <StatCard label={t('jobs.stats.completed')} value={stats.completed} tone=\"success\" />\n <StatCard label={t('jobs.stats.failed')} value={stats.failed} tone=\"danger\" />\n </div>\n )}\n\n {/* Filter row */}\n <div className=\"flex flex-wrap items-center gap-2\">\n <div className=\"flex items-center gap-2\">\n <label className=\"text-sm text-text-dim\" htmlFor=\"status-filter\">\n {t('jobs.filter.status')}\n </label>\n <Select\n value={status ?? '__any__'}\n onValueChange={(v) => patchParams({ status: v === '__any__' ? null : v })}\n >\n <SelectTrigger id=\"status-filter\" className=\"w-[160px]\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"__any__\">{t('jobs.filter.statusAny')}</SelectItem>\n {STATUS_OPTIONS.map((s) => (\n <SelectItem key={s} value={s}>\n {t(`jobs.status.${s}`, { defaultValue: s })}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {/* Bulk action bar — appears when rows are selected. */}\n {selectedCount > 0 && (\n <div className=\"ml-auto flex items-center gap-2\">\n <Badge variant=\"secondary\">\n {t('jobs.batch.selected', { count: selectedCount })}\n </Badge>\n <Button\n variant=\"destructive\"\n size=\"sm\"\n onClick={() => setConfirmCancelOpen(true)}\n disabled={batchCancel.isPending}\n >\n <XCircle className=\"h-4 w-4\" />\n {t('jobs.batch.cancel')}\n </Button>\n </div>\n )}\n </div>\n\n {/* Table */}\n <DataTable\n columns={columns}\n rows={jobs}\n getRowId={(r) => String(r.id)}\n loading={isLoading}\n selection={selection}\n onSelectionChange={setSelection}\n emptyState={\n <EmptyState\n icon={<Briefcase />}\n title={t('jobs.empty.title')}\n description={t('jobs.empty.description')}\n />\n }\n />\n\n {/* Footer pagination */}\n {(jobs.length > 0 || page > 1) && (\n <Pagination\n page={page}\n totalPages={totalPages}\n totalRows={totalRows}\n perPage={perPage}\n perPageOptions={PER_PAGE_OPTIONS}\n onPageChange={(p) => patchParams({ page: p === 1 ? null : String(p) })}\n onPerPageChange={(pp) => patchParams({ per_page: pp === DEFAULT_PER_PAGE ? null : String(pp) })}\n />\n )}\n\n <ConfirmDialog\n open={confirmCancelOpen}\n onOpenChange={setConfirmCancelOpen}\n title={t('jobs.batch.confirmCancel', { count: selectedCount })}\n description={t('jobs.batch.confirmCancelDesc')}\n intent=\"danger\"\n confirmLabel={t('jobs.batch.cancel')}\n onConfirm={onConfirmBatchCancel}\n />\n </div>\n )\n}\n\n// ─── Helpers ───\n\ninterface StatCardProps {\n label: string\n value: number\n tone: 'info' | 'success' | 'warning' | 'danger'\n}\n\nconst TONE_STYLES: Record<StatCardProps['tone'], string> = {\n info: 'border-info/30 text-info',\n success: 'border-success/30 text-success',\n warning: 'border-warning/30 text-warning',\n danger: 'border-danger/30 text-danger',\n}\n\nfunction StatCard({ label, value, tone }: StatCardProps): JSX.Element {\n return (\n <div\n className={cn(\n 'rounded-md border bg-surface px-3 py-2',\n TONE_STYLES[tone],\n )}\n >\n <div className=\"text-xs uppercase tracking-wide text-text-dim\">{label}</div>\n <div className=\"text-2xl font-semibold tabular-nums\">{value}</div>\n </div>\n )\n}\n\nfunction formatTime(iso: string): string {\n try {\n const d = new Date(iso)\n if (Number.isNaN(d.getTime())) return iso\n const now = new Date()\n const sameDay = d.toDateString() === now.toDateString()\n if (sameDay) {\n return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' })\n }\n return d.toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })\n } catch {\n return iso\n }\n}\n\nfunction formatDuration(ms: number | undefined): string {\n if (ms == null) return '—'\n if (ms < 1000) return `${ms}ms`\n const s = ms / 1000\n if (s < 60) return `${s.toFixed(1)}s`\n const m = Math.floor(s / 60)\n const rs = Math.round(s - m * 60)\n return `${m}m${rs}s`\n}\n"],"names":["jobsKeys","q","useJobs","query","useQuery","api","useInvalidateJobs","qc","useQueryClient","useBatchCancelJobs","useMutation","body","PER_PAGE_OPTIONS","DEFAULT_PER_PAGE","STATUS_OPTIONS","LIVE_STATUS_CLASS","JobsRoute","t","useTranslation","params","setParams","useSearchParams","invalidateJobs","page","perPage","status","useMemo","data","isLoading","isFetching","refetch","jobs","stats","live","useEventStream","selection","setSelection","useState","confirmCancelOpen","setConfirmCancelOpen","batchCancel","onConfirmBatchCancel","ids","toast","err","message","describeError","patchParams","patch","next","k","v","totalRows","totalPages","columns","r","jsxs","jsx","StatusBadge","formatTime","formatDuration","selectedCount","cn","Button","Loader2","RefreshCcw","StatCard","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","Badge","XCircle","DataTable","EmptyState","Briefcase","Pagination","p","pp","ConfirmDialog","TONE_STYLES","label","value","tone","iso","d","now","ms","s","m","rs"],"mappings":"0zBAsBO,MAAMA,EAAW,CACtB,IAAM,CAAC,MAAM,EACb,KAAOC,GAAqB,CAAC,OAAQ,OAAQA,CAAC,CAChD,EAEO,SAASC,GAAQC,EAAsB,CAC5C,OAAOC,EAA2B,CAChC,SAAUJ,EAAS,KAAKG,CAAK,EAC7B,QAAS,IAAME,EAAI,SAASF,CAAK,CAAA,CAClC,CACH,CAIO,SAASG,IAAoB,CAClC,MAAMC,EAAKC,EAAA,EACX,MAAO,IAAMD,EAAG,kBAAkB,CAAE,SAAUP,EAAS,IAAK,CAC9D,CAEO,SAASS,IAAqB,CACnC,MAAMF,EAAKC,EAAA,EACX,OAAOE,EAAY,CACjB,WAAaC,GAAuBN,EAAI,gBAAgBM,CAAI,EAC5D,UAAW,IAAMJ,EAAG,kBAAkB,CAAE,SAAUP,EAAS,IAAK,CAAA,CACjE,CACH,CCGA,MAAMY,GAAmB,CAAC,GAAI,GAAI,GAAI,GAAG,EACnCC,EAAmB,GAEnBC,GAA8B,CAClC,UACA,UACA,YACA,YACA,SACA,YACA,cACA,WACA,WACF,EAEMC,GAA+C,CACnD,UAAc,eACd,WAAc,gBACd,aAAc,eACd,OAAc,iBAChB,EAEA,SAAwBC,IAAyB,CAC/C,KAAM,CAAE,EAAAC,CAAA,EAAMC,EAAe,CAAC,QAAS,QAAQ,CAAC,EAC1C,CAACC,EAAQC,CAAS,EAAIC,EAAA,EACtBC,EAAiBhB,GAAA,EAGjBiB,EAAW,KAAK,IAAI,EAAG,OAAOJ,EAAO,IAAI,MAAM,CAAC,GAAS,CAAC,EAC1DK,EAAW,OAAOL,EAAO,IAAI,UAAU,CAAC,GAAKN,EAC7CY,EAAYN,EAAO,IAAI,QAAQ,GAA0B,KAEzDhB,EAAuBuB,EAAAA,QAC3B,KAAO,CACL,MAAQF,EACR,QAASD,EAAO,GAAKC,EACrB,GAAIC,EAAS,CAAE,OAAAA,GAAW,CAAA,CAAC,GAE7B,CAACF,EAAMC,EAASC,CAAM,CAAA,EAGlB,CAAE,KAAAE,EAAM,UAAAC,EAAW,WAAAC,EAAY,QAAAC,CAAA,EAAY5B,GAAQC,CAAK,EACxD4B,EAAOJ,GAAM,MAAQ,CAAA,EACrBK,EAAQL,GAAM,MAGdM,EAAOC,GAAe,CAC1B,IAAK,IAAMZ,EAAA,CAAe,CAC3B,EAGK,CAACa,EAAWC,CAAY,EAAIC,EAAAA,SAAsB,IAAI,GAAK,EAG3D,CAACC,EAAmBC,CAAoB,EAAIF,EAAAA,SAAS,EAAK,EAC1DG,EAAc/B,GAAA,EAEpB,eAAegC,GAAsC,CACnD,MAAMC,EAAM,MAAM,KAAKP,CAAS,EAAE,IAAI,MAAM,EAAE,OAAO,OAAO,QAAQ,EACpE,GAAIO,EAAI,SAAW,EACnB,GAAI,CACF,MAAMF,EAAY,YAAY,CAAE,IAAAE,EAAK,EACrCN,EAAa,IAAI,GAAK,EACtBO,EAAM,QAAQ1B,EAAE,eAAgB,CAAE,GAAI,QAAA,CAAU,CAAC,CACnD,OAAS2B,EAAK,CACZ,KAAM,CAAE,QAAAC,CAAA,EAAYC,EAAcF,EAAK3B,CAAC,EACxC0B,MAAAA,EAAM,MAAME,CAAO,EACbD,CACR,CACF,CAGA,SAASG,EAAYC,EAA4C,CAC/D,MAAMC,EAAO,IAAI,gBAAgB9B,CAAM,EACvC,SAAW,CAAC+B,EAAGC,CAAC,IAAK,OAAO,QAAQH,CAAK,EACnCG,GAAK,MAAQA,IAAM,GAAIF,EAAK,OAAOC,CAAC,EACnCD,EAAK,IAAIC,EAAGC,CAAC,EAGhB,OAAO,KAAKH,CAAK,EAAE,KAAME,GAAMA,IAAM,MAAM,GAAGD,EAAK,OAAO,MAAM,EACpE7B,EAAU6B,EAAM,CAAE,QAAS,EAAA,CAAO,CACpC,CASA,MAAMG,EAAYpB,EACbA,EAAM,QAAUA,EAAM,QAAUA,EAAM,UAAYA,EAAM,QAAUA,EAAM,WAAa,GACtF,OACEqB,EAAaD,EACf,KAAK,IAAI,EAAG,KAAK,KAAKA,EAAY5B,CAAO,CAAC,EAC1CO,EAAK,SAAWP,EAAUD,EAAO,EAAIA,EAGnC+B,EAAkC5B,EAAAA,QACtC,IAAM,CACJ,CACE,GAAI,KACJ,OAAQT,EAAE,aAAa,EACvB,KAAOsC,GAAMC,EAAAA,KAAC,OAAA,CAAK,UAAU,6BAA6B,SAAA,CAAA,IAAED,EAAE,EAAA,EAAG,EACjE,cAAe,OACf,aAAc,EAAA,EAEhB,CACE,GAAI,QACJ,OAAQtC,EAAE,gBAAgB,EAC1B,KAAOsC,GAAME,EAAAA,IAAC,QAAK,UAAU,cAAe,WAAE,MAAM,EACpD,cAAe,MAAA,EAEjB,CACE,GAAI,SACJ,OAAQxC,EAAE,iBAAiB,EAC3B,KAAOsC,GACLE,EAAAA,IAAC,QAAK,UAAU,6BAA8B,WAAE,OAAO,EAEzD,YAAa,EAAA,EAEf,CACE,GAAI,SACJ,OAAQxC,EAAE,iBAAiB,EAC3B,KAAOsC,SACJG,EAAA,CAAY,OAAQH,EAAE,OACpB,SAAAtC,EAAE,eAAesC,EAAE,MAAM,GAAI,CAAE,aAAcA,EAAE,MAAA,CAAQ,EAC1D,EAEF,cAAe,MAAA,EAEjB,CACE,GAAI,YACJ,OAAQtC,EAAE,oBAAoB,EAC9B,KAAOsC,GAAME,EAAAA,IAAC,OAAA,CAAK,UAAU,gBAAiB,SAAAE,GAAWJ,EAAE,UAAU,CAAA,CAAE,EACvE,cAAe,OACf,aAAc,EAAA,EAEhB,CACE,GAAI,WACJ,OAAQtC,EAAE,mBAAmB,EAC7B,KAAOsC,GACLE,EAAAA,IAAC,OAAA,CAAK,UAAU,6BAA8B,SAAAG,GAAeL,EAAE,WAAW,CAAA,CAAE,EAE9E,cAAe,OACf,aAAc,EAAA,EAEhB,CACE,GAAI,OACJ,OAAQtC,EAAE,eAAe,EACzB,KAAOsC,GACLE,MAAC,OAAA,CAAK,UAAU,6BACb,SAAAF,EAAE,MAAQ,KAAO,IAAIA,EAAE,KAAK,QAAQ,CAAC,CAAC,GAAK,IAC9C,EAEF,cAAe,OACf,aAAc,EAAA,CAChB,EAEF,CAACtC,CAAC,CAAA,EAGE4C,EAAgB1B,EAAU,KAEhC,OACEqB,EAAAA,KAAC,MAAA,CAAI,UAAU,wCAEb,SAAA,CAAAA,EAAAA,KAAC,SAAA,CAAO,UAAU,sBAChB,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,oCACb,SAAA,CAAAC,MAAC,KAAA,CAAG,UAAU,wBAAyB,SAAAxC,EAAE,YAAY,EAAE,EACvDwC,EAAAA,IAAC,OAAA,CAAK,UAAWK,EAAG,mCAAoC/C,GAAkBkB,CAAI,CAAC,EAC5E,SAAAhB,EAAE,aAAagB,CAAI,EAAE,EACxB,EACAuB,EAAAA,KAACO,EAAA,CACC,QAAQ,QACR,KAAK,KACL,UAAU,UACV,QAAS,IAAMjC,EAAA,EACf,SAAUD,EACV,aAAYZ,EAAE,kBAAmB,CAAE,GAAI,SAAU,EAEhD,SAAA,CAAAY,EAAa4B,EAAAA,IAACO,IAAQ,UAAU,sBAAA,CAAuB,EAAKP,EAAAA,IAACQ,GAAA,CAAW,UAAU,SAAA,CAAU,EAC7FR,EAAAA,IAAC,OAAA,CAAK,UAAU,mBAAoB,SAAAxC,EAAE,kBAAmB,CAAE,GAAI,QAAA,CAAU,CAAA,CAAE,CAAA,CAAA,CAAA,CAC7E,EACF,QACC,IAAA,CAAE,UAAU,wBAAyB,SAAAA,EAAE,eAAe,CAAA,CAAE,CAAA,EAC3D,EAGCe,GACCwB,EAAAA,KAAC,MAAA,CAAI,UAAU,wCACb,SAAA,CAAAC,EAAAA,IAACS,EAAA,CAAS,MAAOjD,EAAE,oBAAoB,EAAK,MAAOe,EAAM,QAAW,KAAK,MAAA,CAAO,EAChFyB,EAAAA,IAACS,EAAA,CAAS,MAAOjD,EAAE,oBAAoB,EAAK,MAAOe,EAAM,QAAW,KAAK,SAAA,CAAU,EACnFyB,EAAAA,IAACS,EAAA,CAAS,MAAOjD,EAAE,sBAAsB,EAAG,MAAOe,EAAM,UAAW,KAAK,SAAA,CAAU,EACnFyB,EAAAA,IAACS,EAAA,CAAS,MAAOjD,EAAE,mBAAmB,EAAM,MAAOe,EAAM,OAAW,KAAK,QAAA,CAAS,CAAA,EACpF,EAIFwB,EAAAA,KAAC,MAAA,CAAI,UAAU,oCACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACb,SAAA,CAAAC,EAAAA,IAAC,SAAM,UAAU,wBAAwB,QAAQ,gBAC9C,SAAAxC,EAAE,oBAAoB,EACzB,EACAuC,EAAAA,KAACW,EAAA,CACC,MAAO1C,GAAU,UACjB,cAAgB0B,GAAMJ,EAAY,CAAE,OAAQI,IAAM,UAAY,KAAOA,EAAG,EAExE,SAAA,CAAAM,EAAAA,IAACW,GAAc,GAAG,gBAAgB,UAAU,YAC1C,SAAAX,EAAAA,IAACY,IAAY,CAAA,CACf,SACCC,EAAA,CACC,SAAA,CAAAb,MAACc,EAAA,CAAW,MAAM,UAAW,SAAAtD,EAAE,uBAAuB,EAAE,EACvDH,GAAe,IAAK,GACnB2C,EAAAA,IAACc,EAAA,CAAmB,MAAO,EACxB,SAAAtD,EAAE,eAAe,CAAC,GAAI,CAAE,aAAc,EAAG,CAAA,EAD3B,CAEjB,CACD,CAAA,CAAA,CACH,CAAA,CAAA,CAAA,CACF,EACF,EAGC4C,EAAgB,GACfL,OAAC,MAAA,CAAI,UAAU,kCACb,SAAA,CAAAC,EAAAA,IAACe,EAAA,CAAM,QAAQ,YACZ,SAAAvD,EAAE,sBAAuB,CAAE,MAAO4C,CAAA,CAAe,CAAA,CACpD,EACAL,EAAAA,KAACO,EAAA,CACC,QAAQ,cACR,KAAK,KACL,QAAS,IAAMxB,EAAqB,EAAI,EACxC,SAAUC,EAAY,UAEtB,SAAA,CAAAiB,EAAAA,IAACgB,GAAA,CAAQ,UAAU,SAAA,CAAU,EAC5BxD,EAAE,mBAAmB,CAAA,CAAA,CAAA,CACxB,CAAA,CACF,CAAA,EAEJ,EAGAwC,EAAAA,IAACiB,EAAA,CACC,QAAApB,EACA,KAAMvB,EACN,SAAWwB,GAAM,OAAOA,EAAE,EAAE,EAC5B,QAAS3B,EACT,UAAAO,EACA,kBAAmBC,EACnB,WACEqB,EAAAA,IAACkB,EAAA,CACC,WAAOC,GAAA,EAAU,EACjB,MAAO3D,EAAE,kBAAkB,EAC3B,YAAaA,EAAE,wBAAwB,CAAA,CAAA,CACzC,CAAA,GAKFc,EAAK,OAAS,GAAKR,EAAO,IAC1BkC,EAAAA,IAACoB,GAAA,CACC,KAAAtD,EACA,WAAA8B,EACA,UAAAD,EACA,QAAA5B,EACA,eAAgBZ,GAChB,aAAekE,GAAM/B,EAAY,CAAE,KAAM+B,IAAM,EAAI,KAAO,OAAOA,CAAC,CAAA,CAAG,EACrE,gBAAkBC,GAAOhC,EAAY,CAAE,SAAUgC,IAAOlE,EAAmB,KAAO,OAAOkE,CAAE,CAAA,CAAG,CAAA,CAAA,EAIlGtB,EAAAA,IAACuB,GAAA,CACC,KAAM1C,EACN,aAAcC,EACd,MAAOtB,EAAE,2BAA4B,CAAE,MAAO4C,EAAe,EAC7D,YAAa5C,EAAE,8BAA8B,EAC7C,OAAO,SACP,aAAcA,EAAE,mBAAmB,EACnC,UAAWwB,CAAA,CAAA,CACb,EACF,CAEJ,CAUA,MAAMwC,GAAqD,CACzD,KAAS,8BACT,QAAS,iCACT,QAAS,iCACT,OAAS,+BACX,EAEA,SAASf,EAAS,CAAE,MAAAgB,EAAO,MAAAC,EAAO,KAAAC,GAAoC,CACpE,OACE5B,EAAAA,KAAC,MAAA,CACC,UAAWM,EACT,yCACAmB,GAAYG,CAAI,CAAA,EAGlB,SAAA,CAAA3B,EAAAA,IAAC,MAAA,CAAI,UAAU,gDAAiD,SAAAyB,EAAM,EACtEzB,EAAAA,IAAC,MAAA,CAAI,UAAU,sCAAuC,SAAA0B,CAAA,CAAM,CAAA,CAAA,CAAA,CAGlE,CAEA,SAASxB,GAAW0B,EAAqB,CACvC,GAAI,CACF,MAAMC,EAAI,IAAI,KAAKD,CAAG,EACtB,GAAI,OAAO,MAAMC,EAAE,QAAA,CAAS,EAAG,OAAOD,EACtC,MAAME,MAAU,KAEhB,OADgBD,EAAE,aAAA,IAAmBC,EAAI,aAAA,EAEhCD,EAAE,mBAAmB,OAAW,CAAE,KAAM,UAAW,OAAQ,UAAW,OAAQ,SAAA,CAAW,EAE3FA,EAAE,eAAe,OAAW,CAAE,MAAO,QAAS,IAAK,UAAW,KAAM,UAAW,OAAQ,SAAA,CAAW,CAC3G,MAAQ,CACN,OAAOD,CACT,CACF,CAEA,SAASzB,GAAe4B,EAAgC,CACtD,GAAIA,GAAM,KAAM,MAAO,IACvB,GAAIA,EAAK,IAAM,MAAO,GAAGA,CAAE,KAC3B,MAAMC,EAAID,EAAK,IACf,GAAIC,EAAI,GAAI,MAAO,GAAGA,EAAE,QAAQ,CAAC,CAAC,IAClC,MAAMC,EAAI,KAAK,MAAMD,EAAI,EAAE,EACrBE,EAAK,KAAK,MAAMF,EAAIC,EAAI,EAAE,EAChC,MAAO,GAAGA,CAAC,IAAIC,CAAE,GACnB"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{u as a,j as e,T as r,N as i,c as n,O as m}from"./index-
|
|
2
|
-
//# sourceMappingURL=layout-
|
|
1
|
+
import{u as a,j as e,T as r,N as i,c as n,O as m}from"./index-DHh1LYlA.js";import"./react-DlP5eolq.js";const u=[{to:"messengers",i18nKey:"tabs.messengers",mounted:!0},{to:"agents",i18nKey:"tabs.agents",mounted:!0},{to:"llm",i18nKey:"tabs.llm",mounted:!0},{to:"mobile",i18nKey:"tabs.mobile",mounted:!0},{to:"agim-skills",i18nKey:"tabs.agimSkills",mounted:!0},{to:"search",i18nKey:"tabs.search",mounted:!0},{to:"mcp",i18nKey:"tabs.mcp",mounted:!0},{to:"policy",i18nKey:"tabs.policy",mounted:!0},{to:"email",i18nKey:"tabs.email",mounted:!0},{to:"viewer",i18nKey:"tabs.viewer",mounted:!0},{to:"security",i18nKey:"tabs.security",mounted:!0},{to:"workspaces",i18nKey:"tabs.workspaces",mounted:!0},{to:"admins",i18nKey:"tabs.admins",mounted:!0},{to:"service",i18nKey:"tabs.service",mounted:!0}];function d(){const{t:s}=a("settings");return e.jsxs("div",{className:"flex min-h-dvh flex-col bg-bg",children:[e.jsx(r,{}),e.jsx("nav",{className:n("sticky top-0 z-10","flex items-center gap-1","border-b border-border bg-surface","px-3 sm:px-4 py-1","overflow-x-auto"),"aria-label":s("pageTitle"),children:u.filter(t=>t.mounted).map(t=>e.jsx(i,{to:t.to,className:({isActive:o})=>n("shrink-0 rounded-md px-3 py-1.5 text-sm no-underline","transition-colors tap-target",o?"bg-accent-bg text-accent font-medium":"text-text-dim hover:bg-surface-hover hover:text-text"),children:s(t.i18nKey)},t.to))}),e.jsx("main",{className:"flex-1 px-3 sm:px-4 py-4 pb-safe",children:e.jsx(m,{})})]})}export{d as default};
|
|
2
|
+
//# sourceMappingURL=layout-BX43KyXM.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout-
|
|
1
|
+
{"version":3,"file":"layout-BX43KyXM.js","sources":["../../src/routes/settings/layout.tsx"],"sourcesContent":["/**\n * /settings — layout shell with sub-tab nav (environment / service).\n *\n * Workspaces / WeChat QR / Admin allowlist will land as additional\n * sub-tabs in PR-19b/c. The `mounted` flag gates their nav links.\n */\n\nimport { NavLink, Outlet } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { Topbar } from '@/components/shell/topbar'\nimport { cn } from '@/lib/utils'\n\ninterface SubTab {\n to: string\n i18nKey: string\n mounted: boolean\n}\n\nconst SUB_TABS: SubTab[] = [\n { to: 'messengers', i18nKey: 'tabs.messengers', mounted: true },\n { to: 'agents', i18nKey: 'tabs.agents', mounted: true },\n // Stage 6 — Agim Agent stack (model APIs + runtime knobs).\n { to: 'llm', i18nKey: 'tabs.llm', mounted: true },\n // v1.2.129 — mobile QR generator (open /m/chat from a phone).\n { to: 'mobile', i18nKey: 'tabs.mobile', mounted: true },\n // P1 follow-up — agim SKILL.md editor.\n { to: 'agim-skills', i18nKey: 'tabs.agimSkills', mounted: true },\n // v1.2.126 — web_search provider chain + per-provider keys.\n { to: 'search', i18nKey: 'tabs.search', mounted: true },\n { to: 'mcp', i18nKey: 'tabs.mcp', mounted: true },\n { to: 'policy', i18nKey: 'tabs.policy', mounted: true },\n { to: 'email', i18nKey: 'tabs.email', mounted: true },\n { to: 'viewer', i18nKey: 'tabs.viewer', mounted: true },\n { to: 'security', i18nKey: 'tabs.security', mounted: true },\n { to: 'workspaces', i18nKey: 'tabs.workspaces', mounted: true },\n { to: 'admins', i18nKey: 'tabs.admins', mounted: true },\n // R13 follow-up — /settings/env catch-all editor removed; raw env-var\n // editing belongs in `~/.agim/env` on the host, not in a web form.\n { to: 'service', i18nKey: 'tabs.service', mounted: true },\n]\n\nexport default function SettingsLayout(): JSX.Element {\n const { t } = useTranslation('settings')\n return (\n <div className=\"flex min-h-dvh flex-col bg-bg\">\n <Topbar />\n\n <nav\n className={cn(\n 'sticky top-0 z-10',\n 'flex items-center gap-1',\n 'border-b border-border bg-surface',\n 'px-3 sm:px-4 py-1',\n 'overflow-x-auto',\n )}\n aria-label={t('pageTitle')}\n >\n {SUB_TABS.filter((tab) => tab.mounted).map((tab) => (\n <NavLink\n key={tab.to}\n to={tab.to}\n className={({ isActive }) =>\n cn(\n 'shrink-0 rounded-md px-3 py-1.5 text-sm no-underline',\n 'transition-colors tap-target',\n isActive\n ? 'bg-accent-bg text-accent font-medium'\n : 'text-text-dim hover:bg-surface-hover hover:text-text',\n )\n }\n >\n {t(tab.i18nKey)}\n </NavLink>\n ))}\n </nav>\n\n <main className=\"flex-1 px-3 sm:px-4 py-4 pb-safe\">\n <Outlet />\n </main>\n </div>\n )\n}\n"],"names":["SUB_TABS","SettingsLayout","t","useTranslation","jsxs","jsx","Topbar","cn","tab","NavLink","isActive","Outlet"],"mappings":"uGAkBA,MAAMA,EAAqB,CACzB,CAAE,GAAI,aAAgB,QAAS,kBAAqB,QAAS,EAAA,EAC7D,CAAE,GAAI,SAAgB,QAAS,cAAqB,QAAS,EAAA,EAE7D,CAAE,GAAI,MAAgB,QAAS,WAAqB,QAAS,EAAA,EAE7D,CAAE,GAAI,SAAgB,QAAS,cAAqB,QAAS,EAAA,EAE7D,CAAE,GAAI,cAAgB,QAAS,kBAAqB,QAAS,EAAA,EAE7D,CAAE,GAAI,SAAgB,QAAS,cAAqB,QAAS,EAAA,EAC7D,CAAE,GAAI,MAAgB,QAAS,WAAqB,QAAS,EAAA,EAC7D,CAAE,GAAI,SAAgB,QAAS,cAAqB,QAAS,EAAA,EAC7D,CAAE,GAAI,QAAgB,QAAS,aAAqB,QAAS,EAAA,EAC7D,CAAE,GAAI,SAAgB,QAAS,cAAqB,QAAS,EAAA,EAC7D,CAAE,GAAI,WAAgB,QAAS,gBAAqB,QAAS,EAAA,EAC7D,CAAE,GAAI,aAAgB,QAAS,kBAAqB,QAAS,EAAA,EAC7D,CAAE,GAAI,SAAgB,QAAS,cAAqB,QAAS,EAAA,EAG7D,CAAE,GAAI,UAAgB,QAAS,eAAqB,QAAS,EAAA,CAC/D,EAEA,SAAwBC,GAA8B,CACpD,KAAM,CAAE,EAAAC,CAAA,EAAMC,EAAe,UAAU,EACvC,OACEC,EAAAA,KAAC,MAAA,CAAI,UAAU,gCACb,SAAA,CAAAC,EAAAA,IAACC,EAAA,EAAO,EAERD,EAAAA,IAAC,MAAA,CACC,UAAWE,EACT,oBACA,0BACA,oCACA,oBACA,iBAAA,EAEF,aAAYL,EAAE,WAAW,EAExB,SAAAF,EAAS,OAAQQ,GAAQA,EAAI,OAAO,EAAE,IAAKA,GAC1CH,EAAAA,IAACI,EAAA,CAEC,GAAID,EAAI,GACR,UAAW,CAAC,CAAE,SAAAE,CAAA,IACZH,EACE,uDACA,+BACAG,EACI,uCACA,sDAAA,EAIP,SAAAR,EAAEM,EAAI,OAAO,CAAA,EAZTA,EAAI,EAAA,CAcZ,CAAA,CAAA,QAGF,OAAA,CAAK,UAAU,mCACd,SAAAH,EAAAA,IAACM,IAAO,CAAA,CACV,CAAA,EACF,CAEJ"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{u as n,j as e,T as u,N as r,c as a,O as i}from"./index-
|
|
2
|
-
//# sourceMappingURL=layout-
|
|
1
|
+
import{u as n,j as e,T as u,N as r,c as a,O as i}from"./index-DHh1LYlA.js";import"./react-DlP5eolq.js";const b=[{to:"jobs",i18nKey:"subnav.jobs",mounted:!0},{to:"subtasks",i18nKey:"subnav.subtasks",mounted:!0},{to:"bgjobs",i18nKey:"subnav.bgjobs",mounted:!0},{to:"schedules",i18nKey:"subnav.schedules",mounted:!0},{to:"outbox",i18nKey:"subnav.outbox",mounted:!0},{to:"a2a",i18nKey:"subnav.a2a",mounted:!0},{to:"heartbeat",i18nKey:"subnav.heartbeat",mounted:!0},{to:"goals",i18nKey:"subnav.goals",mounted:!0},{to:"asks",i18nKey:"subnav.asks",mounted:!0},{to:"plans",i18nKey:"subnav.plans",mounted:!0}];function l(){const{t:s}=n("tasks");return e.jsxs("div",{className:"flex min-h-dvh flex-col bg-bg",children:[e.jsx(u,{}),e.jsx("nav",{className:a("sticky top-[var(--topbar-h,0)] z-10","flex items-center gap-1","border-b border-border bg-surface","px-3 sm:px-4 py-1","overflow-x-auto"),"aria-label":s("pageTitle"),children:b.filter(t=>t.mounted).map(t=>e.jsx(r,{to:t.to,className:({isActive:o})=>a("shrink-0 rounded-md px-3 py-1.5 text-sm no-underline","transition-colors tap-target",o?"bg-accent-bg text-accent font-medium":"text-text-dim hover:bg-surface-hover hover:text-text"),children:s(t.i18nKey)},t.to))}),e.jsx("main",{className:"flex-1 px-3 sm:px-4 py-4 pb-safe",children:e.jsx(i,{})})]})}export{l as default};
|
|
2
|
+
//# sourceMappingURL=layout-BcYZlaqf.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout-
|
|
1
|
+
{"version":3,"file":"layout-BcYZlaqf.js","sources":["../../src/routes/tasks/layout.tsx"],"sourcesContent":["/**\n * /tasks — layout shell shared by every sub-tab.\n *\n * Renders the application Topbar plus a sub-tab strip below it. The\n * actual sub-tab body comes from <Outlet /> — one file per tab under\n * routes/tasks/.\n *\n * Sub-tab order matches plan: jobs / subtasks / bgjobs / schedules /\n * outbox / a2a. Each sub-tab is gated on its route being mounted; in\n * PR-10a only `/tasks/jobs` is wired up so the others stay out of the\n * nav until their PRs land.\n */\n\nimport { NavLink, Outlet } from 'react-router-dom'\nimport { useTranslation } from 'react-i18next'\nimport { Topbar } from '@/components/shell/topbar'\nimport { cn } from '@/lib/utils'\n\ninterface SubTab {\n to: string\n i18nKey: string\n mounted: boolean\n}\n\nconst SUB_TABS: SubTab[] = [\n { to: 'jobs', i18nKey: 'subnav.jobs', mounted: true },\n { to: 'subtasks', i18nKey: 'subnav.subtasks', mounted: true },\n { to: 'bgjobs', i18nKey: 'subnav.bgjobs', mounted: true },\n { to: 'schedules', i18nKey: 'subnav.schedules', mounted: true },\n { to: 'outbox', i18nKey: 'subnav.outbox', mounted: true },\n { to: 'a2a', i18nKey: 'subnav.a2a', mounted: true },\n // P1 follow-up — per-thread background primitives.\n { to: 'heartbeat', i18nKey: 'subnav.heartbeat', mounted: true },\n { to: 'goals', i18nKey: 'subnav.goals', mounted: true },\n { to: 'asks', i18nKey: 'subnav.asks', mounted: true },\n // v1.2.133 — native_exit_plan_mode audit log.\n { to: 'plans', i18nKey: 'subnav.plans', mounted: true },\n]\n\nexport default function TasksLayout(): JSX.Element {\n const { t } = useTranslation('tasks')\n return (\n <div className=\"flex min-h-dvh flex-col bg-bg\">\n <Topbar />\n\n <nav\n className={cn(\n 'sticky top-[var(--topbar-h,0)] z-10',\n 'flex items-center gap-1',\n 'border-b border-border bg-surface',\n 'px-3 sm:px-4 py-1',\n 'overflow-x-auto',\n )}\n aria-label={t('pageTitle')}\n >\n {SUB_TABS.filter((tab) => tab.mounted).map((tab) => (\n <NavLink\n key={tab.to}\n to={tab.to}\n className={({ isActive }) =>\n cn(\n 'shrink-0 rounded-md px-3 py-1.5 text-sm no-underline',\n 'transition-colors tap-target',\n isActive\n ? 'bg-accent-bg text-accent font-medium'\n : 'text-text-dim hover:bg-surface-hover hover:text-text',\n )\n }\n >\n {t(tab.i18nKey)}\n </NavLink>\n ))}\n </nav>\n\n <main className=\"flex-1 px-3 sm:px-4 py-4 pb-safe\">\n <Outlet />\n </main>\n </div>\n )\n}\n"],"names":["SUB_TABS","TasksLayout","t","useTranslation","jsxs","jsx","Topbar","cn","tab","NavLink","isActive","Outlet"],"mappings":"uGAwBA,MAAMA,EAAqB,CACzB,CAAE,GAAI,OAAa,QAAS,cAAoB,QAAS,EAAA,EACzD,CAAE,GAAI,WAAa,QAAS,kBAAoB,QAAS,EAAA,EACzD,CAAE,GAAI,SAAa,QAAS,gBAAoB,QAAS,EAAA,EACzD,CAAE,GAAI,YAAa,QAAS,mBAAoB,QAAS,EAAA,EACzD,CAAE,GAAI,SAAa,QAAS,gBAAoB,QAAS,EAAA,EACzD,CAAE,GAAI,MAAa,QAAS,aAAoB,QAAS,EAAA,EAEzD,CAAE,GAAI,YAAa,QAAS,mBAAoB,QAAS,EAAA,EACzD,CAAE,GAAI,QAAa,QAAS,eAAoB,QAAS,EAAA,EACzD,CAAE,GAAI,OAAa,QAAS,cAAoB,QAAS,EAAA,EAEzD,CAAE,GAAI,QAAa,QAAS,eAAoB,QAAS,EAAA,CAC3D,EAEA,SAAwBC,GAA2B,CACjD,KAAM,CAAE,EAAAC,CAAA,EAAMC,EAAe,OAAO,EACpC,OACEC,EAAAA,KAAC,MAAA,CAAI,UAAU,gCACb,SAAA,CAAAC,EAAAA,IAACC,EAAA,EAAO,EAERD,EAAAA,IAAC,MAAA,CACC,UAAWE,EACT,sCACA,0BACA,oCACA,oBACA,iBAAA,EAEF,aAAYL,EAAE,WAAW,EAExB,SAAAF,EAAS,OAAQQ,GAAQA,EAAI,OAAO,EAAE,IAAKA,GAC1CH,EAAAA,IAACI,EAAA,CAEC,GAAID,EAAI,GACR,UAAW,CAAC,CAAE,SAAAE,CAAA,IACZH,EACE,uDACA,+BACAG,EACI,uCACA,sDAAA,EAIP,SAAAR,EAAEM,EAAI,OAAO,CAAA,EAZTA,EAAI,EAAA,CAcZ,CAAA,CAAA,QAGF,OAAA,CAAK,UAAU,mCACd,SAAAH,EAAAA,IAACM,IAAO,CAAA,CACV,CAAA,EACF,CAEJ"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{u as m,j as e,S as d,g as u,h as p,i as h,k as i,f,T as b,N as j,c as x,O as g}from"./index-
|
|
2
|
-
//# sourceMappingURL=layout-
|
|
1
|
+
import{u as m,j as e,S as d,g as u,h as p,i as h,k as i,f,T as b,N as j,c as x,O as g}from"./index-DHh1LYlA.js";import{u as y}from"./use-memory-Bz1Zao7g.js";import"./react-DlP5eolq.js";function _({value:n,onChange:c,className:l}){const{t:r}=m("memory"),{data:o,isLoading:s}=y(),t=o?.users??[];return e.jsxs(d,{value:n||"__placeholder__",onValueChange:a=>c(a==="__placeholder__"?"":a),disabled:s||t.length===0,children:[e.jsx(u,{className:l??"h-9 w-72 max-w-full",children:e.jsx(p,{placeholder:r("userPicker.placeholder")})}),e.jsxs(h,{children:[e.jsx(i,{value:"__placeholder__",disabled:!0,children:r("userPicker.placeholder")}),t.map(a=>e.jsx(i,{value:a.user_key,children:e.jsxs("span",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"font-mono text-xs",children:a.user_key}),e.jsx("span",{className:"text-text-dim text-xs",children:r("userPicker.factsLabel",{count:a.fact_count})}),a.has_persona&&e.jsxs("span",{className:"text-accent text-xs",children:["·",r("userPicker.personaTag"),"·"]})]})},a.user_key))]})]})}const v=[{to:"facts",i18nKey:"tabs.facts",mounted:!0},{to:"persona",i18nKey:"tabs.persona",mounted:!0},{to:"distill",i18nKey:"tabs.distill",mounted:!0},{to:"vector",i18nKey:"tabs.vector",mounted:!0}];function P(){const{t:n}=m("memory"),[c,l]=f(),r=c.get("user")??"";function o(s){const t=new URLSearchParams(c);s?t.set("user",s):t.delete("user"),l(t,{replace:!0})}return e.jsxs("div",{className:"flex min-h-dvh flex-col bg-bg",children:[e.jsx(b,{}),e.jsx("div",{className:"border-b border-border bg-surface px-3 sm:px-4 py-2",children:e.jsxs("div",{className:"mx-auto flex max-w-7xl items-center gap-3",children:[e.jsx("span",{className:"text-sm text-text-dim shrink-0",children:n("userPicker.label")}),e.jsx(_,{value:r,onChange:o})]})}),e.jsx("nav",{className:x("sticky top-0 z-10","flex items-center gap-1","border-b border-border bg-surface","px-3 sm:px-4 py-1","overflow-x-auto"),"aria-label":n("pageTitle"),children:v.filter(s=>s.mounted).map(s=>e.jsx(j,{to:s.to,className:({isActive:t})=>x("shrink-0 rounded-md px-3 py-1.5 text-sm no-underline","transition-colors tap-target",t?"bg-accent-bg text-accent font-medium":"text-text-dim hover:bg-surface-hover hover:text-text"),children:n(s.i18nKey)},s.to))}),e.jsx("main",{className:"flex-1 px-3 sm:px-4 py-4 pb-safe",children:e.jsx(g,{})})]})}export{P as default};
|
|
2
|
+
//# sourceMappingURL=layout-Cb7looUv.js.map
|