@aion0/forge 0.5.26 → 0.5.27
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/.forge/worktrees/pipeline-4dd8dc2d/CLAUDE.md +86 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/README.md +136 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/RELEASE_NOTES.md +36 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/agents/route.ts +17 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/auth/[...nextauth]/route.ts +3 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/auth/verify/route.ts +46 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude/[id]/route.ts +31 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude/[id]/stream/route.ts +63 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude/route.ts +28 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude-sessions/[projectName]/entries/route.ts +23 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude-sessions/[projectName]/live/route.ts +72 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude-sessions/[projectName]/route.ts +37 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude-sessions/sync/route.ts +17 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/claude-templates/route.ts +145 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/code/route.ts +299 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/delivery/[id]/route.ts +62 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/delivery/route.ts +40 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/detect-cli/route.ts +46 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/docs/route.ts +176 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/docs/sessions/route.ts +54 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/favorites/route.ts +26 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/flows/route.ts +6 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/flows/run/route.ts +19 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/git/route.ts +149 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/help/route.ts +84 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/issue-scanner/route.ts +116 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/logs/route.ts +100 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/mobile-chat/route.ts +115 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/monitor/route.ts +74 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/notifications/route.ts +42 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/notify/test/route.ts +33 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/online/route.ts +40 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/pipelines/[id]/route.ts +41 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/pipelines/route.ts +90 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/plugins/route.ts +75 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/preview/[...path]/route.ts +64 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/preview/route.ts +156 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/project-pipelines/route.ts +91 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/project-sessions/route.ts +61 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/projects/route.ts +26 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/sessions/[id]/chat/route.ts +64 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/sessions/[id]/messages/route.ts +9 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/sessions/[id]/route.ts +17 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/sessions/route.ts +20 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/settings/route.ts +64 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/skills/local/route.ts +228 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/skills/route.ts +182 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/smith-templates/route.ts +81 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/status/route.ts +12 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tabs/route.ts +25 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tasks/[id]/route.ts +51 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tasks/[id]/stream/route.ts +77 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tasks/link/route.ts +37 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tasks/route.ts +44 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tasks/session/route.ts +14 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/telegram/route.ts +23 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/templates/route.ts +6 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/terminal-bell/route.ts +39 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/terminal-cwd/route.ts +19 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/terminal-state/route.ts +15 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/tunnel/route.ts +26 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/upgrade/route.ts +43 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/usage/route.ts +20 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/version/route.ts +78 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/watchers/route.ts +33 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/workspace/[id]/agents/route.ts +35 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/workspace/[id]/memory/route.ts +23 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/workspace/[id]/smith/route.ts +22 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/workspace/[id]/stream/route.ts +31 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/api/workspace/route.ts +79 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/global-error.tsx +21 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/globals.css +52 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/icon.ico +0 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/icon.png +0 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/icon.svg +106 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/layout.tsx +17 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/login/LoginForm.tsx +96 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/login/page.tsx +10 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/mobile/page.tsx +10 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/app/page.tsx +22 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/bin/forge-server.mjs +484 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/check-forge-status.sh +71 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/cli/mw.ts +579 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/BrowserPanel.tsx +175 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/ChatPanel.tsx +191 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/ClaudeTerminal.tsx +267 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/CodeViewer.tsx +787 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/ConversationEditor.tsx +411 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/ConversationGraphView.tsx +347 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/ConversationTerminalView.tsx +303 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/Dashboard.tsx +807 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/DashboardWrapper.tsx +9 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/DeliveryFlowEditor.tsx +491 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/DeliveryList.tsx +230 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/DeliveryWorkspace.tsx +589 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/DocTerminal.tsx +187 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/DocsViewer.tsx +574 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/HelpDialog.tsx +169 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/HelpTerminal.tsx +141 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/InlinePipelineView.tsx +111 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/LogViewer.tsx +194 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/MarkdownContent.tsx +73 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/MobileView.tsx +385 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/MonitorPanel.tsx +122 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/NewSessionModal.tsx +93 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/NewTaskModal.tsx +492 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/PipelineEditor.tsx +570 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/PipelineView.tsx +1018 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/PluginsPanel.tsx +472 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/ProjectDetail.tsx +1618 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/ProjectList.tsx +108 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/ProjectManager.tsx +401 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/SessionList.tsx +74 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/SessionView.tsx +726 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/SettingsModal.tsx +1647 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/SkillsPanel.tsx +969 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/StatusBar.tsx +99 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/TabBar.tsx +46 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/TaskBoard.tsx +113 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/TaskDetail.tsx +372 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/TerminalLauncher.tsx +398 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/TunnelToggle.tsx +206 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/UsagePanel.tsx +207 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/WebTerminal.tsx +1743 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/WorkspaceTree.tsx +221 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/components/WorkspaceView.tsx +4048 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/dev-test.sh +5 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/docs/Forge_Memory_Layer_Design.docx +0 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/docs/Forge_Strategy_Research_2026.docx +0 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/docs/LOCAL-DEPLOY.md +144 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/docs/roadmap-multi-agent-workflow.md +330 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/forge-logo.png +0 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/forge-logo.svg +106 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/hooks/useSidebarResize.ts +52 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/install.sh +29 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/instrumentation.ts +35 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/agents/claude-adapter.ts +104 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/agents/generic-adapter.ts +64 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/agents/index.ts +245 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/agents/types.ts +70 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/artifacts.ts +106 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/auth.ts +62 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/docker.yaml +70 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/http.yaml +66 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/jenkins.yaml +92 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/llm-vision.yaml +85 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/playwright.yaml +111 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/shell-command.yaml +60 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/slack.yaml +48 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/builtin-plugins/webhook.yaml +56 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/claude-process.ts +361 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/claude-sessions.ts +266 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/claude-templates.ts +227 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/cloudflared.ts +424 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/crypto.ts +67 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/delivery.ts +787 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/dirs.ts +99 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/flows.ts +86 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/forge-mcp-server.ts +732 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/forge-skills/forge-inbox.md +38 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/forge-skills/forge-send.md +47 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/forge-skills/forge-status.md +32 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/forge-skills/forge-workspace-sync.md +37 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/00-overview.md +40 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/01-settings.md +194 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/02-telegram.md +41 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/03-tunnel.md +31 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/04-tasks.md +52 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/05-pipelines.md +460 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/06-skills.md +43 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/07-projects.md +73 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/08-rules.md +53 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/09-issue-autofix.md +55 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/10-troubleshooting.md +89 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/11-workspace.md +810 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/help-docs/CLAUDE.md +62 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/init.ts +266 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/issue-scanner.ts +298 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/logger.ts +79 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/notifications.ts +75 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/notify.ts +108 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/password.ts +97 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/pipeline-scheduler.ts +373 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/pipeline.ts +1565 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/plugins/executor.ts +347 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/plugins/registry.ts +228 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/plugins/types.ts +103 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/project-sessions.ts +53 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/projects.ts +86 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/session-manager.ts +156 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/session-utils.ts +53 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/session-watcher.ts +345 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/settings.ts +195 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/skills.ts +458 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/task-manager.ts +951 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/telegram-bot.ts +1477 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/telegram-standalone.ts +83 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/terminal-server.ts +70 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/terminal-standalone.ts +438 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/usage-scanner.ts +249 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/__tests__/state-machine.test.ts +388 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/__tests__/workspace.test.ts +311 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/agent-bus.ts +416 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/agent-worker.ts +655 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/backends/api-backend.ts +262 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/backends/cli-backend.ts +491 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/index.ts +84 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/manager.ts +136 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/orchestrator.ts +3415 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/persistence.ts +309 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/presets.ts +649 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/requests.ts +287 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/session-monitor.ts +240 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/skill-installer.ts +275 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/smith-memory.ts +498 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/types.ts +241 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace/watch-manager.ts +560 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/lib/workspace-standalone.ts +978 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/middleware.ts +51 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/next.config.ts +26 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/package.json +74 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/pnpm-lock.yaml +3719 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/pnpm-workspace.yaml +1 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/postcss.config.mjs +7 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/publish.sh +133 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/README.md +66 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/results/.gitignore +2 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/run.ts +635 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/01-text-utils/task.md +26 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/01-text-utils/validator.sh +46 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/02-pagination/setup.sh +19 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/02-pagination/task.md +48 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/02-pagination/validator.sh +69 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/03-bug-fix/setup.sh +82 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/03-bug-fix/task.md +30 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/bench/tasks/03-bug-fix/validator.sh +29 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/scripts/verify-usage.ts +178 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/src/config/index.ts +129 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/src/core/db/database.ts +259 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/src/core/memory/strategy.ts +32 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/src/core/providers/chat.ts +65 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/src/core/providers/registry.ts +60 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/src/core/session/manager.ts +190 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/src/types/index.ts +129 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/start.sh +32 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/templates/smith-lead.json +45 -0
- package/.forge/worktrees/pipeline-4dd8dc2d/tsconfig.json +42 -0
- package/RELEASE_NOTES.md +11 -28
- package/app/api/terminal-bell/route.ts +6 -2
- package/components/WebTerminal.tsx +36 -2
- package/lib/terminal-standalone.ts +19 -2
- package/next-env.d.ts +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
3
|
+
import { join, dirname } from 'node:path';
|
|
4
|
+
import { spawn, execSync, type ChildProcess } from 'node:child_process';
|
|
5
|
+
import { getDataDir, getConfigDir } from '@/lib/dirs';
|
|
6
|
+
|
|
7
|
+
const CONFIG_FILE = join(getDataDir(), 'preview.json');
|
|
8
|
+
|
|
9
|
+
interface PreviewEntry {
|
|
10
|
+
port: number;
|
|
11
|
+
url: string | null;
|
|
12
|
+
status: string;
|
|
13
|
+
label?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Persist state across hot-reloads
|
|
17
|
+
const stateKey = Symbol.for('mw-preview-state');
|
|
18
|
+
const g = globalThis as any;
|
|
19
|
+
if (!g[stateKey]) g[stateKey] = { entries: new Map<number, { process: ChildProcess | null; url: string | null; status: string; label: string }>() };
|
|
20
|
+
const state: { entries: Map<number, { process: ChildProcess | null; url: string | null; status: string; label: string }> } = g[stateKey];
|
|
21
|
+
|
|
22
|
+
function getConfig(): PreviewEntry[] {
|
|
23
|
+
try {
|
|
24
|
+
const data = JSON.parse(readFileSync(CONFIG_FILE, 'utf-8'));
|
|
25
|
+
return Array.isArray(data) ? data : data.port ? [data] : [];
|
|
26
|
+
} catch {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function saveConfig(entries: PreviewEntry[]) {
|
|
32
|
+
const dir = dirname(CONFIG_FILE);
|
|
33
|
+
mkdirSync(dir, { recursive: true });
|
|
34
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(entries, null, 2));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function getCloudflaredPath(): string | null {
|
|
38
|
+
const binPath = join(getConfigDir(), 'bin', 'cloudflared');
|
|
39
|
+
if (existsSync(binPath)) return binPath;
|
|
40
|
+
try {
|
|
41
|
+
return execSync('which cloudflared', { encoding: 'utf-8' }).trim();
|
|
42
|
+
} catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// GET — list all previews
|
|
48
|
+
export async function GET() {
|
|
49
|
+
const entries: PreviewEntry[] = [];
|
|
50
|
+
for (const [port, s] of state.entries) {
|
|
51
|
+
entries.push({ port, url: s.url, status: s.status, label: s.label });
|
|
52
|
+
}
|
|
53
|
+
return NextResponse.json(entries);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// POST — start/stop/manage previews
|
|
57
|
+
export async function POST(req: Request) {
|
|
58
|
+
const body = await req.json();
|
|
59
|
+
|
|
60
|
+
// Stop a preview
|
|
61
|
+
if (body.action === 'stop' && body.port) {
|
|
62
|
+
const entry = state.entries.get(body.port);
|
|
63
|
+
if (entry?.process) {
|
|
64
|
+
entry.process.kill('SIGTERM');
|
|
65
|
+
} else {
|
|
66
|
+
// Process ref lost (hot-reload) — kill by port match
|
|
67
|
+
try {
|
|
68
|
+
const pids = execSync(`pgrep -f 'cloudflared tunnel.*localhost:${body.port}'`, { encoding: 'utf-8', timeout: 3000, stdio: ['pipe', 'pipe', 'pipe'] }).trim();
|
|
69
|
+
for (const pid of pids.split('\n').filter(Boolean)) {
|
|
70
|
+
try { process.kill(parseInt(pid), 'SIGTERM'); } catch {}
|
|
71
|
+
}
|
|
72
|
+
} catch {}
|
|
73
|
+
}
|
|
74
|
+
state.entries.delete(body.port);
|
|
75
|
+
syncConfig();
|
|
76
|
+
return NextResponse.json({ ok: true });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Start a new preview
|
|
80
|
+
if (body.action === 'start' && body.port) {
|
|
81
|
+
const port = parseInt(body.port);
|
|
82
|
+
if (!port || port < 1 || port > 65535) {
|
|
83
|
+
return NextResponse.json({ error: 'Invalid port' }, { status: 400 });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Already running?
|
|
87
|
+
const existing = state.entries.get(port);
|
|
88
|
+
if (existing && existing.status === 'running') {
|
|
89
|
+
return NextResponse.json({ port, url: existing.url, status: 'running', label: existing.label });
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const binPath = getCloudflaredPath();
|
|
93
|
+
if (!binPath) {
|
|
94
|
+
return NextResponse.json({ error: 'cloudflared not installed. Start the main tunnel first.' }, { status: 500 });
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const label = body.label || `localhost:${port}`;
|
|
98
|
+
state.entries.set(port, { process: null, url: null, status: 'starting', label });
|
|
99
|
+
syncConfig();
|
|
100
|
+
|
|
101
|
+
// Start tunnel
|
|
102
|
+
return new Promise<NextResponse>((resolve) => {
|
|
103
|
+
let resolved = false;
|
|
104
|
+
const child = spawn(binPath, ['tunnel', '--url', `http://localhost:${port}`], {
|
|
105
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const entry = state.entries.get(port)!;
|
|
109
|
+
entry.process = child;
|
|
110
|
+
|
|
111
|
+
const handleOutput = (data: Buffer) => {
|
|
112
|
+
const urlMatch = data.toString().match(/(https:\/\/[a-z0-9-]+\.trycloudflare\.com)/);
|
|
113
|
+
if (urlMatch && !entry.url) {
|
|
114
|
+
entry.url = urlMatch[1];
|
|
115
|
+
entry.status = 'running';
|
|
116
|
+
syncConfig();
|
|
117
|
+
if (!resolved) {
|
|
118
|
+
resolved = true;
|
|
119
|
+
resolve(NextResponse.json({ port, url: entry.url, status: 'running', label }));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
child.stdout?.on('data', handleOutput);
|
|
125
|
+
child.stderr?.on('data', handleOutput);
|
|
126
|
+
|
|
127
|
+
child.on('exit', () => {
|
|
128
|
+
entry.process = null;
|
|
129
|
+
entry.status = 'stopped';
|
|
130
|
+
entry.url = null;
|
|
131
|
+
syncConfig();
|
|
132
|
+
if (!resolved) {
|
|
133
|
+
resolved = true;
|
|
134
|
+
resolve(NextResponse.json({ port, url: null, status: 'stopped', error: 'Tunnel exited' }));
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
setTimeout(() => {
|
|
139
|
+
if (!resolved) {
|
|
140
|
+
resolved = true;
|
|
141
|
+
resolve(NextResponse.json({ port, url: null, status: entry.status, error: 'Timeout' }));
|
|
142
|
+
}
|
|
143
|
+
}, 30000);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return NextResponse.json({ error: 'Unknown action' }, { status: 400 });
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function syncConfig() {
|
|
151
|
+
const entries: PreviewEntry[] = [];
|
|
152
|
+
for (const [port, s] of state.entries) {
|
|
153
|
+
entries.push({ port, url: s.url, status: s.status, label: s.label });
|
|
154
|
+
}
|
|
155
|
+
saveConfig(entries);
|
|
156
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import {
|
|
3
|
+
getBindings,
|
|
4
|
+
addBinding,
|
|
5
|
+
removeBinding,
|
|
6
|
+
updateBinding,
|
|
7
|
+
getRuns,
|
|
8
|
+
deleteRun,
|
|
9
|
+
triggerPipeline,
|
|
10
|
+
getNextRunTime,
|
|
11
|
+
scanAndTriggerIssues,
|
|
12
|
+
resetDedup,
|
|
13
|
+
} from '@/lib/pipeline-scheduler';
|
|
14
|
+
import { listWorkflows } from '@/lib/pipeline';
|
|
15
|
+
|
|
16
|
+
// GET /api/project-pipelines?project=PATH
|
|
17
|
+
export async function GET(req: Request) {
|
|
18
|
+
const { searchParams } = new URL(req.url);
|
|
19
|
+
const projectPath = searchParams.get('project');
|
|
20
|
+
if (!projectPath) return NextResponse.json({ error: 'project required' }, { status: 400 });
|
|
21
|
+
|
|
22
|
+
const bindings = getBindings(projectPath).map(b => ({
|
|
23
|
+
...b,
|
|
24
|
+
nextRunAt: getNextRunTime(b),
|
|
25
|
+
}));
|
|
26
|
+
const runs = getRuns(projectPath);
|
|
27
|
+
const workflows = listWorkflows().map(w => ({ name: w.name, description: w.description, builtin: w.builtin }));
|
|
28
|
+
|
|
29
|
+
return NextResponse.json({ bindings, runs, workflows });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// POST /api/project-pipelines
|
|
33
|
+
export async function POST(req: Request) {
|
|
34
|
+
const body = await req.json();
|
|
35
|
+
|
|
36
|
+
if (body.action === 'add') {
|
|
37
|
+
const { projectPath, projectName, workflowName, config } = body;
|
|
38
|
+
if (!projectPath || !workflowName) return NextResponse.json({ error: 'projectPath and workflowName required' }, { status: 400 });
|
|
39
|
+
addBinding(projectPath, projectName || projectPath.split('/').pop(), workflowName, config);
|
|
40
|
+
return NextResponse.json({ ok: true });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (body.action === 'remove') {
|
|
44
|
+
removeBinding(body.projectPath, body.workflowName);
|
|
45
|
+
return NextResponse.json({ ok: true });
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (body.action === 'update') {
|
|
49
|
+
updateBinding(body.projectPath, body.workflowName, { enabled: body.enabled, config: body.config });
|
|
50
|
+
return NextResponse.json({ ok: true });
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (body.action === 'trigger') {
|
|
54
|
+
const { projectPath, projectName, workflowName, input } = body;
|
|
55
|
+
if (!projectPath || !workflowName) return NextResponse.json({ error: 'projectPath and workflowName required' }, { status: 400 });
|
|
56
|
+
try {
|
|
57
|
+
const result = triggerPipeline(projectPath, projectName || projectPath.split('/').pop(), workflowName, input);
|
|
58
|
+
return NextResponse.json({ ok: true, ...result });
|
|
59
|
+
} catch (e: any) {
|
|
60
|
+
return NextResponse.json({ ok: false, error: e.message }, { status: 500 });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (body.action === 'delete-run') {
|
|
65
|
+
deleteRun(body.id);
|
|
66
|
+
return NextResponse.json({ ok: true });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (body.action === 'scan-now') {
|
|
70
|
+
const { projectPath, projectName, workflowName } = body;
|
|
71
|
+
if (!projectPath || !workflowName) return NextResponse.json({ error: 'projectPath and workflowName required' }, { status: 400 });
|
|
72
|
+
const bindings = getBindings(projectPath);
|
|
73
|
+
const binding = bindings.find(b => b.workflowName === workflowName);
|
|
74
|
+
if (!binding) return NextResponse.json({ error: 'Binding not found' }, { status: 404 });
|
|
75
|
+
try {
|
|
76
|
+
const result = scanAndTriggerIssues(binding);
|
|
77
|
+
return NextResponse.json({ ok: true, ...result });
|
|
78
|
+
} catch (e: any) {
|
|
79
|
+
return NextResponse.json({ ok: false, error: e.message }, { status: 500 });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (body.action === 'reset-dedup') {
|
|
84
|
+
const { projectPath, workflowName, dedupKey } = body;
|
|
85
|
+
if (!projectPath || !workflowName || !dedupKey) return NextResponse.json({ error: 'projectPath, workflowName, dedupKey required' }, { status: 400 });
|
|
86
|
+
resetDedup(projectPath, workflowName, dedupKey);
|
|
87
|
+
return NextResponse.json({ ok: true });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return NextResponse.json({ error: 'Invalid action' }, { status: 400 });
|
|
91
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { getFixedSession, setFixedSession, clearFixedSession, getAllFixedSessions } from '@/lib/project-sessions';
|
|
3
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
|
|
6
|
+
// GET: get fixed session for a project, or all bindings
|
|
7
|
+
export async function GET(req: Request) {
|
|
8
|
+
const url = new URL(req.url);
|
|
9
|
+
const projectPath = url.searchParams.get('projectPath');
|
|
10
|
+
if (projectPath) {
|
|
11
|
+
// Also ensure mcp.json exists when querying
|
|
12
|
+
ensureMcpConfig(projectPath);
|
|
13
|
+
return NextResponse.json({ projectPath, fixedSessionId: getFixedSession(projectPath) || null });
|
|
14
|
+
}
|
|
15
|
+
return NextResponse.json(getAllFixedSessions());
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// POST: set fixed session or ensure MCP config
|
|
19
|
+
export async function POST(req: Request) {
|
|
20
|
+
const body = await req.json();
|
|
21
|
+
const { projectPath, fixedSessionId, action } = body;
|
|
22
|
+
if (!projectPath) return NextResponse.json({ error: 'projectPath required' }, { status: 400 });
|
|
23
|
+
|
|
24
|
+
// Ensure MCP config action
|
|
25
|
+
if (action === 'ensure_mcp') {
|
|
26
|
+
ensureMcpConfig(projectPath);
|
|
27
|
+
return NextResponse.json({ ok: true });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!fixedSessionId) {
|
|
31
|
+
clearFixedSession(projectPath);
|
|
32
|
+
return NextResponse.json({ ok: true, cleared: true });
|
|
33
|
+
}
|
|
34
|
+
setFixedSession(projectPath, fixedSessionId);
|
|
35
|
+
return NextResponse.json({ ok: true, projectPath, fixedSessionId });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Generate .forge/mcp.json in the project directory with workspace context baked in */
|
|
39
|
+
function ensureMcpConfig(projectPath: string): void {
|
|
40
|
+
try {
|
|
41
|
+
const forgeDir = join(projectPath, '.forge');
|
|
42
|
+
const configPath = join(forgeDir, 'mcp.json');
|
|
43
|
+
const mcpPort = Number(process.env.MCP_PORT) || 8406;
|
|
44
|
+
|
|
45
|
+
// Resolve workspace + primary agent for this project
|
|
46
|
+
let wsParam = '';
|
|
47
|
+
try {
|
|
48
|
+
const { findWorkspaceByProject } = require('@/lib/workspace');
|
|
49
|
+
const ws = findWorkspaceByProject(projectPath);
|
|
50
|
+
if (ws) {
|
|
51
|
+
wsParam = `?workspaceId=${ws.id}`;
|
|
52
|
+
}
|
|
53
|
+
} catch {}
|
|
54
|
+
|
|
55
|
+
const config = { mcpServers: { forge: { type: 'sse', url: `http://localhost:${mcpPort}/sse${wsParam}` } } };
|
|
56
|
+
|
|
57
|
+
// Always rewrite (workspace context may have changed)
|
|
58
|
+
mkdirSync(forgeDir, { recursive: true });
|
|
59
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
60
|
+
} catch {}
|
|
61
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { scanProjects } from '@/lib/projects';
|
|
3
|
+
import { applyDefaultTemplates, listTemplates } from '@/lib/claude-templates';
|
|
4
|
+
|
|
5
|
+
// Track known projects to detect new ones
|
|
6
|
+
const knownProjects = new Set<string>();
|
|
7
|
+
|
|
8
|
+
export async function GET() {
|
|
9
|
+
const projects = scanProjects();
|
|
10
|
+
|
|
11
|
+
// Auto-apply default templates to newly detected projects
|
|
12
|
+
const hasDefaults = listTemplates().some(t => t.isDefault);
|
|
13
|
+
if (hasDefaults) {
|
|
14
|
+
for (const p of projects) {
|
|
15
|
+
if (!knownProjects.has(p.path)) {
|
|
16
|
+
knownProjects.add(p.path);
|
|
17
|
+
try { applyDefaultTemplates(p.path); } catch {}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
} else {
|
|
21
|
+
// Still track projects even without defaults
|
|
22
|
+
for (const p of projects) knownProjects.add(p.path);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return NextResponse.json(projects);
|
|
26
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { getSessionManager } from '@/lib/session-manager';
|
|
2
|
+
import { chatStream } from '@/src/core/providers/chat';
|
|
3
|
+
import type { ModelMessage } from 'ai';
|
|
4
|
+
|
|
5
|
+
export async function POST(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
6
|
+
const { id } = await params;
|
|
7
|
+
const { message } = await req.json();
|
|
8
|
+
const manager = getSessionManager();
|
|
9
|
+
|
|
10
|
+
const session = manager.get(id);
|
|
11
|
+
if (!session) {
|
|
12
|
+
return new Response(JSON.stringify({ error: 'Session not found' }), { status: 404 });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Save user message
|
|
16
|
+
manager.addMessage(id, 'user', message, session.provider, session.model);
|
|
17
|
+
|
|
18
|
+
// Get memory-filtered messages
|
|
19
|
+
const memoryMessages = manager.getMemoryMessages(id);
|
|
20
|
+
const coreMessages: ModelMessage[] = memoryMessages.map(m => ({
|
|
21
|
+
role: m.role as 'user' | 'assistant',
|
|
22
|
+
content: m.content,
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
manager.updateStatus(id, 'running');
|
|
26
|
+
|
|
27
|
+
// Stream response
|
|
28
|
+
const encoder = new TextEncoder();
|
|
29
|
+
const stream = new ReadableStream({
|
|
30
|
+
async start(controller) {
|
|
31
|
+
try {
|
|
32
|
+
const result = await chatStream({
|
|
33
|
+
provider: session.provider,
|
|
34
|
+
model: session.model || undefined,
|
|
35
|
+
systemPrompt: session.systemPrompt,
|
|
36
|
+
messages: coreMessages,
|
|
37
|
+
onToken(token) {
|
|
38
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify({ token })}\n\n`));
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Save assistant message
|
|
43
|
+
manager.addMessage(id, 'assistant', result.content, result.provider, result.model);
|
|
44
|
+
manager.recordUsage(id, result);
|
|
45
|
+
manager.updateStatus(id, 'idle');
|
|
46
|
+
|
|
47
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify({ done: true, usage: { input: result.inputTokens, output: result.outputTokens } })}\n\n`));
|
|
48
|
+
controller.close();
|
|
49
|
+
} catch (err: any) {
|
|
50
|
+
manager.updateStatus(id, 'error');
|
|
51
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify({ error: err.message })}\n\n`));
|
|
52
|
+
controller.close();
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return new Response(stream, {
|
|
58
|
+
headers: {
|
|
59
|
+
'Content-Type': 'text/event-stream',
|
|
60
|
+
'Cache-Control': 'no-cache',
|
|
61
|
+
Connection: 'keep-alive',
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { getSessionManager } from '@/lib/session-manager';
|
|
3
|
+
|
|
4
|
+
export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
5
|
+
const { id } = await params;
|
|
6
|
+
const manager = getSessionManager();
|
|
7
|
+
const messages = manager.getMessages(id);
|
|
8
|
+
return NextResponse.json(messages);
|
|
9
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { getSessionManager } from '@/lib/session-manager';
|
|
3
|
+
|
|
4
|
+
export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
5
|
+
const { id } = await params;
|
|
6
|
+
const manager = getSessionManager();
|
|
7
|
+
const session = manager.get(id) || manager.getByName(id);
|
|
8
|
+
if (!session) return NextResponse.json({ error: 'Not found' }, { status: 404 });
|
|
9
|
+
return NextResponse.json(session);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function DELETE(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
13
|
+
const { id } = await params;
|
|
14
|
+
const manager = getSessionManager();
|
|
15
|
+
manager.delete(id);
|
|
16
|
+
return NextResponse.json({ ok: true });
|
|
17
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { getSessionManager } from '@/lib/session-manager';
|
|
3
|
+
import { loadAllTemplates } from '@/src/config';
|
|
4
|
+
|
|
5
|
+
export async function GET() {
|
|
6
|
+
const manager = getSessionManager();
|
|
7
|
+
const sessions = manager.list();
|
|
8
|
+
return NextResponse.json(sessions);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function POST(req: Request) {
|
|
12
|
+
const body = await req.json();
|
|
13
|
+
const manager = getSessionManager();
|
|
14
|
+
try {
|
|
15
|
+
const session = manager.create(body);
|
|
16
|
+
return NextResponse.json(session);
|
|
17
|
+
} catch (err: any) {
|
|
18
|
+
return NextResponse.json({ error: err.message }, { status: 400 });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { loadSettings, loadSettingsMasked, saveSettings, type Settings } from '@/lib/settings';
|
|
3
|
+
import { restartTelegramBot } from '@/lib/init';
|
|
4
|
+
import { SECRET_FIELDS } from '@/lib/crypto';
|
|
5
|
+
import { verifyAdmin } from '@/lib/password';
|
|
6
|
+
|
|
7
|
+
export async function GET() {
|
|
8
|
+
return NextResponse.json(loadSettingsMasked());
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function PUT(req: Request) {
|
|
12
|
+
const body = await req.json();
|
|
13
|
+
|
|
14
|
+
// Handle secret field updates separately
|
|
15
|
+
if (body._secretUpdate) {
|
|
16
|
+
const { field, adminPassword, newValue } = body._secretUpdate as {
|
|
17
|
+
field: string;
|
|
18
|
+
adminPassword: string;
|
|
19
|
+
newValue: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// Validate field name
|
|
23
|
+
if (!SECRET_FIELDS.includes(field as any)) {
|
|
24
|
+
return NextResponse.json({ ok: false, error: 'Invalid field' }, { status: 400 });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Verify admin password
|
|
28
|
+
if (!verifyAdmin(adminPassword)) {
|
|
29
|
+
return NextResponse.json({ ok: false, error: 'Wrong password' }, { status: 403 });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Update the specific field
|
|
33
|
+
const current = loadSettings();
|
|
34
|
+
(current as any)[field] = newValue;
|
|
35
|
+
saveSettings(current);
|
|
36
|
+
|
|
37
|
+
// Restart Telegram bot if token changed
|
|
38
|
+
if (field === 'telegramBotToken') {
|
|
39
|
+
restartTelegramBot();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return NextResponse.json({ ok: true });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Normal settings update — strip masked secrets so we don't overwrite with placeholder
|
|
46
|
+
const settings = loadSettings();
|
|
47
|
+
const updated = body as Settings;
|
|
48
|
+
|
|
49
|
+
for (const field of SECRET_FIELDS) {
|
|
50
|
+
// Keep existing encrypted value if frontend sent masked placeholder
|
|
51
|
+
if (updated[field] === '••••••••' || updated[field] === '') {
|
|
52
|
+
updated[field] = settings[field];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Remove internal fields
|
|
57
|
+
delete (updated as any)._secretStatus;
|
|
58
|
+
|
|
59
|
+
const changed = Object.keys(updated).filter(k => JSON.stringify((updated as any)[k]) !== JSON.stringify((settings as any)[k]) && !['telegramTunnelPassword', 'telegramBotToken'].includes(k));
|
|
60
|
+
if (changed.length > 0) console.log(`[settings] Updated: ${changed.join(', ')}`);
|
|
61
|
+
saveSettings(updated);
|
|
62
|
+
restartTelegramBot();
|
|
63
|
+
return NextResponse.json({ ok: true });
|
|
64
|
+
}
|