From 65e85135c11c4ac83aa91807e90ac0873b2da90c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Sun, 29 Mar 2026 14:08:15 -0400 Subject: [PATCH] large update --- .gitignore | 6 +- CLAUDE.md | 35 + build/electron-builder.runtime.json | 6 +- build/release/builder-debug.yml | 2 +- .../win-arm64-unpacked/resources/app.asar | Bin 64386348 -> 64516861 bytes package.json | 2 +- .../src/cli/format-event.ts | 18 +- .../adapter-claude-local/src/server/index.ts | 52 +- .../adapter-claude-local/src/server/test.ts | 34 +- .../src/ui/build-config.ts | 63 +- .../src/ui/parse-stdout.ts | 31 +- .../src/cli/format-event.ts | 31 +- .../adapter-codex-local/src/server/execute.ts | 10 +- .../adapter-codex-local/src/server/index.ts | 52 +- .../adapter-codex-local/src/server/test.ts | 34 +- .../src/ui/build-config.ts | 63 +- .../src/ui/parse-stdout.ts | 31 +- .../src/cli/format-event.ts | 41 +- .../src/server/execute.ts | 62 +- .../adapter-gemini-local/src/server/index.ts | 62 +- .../adapter-gemini-local/src/server/test.ts | 26 +- .../adapter-gemini-local/src/server/utils.ts | 8 - .../src/ui/build-config.ts | 51 +- .../src/ui/parse-stdout.ts | 31 +- .../adapter-kimi-local/src/server/execute.ts | 10 +- .../adapter-kimi-local/src/server/test.ts | 10 +- .../adapter-kimi-local/src/ui/build-config.ts | 51 +- .../src/cli/format-event.ts | 40 +- .../src/server/execute.ts | 10 +- .../src/server/index.ts | 62 +- .../src/server/models.ts | 10 +- .../adapter-opencode-local/src/server/test.ts | 33 +- .../src/ui/build-config.ts | 51 +- .../src/ui/parse-stdout.ts | 14 +- packages/adapter-utils/src/config-utils.ts | 61 ++ packages/adapter-utils/src/parse-utils.ts | 47 ++ packages/adapter-utils/src/server-utils.ts | 34 +- packages/adapter-utils/src/session-codec.ts | 61 ++ packages/adapter-utils/src/test-utils.ts | 43 ++ packages/adapter-utils/src/types.ts | 24 - src/main/api-server.ts | 309 ++++++++- src/main/automation-service.ts | 211 +++++- src/main/bootstrap-application.ts | 39 +- src/main/browser-action-service.ts | 13 +- src/main/connector-auth-service.ts | 158 +++-- src/main/connector-health-service.ts | 46 +- src/main/connector-matching.ts | 83 +-- src/main/connectors.ts | 250 +++++++ src/main/database.ts | 516 +++++++++++--- src/main/desktop-shell-service.ts | 35 +- src/main/host-environment-service.ts | 2 - src/main/ipc-core-admin-handlers.ts | 20 +- src/main/ipc-core-common.ts | 7 +- src/main/ipc-domain-common.ts | 5 +- src/main/main-runtime-support.ts | 10 +- src/main/onboarding-service.ts | 10 +- src/main/orchestration-service.ts | 77 +-- src/main/orchestrator/worker.ts | 23 +- src/main/prompt-builder.ts | 79 ++- src/main/service-graph.ts | 23 +- src/main/skill-format.ts | 13 - src/main/skill-github.ts | 14 - src/main/skill-keys.ts | 20 - src/main/skill-service.ts | 41 +- src/main/skill-types.ts | 4 - src/main/task-quality-gates.ts | 19 - src/main/worker-service.ts | 45 +- src/preload/index.ts | 7 + src/renderer/App.tsx | 80 ++- .../CompanyOnboarding/CompanyStep.tsx | 73 +- .../CompanyOnboarding/MissionStep.tsx | 2 +- .../CompanyOnboarding/NodeCheckStep.tsx | 146 ++++ .../CompanyOnboarding/OnboardingHero.tsx | 94 ++- .../CompanyOnboarding/OnboardingWizard.tsx | 479 ++++++++----- .../CompanyOnboarding/ProvidersStep.tsx | 646 ++++++++++++++++++ .../CompanyOnboarding/WelcomeStep.tsx | 94 +++ src/renderer/components/TitleBar.tsx | 65 ++ src/renderer/components/communication.tsx | 2 +- .../communication/MessageComposer.tsx | 45 +- src/renderer/components/connectors.tsx | 13 +- .../components/dashboard/Dashboard.tsx | 5 +- .../dashboard/DepartmentOverview.tsx | 127 ---- .../components/dashboard/GoalProgress.tsx | 44 -- .../components/dashboard/HealthCard.tsx | 109 --- .../components/dashboard/NeedsAttention.tsx | 147 ---- .../components/dashboard/QuickActions.tsx | 78 --- .../components/dashboard/SprintProgress.tsx | 69 -- .../components/dashboard/TaskPipeline.tsx | 36 - src/renderer/components/execution.tsx | 1 + .../components/execution/ModelManagement.tsx | 204 ++++++ .../components/execution/TaskCreator.tsx | 2 +- .../components/execution/TaskInspector.tsx | 2 +- .../components/organization/AgentCreator.tsx | 4 +- .../components/organization/AgentEditor.tsx | 75 +- .../components/organization/AgentRoster.tsx | 2 +- .../components/organization/OrgChart.tsx | 9 +- .../components/organization/orgTreeLayout.ts | 10 + src/renderer/components/runs/run-helpers.tsx | 44 -- src/renderer/components/ui.tsx | 21 +- src/renderer/i18n/en.ts | 54 ++ src/renderer/i18n/zh.ts | 54 ++ src/renderer/lib/ipc-batcher.ts | 35 - src/renderer/lib/keyboard.ts | 32 +- src/renderer/lib/status-colors.ts | 108 --- src/renderer/state/hooks.ts | 47 -- src/renderer/styles.css | 44 ++ src/shared/contracts.ts | 19 +- src/shared/types.ts | 75 +- tests/integration/autonomous-chain.spec.ts | 22 +- tests/unit/ipc-batcher.test.ts | 73 +- tests/unit/wakeup-lifecycle.test.ts | 187 +---- 111 files changed, 3936 insertions(+), 2933 deletions(-) delete mode 100644 packages/adapter-gemini-local/src/server/utils.ts create mode 100644 packages/adapter-utils/src/config-utils.ts create mode 100644 packages/adapter-utils/src/parse-utils.ts create mode 100644 packages/adapter-utils/src/session-codec.ts create mode 100644 packages/adapter-utils/src/test-utils.ts create mode 100644 src/renderer/components/CompanyOnboarding/NodeCheckStep.tsx create mode 100644 src/renderer/components/CompanyOnboarding/ProvidersStep.tsx create mode 100644 src/renderer/components/CompanyOnboarding/WelcomeStep.tsx create mode 100644 src/renderer/components/TitleBar.tsx delete mode 100644 src/renderer/components/dashboard/DepartmentOverview.tsx delete mode 100644 src/renderer/components/dashboard/GoalProgress.tsx delete mode 100644 src/renderer/components/dashboard/HealthCard.tsx delete mode 100644 src/renderer/components/dashboard/NeedsAttention.tsx delete mode 100644 src/renderer/components/dashboard/QuickActions.tsx delete mode 100644 src/renderer/components/dashboard/SprintProgress.tsx delete mode 100644 src/renderer/components/dashboard/TaskPipeline.tsx create mode 100644 src/renderer/components/execution/ModelManagement.tsx delete mode 100644 src/renderer/lib/status-colors.ts delete mode 100644 src/renderer/state/hooks.ts diff --git a/.gitignore b/.gitignore index d86c7adf..4fbdb4c1 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,8 @@ coverage/ *.tsbuildinfo win-unpacked .blockmap +.claude +build # Test artifacts test-results/ @@ -58,8 +60,6 @@ npm-debug.log* pnpm-debug.log* yarn-debug.log* yarn-error.log* -CLAUDE.md build/release/AgentCompany-0.4.61-arm64.dmg CLAUDE.md -CLAUDE.md -build/release/AgentCompany-0.4.90-arm64.dmg +build/release/AgentCompany-0.4.90-arm64.dmg \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index a86b9832..c1dcf26a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -457,3 +457,38 @@ AgentCompany is a cross-platform Electron desktop app that lets users create aut - Async cleanup: `appLifecycleService` waits 3 seconds for worker child process to exit before app.exit(0) ## Cross-Cutting Concerns + +## 核心原则 (Core Persona) + +1. **​第一性原理​**: 从原始需求出发。动机不清立刻停,路径非最优直接纠正。 +2. **​极简沟通​**: 用简单直白的中文一次性输出,把用户当高中生。拒绝角色扮演,拒绝分段分口吻,对话中已解决的问题后续绝不再提。不要用 P0/P1/P2 这种术语。 +3. **​Let it crash​**: 发现问题尽早暴露。严禁使用任何降级、兜底、后发式补丁或非严谨通用算法的后处理补救。 +4. **​禁止擅自开分支​**: 严禁私自创建新 worktree。可以给建议,但必须征得用户明确同意后方可操作。 +5. **​自检与精简​**: 每次改动后,严格执行「Review查Bug然后第一性原理分析」流程,思考是否有更简单、更稳健的实现。 + +## 开发工作流 (Development Workflow) + +1. **​分析层​**: 文字、图标、颜色的UI修改,直接操作执行层并落地archive。重大重构/多任务才走规划层。 +2. **​规划层​**: 使用 using-superpowers 编排流程并产出/更新全局流程图。 +3. **​任务层​**: 使用 planning-with-files 维护 task_plan.md / progress.md / findings.md。 +4. **​执行层​**: OpenSpec 四步闭环(propose -> 用户确认 -> apply -> archive)。 +5. **​粒度控制​**: 动手前用 gsd-method-guide 拆解为 `///`。 + +## 工程规范 (Engineering Constraints) + +1. **​数据处理​**: 不可捏造数据。生产代码严禁 Mock。Mock 仅限本地调试(统一入口: `127.0.0.1:xxxx/mock`),必须在 `.gitignore` 中排除。 +2. **​自动化执行​**: `curl`、`cat`、`git` 等命令直接运行免确认;Playwright 脚本在终端持续会话,禁止无意义的暂停。 +3. **​子代理分流​**: 复杂问题(多于1个、需 Review/研究/并行分析)必须拆解并使用子代理(5.4 模型),保持主上下文纯净。 +4. **​API 接入​**: 参考 `/Users/ifengz/CodingCase/002_DevelopSpec/1.Doc/`中的现成方案,并不断补充新内容。 +5. **​自我进化​**: 用户指正后立即更新 `lessons.md`。开始新任务前必须回顾 `lessons.md`。 + +## 运维安全守则 (Operations Constraints) + +1. **​排障顺序​**: 遇网络/证书/代理异常,优先排查入口及反代配置。严禁使用临时IP:端口判定数据库损坏,必须寻找固定入口(域名/面板地址)。 + +## 输出规范 (Output Specs - 拒绝啰嗦) + +1. **​禁止陈述式汇报​**: 严禁复读背景,严禁分“证据/分析/结论”等多维度拆解简单问题。 +2. **​结论先行​**: 直接给结论和修补方案。解释必须是短小精悍的中文大白话,不显示P0/P1等级。 +3. **​表格化输出​**: 多数内容(尤其是评审、对比、多项任务)必须以Markdown表格输出。 +4. **​强制收口​**: 结束对话必须明确告知用到的 skill。 diff --git a/build/electron-builder.runtime.json b/build/electron-builder.runtime.json index 3e0547bf..5e1a7c60 100644 --- a/build/electron-builder.runtime.json +++ b/build/electron-builder.runtime.json @@ -1,9 +1,9 @@ { - "extends": "C:\\Users\\zhang\\Documents\\GitHub\\AgentCompany\\.claude\\worktrees\\agent-afbb9437\\electron-builder.yml", + "extends": "C:\\Users\\zhang\\Documents\\GitHub\\AgentCompany\\electron-builder.yml", "directories": { - "output": "C:\\Users\\zhang\\Documents\\GitHub\\AgentCompany\\.claude\\worktrees\\agent-afbb9437\\build\\release" + "output": "C:\\Users\\zhang\\Documents\\GitHub\\AgentCompany\\build\\release" }, "extraMetadata": { - "version": "0.4.100" + "version": "0.4.133" } } diff --git a/build/release/builder-debug.yml b/build/release/builder-debug.yml index 5ba1b9fe..5027d739 100644 --- a/build/release/builder-debug.yml +++ b/build/release/builder-debug.yml @@ -43,4 +43,4 @@ arm64: - assets/icon.png - assets/tray-icon*.png nsis: - script: "!include \"C:\\Users\\zhang\\Documents\\GitHub\\AgentCompany\\.claude\\worktrees\\agent-afbb9437\\node_modules\\.pnpm\\app-builder-lib@26.8.1_dmg-_62d31da0b96a3ea7b7d51a6bbe3b3b6e\\node_modules\\app-builder-lib\\templates\\nsis\\include\\StdUtils.nsh\"\n!addincludedir \"C:\\Users\\zhang\\Documents\\GitHub\\AgentCompany\\.claude\\worktrees\\agent-afbb9437\\node_modules\\.pnpm\\app-builder-lib@26.8.1_dmg-_62d31da0b96a3ea7b7d51a6bbe3b3b6e\\node_modules\\app-builder-lib\\templates\\nsis\\include\"\n!macro _isUpdated _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"updated\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isUpdated `\"\" isUpdated \"\"`\n\n!macro _isForceRun _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"force-run\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isForceRun `\"\" isForceRun \"\"`\n\n!macro _isKeepShortcuts _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"keep-shortcuts\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isKeepShortcuts `\"\" isKeepShortcuts \"\"`\n\n!macro _isNoDesktopShortcut _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"no-desktop-shortcut\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isNoDesktopShortcut `\"\" isNoDesktopShortcut \"\"`\n\n!macro _isDeleteAppData _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"delete-app-data\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isDeleteAppData `\"\" isDeleteAppData \"\"`\n\n!macro _isForAllUsers _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"allusers\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isForAllUsers `\"\" isForAllUsers \"\"`\n\n!macro _isForCurrentUser _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"currentuser\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isForCurrentUser `\"\" isForCurrentUser \"\"`\n\n!macro addLangs\n !insertmacro MUI_LANGUAGE \"English\"\n !insertmacro MUI_LANGUAGE \"German\"\n !insertmacro MUI_LANGUAGE \"French\"\n !insertmacro MUI_LANGUAGE \"SpanishInternational\"\n !insertmacro MUI_LANGUAGE \"SimpChinese\"\n !insertmacro MUI_LANGUAGE \"TradChinese\"\n !insertmacro MUI_LANGUAGE \"Japanese\"\n !insertmacro MUI_LANGUAGE \"Korean\"\n !insertmacro MUI_LANGUAGE \"Italian\"\n !insertmacro MUI_LANGUAGE \"Dutch\"\n !insertmacro MUI_LANGUAGE \"Danish\"\n !insertmacro MUI_LANGUAGE \"Swedish\"\n !insertmacro MUI_LANGUAGE \"Norwegian\"\n !insertmacro MUI_LANGUAGE \"Finnish\"\n !insertmacro MUI_LANGUAGE \"Russian\"\n !insertmacro MUI_LANGUAGE \"Portuguese\"\n !insertmacro MUI_LANGUAGE \"PortugueseBR\"\n !insertmacro MUI_LANGUAGE \"Polish\"\n !insertmacro MUI_LANGUAGE \"Ukrainian\"\n !insertmacro MUI_LANGUAGE \"Czech\"\n !insertmacro MUI_LANGUAGE \"Slovak\"\n !insertmacro MUI_LANGUAGE \"Hungarian\"\n !insertmacro MUI_LANGUAGE \"Arabic\"\n !insertmacro MUI_LANGUAGE \"Turkish\"\n !insertmacro MUI_LANGUAGE \"Thai\"\n !insertmacro MUI_LANGUAGE \"Vietnamese\"\n!macroend\n\n!addplugindir /x86-unicode \"C:\\Users\\zhang\\AppData\\Local\\electron-builder\\Cache\\nsis\\nsis-resources-3.4.1-nsis-resources-3.4.1\\plugins\\x86-unicode\"\n!include \"C:\\Users\\zhang\\AppData\\Local\\Temp\\t-8uQAoB\\6-messages.nsh\"\n\n!include \"common.nsh\"\n!include \"extractAppPackage.nsh\"\n\n# https://github.com/electron-userland/electron-builder/issues/3972#issuecomment-505171582\nCRCCheck off\nWindowIcon Off\nAutoCloseWindow True\nRequestExecutionLevel ${REQUEST_EXECUTION_LEVEL}\n\nFunction .onInit\n !ifndef SPLASH_IMAGE\n SetSilent silent\n !endif\n\n !insertmacro check64BitAndSetRegView\nFunctionEnd\n\nFunction .onGUIInit\n InitPluginsDir\n\n !ifdef SPLASH_IMAGE\n File /oname=$PLUGINSDIR\\splash.bmp \"${SPLASH_IMAGE}\"\n BgImage::SetBg $PLUGINSDIR\\splash.bmp\n BgImage::Redraw\n !endif\nFunctionEnd\n\nSection\n !ifdef SPLASH_IMAGE\n HideWindow\n !endif\n\n StrCpy $INSTDIR \"$PLUGINSDIR\\app\"\n !ifdef UNPACK_DIR_NAME\n StrCpy $INSTDIR \"$TEMP\\${UNPACK_DIR_NAME}\"\n !endif\n\n RMDir /r $INSTDIR\n SetOutPath $INSTDIR\n\n !ifdef APP_DIR_64\n !ifdef APP_DIR_ARM64\n !ifdef APP_DIR_32\n ${if} ${IsNativeARM64}\n File /r \"${APP_DIR_ARM64}\\*.*\"\n ${elseif} ${RunningX64}\n File /r \"${APP_DIR_64}\\*.*\"\n ${else}\n File /r \"${APP_DIR_32}\\*.*\"\n ${endIf}\n !else\n ${if} ${IsNativeARM64}\n File /r \"${APP_DIR_ARM64}\\*.*\"\n ${else}\n File /r \"${APP_DIR_64}\\*.*\"\n {endIf}\n !endif\n !else\n !ifdef APP_DIR_32\n ${if} ${RunningX64}\n File /r \"${APP_DIR_64}\\*.*\"\n ${else}\n File /r \"${APP_DIR_32}\\*.*\"\n ${endIf}\n !else\n File /r \"${APP_DIR_64}\\*.*\"\n !endif\n !endif\n !else\n !ifdef APP_DIR_32\n File /r \"${APP_DIR_32}\\*.*\"\n !else\n !insertmacro extractEmbeddedAppPackage\n !endif\n !endif\n\n System::Call 'Kernel32::SetEnvironmentVariable(t, t)i (\"PORTABLE_EXECUTABLE_DIR\", \"$EXEDIR\").r0'\n System::Call 'Kernel32::SetEnvironmentVariable(t, t)i (\"PORTABLE_EXECUTABLE_FILE\", \"$EXEPATH\").r0'\n System::Call 'Kernel32::SetEnvironmentVariable(t, t)i (\"PORTABLE_EXECUTABLE_APP_FILENAME\", \"${APP_FILENAME}\").r0'\n ${StdUtils.GetAllParameters} $R0 0\n\n !ifdef SPLASH_IMAGE\n BgImage::Destroy\n !endif\n\n\tExecWait \"$INSTDIR\\${APP_EXECUTABLE_FILENAME} $R0\" $0\n SetErrorLevel $0\n\n SetOutPath $EXEDIR\n\tRMDir /r $INSTDIR\nSectionEnd\n" + script: "!include \"C:\\Users\\zhang\\Documents\\GitHub\\AgentCompany\\node_modules\\.pnpm\\app-builder-lib@26.8.1_dmg-_62d31da0b96a3ea7b7d51a6bbe3b3b6e\\node_modules\\app-builder-lib\\templates\\nsis\\include\\StdUtils.nsh\"\n!addincludedir \"C:\\Users\\zhang\\Documents\\GitHub\\AgentCompany\\node_modules\\.pnpm\\app-builder-lib@26.8.1_dmg-_62d31da0b96a3ea7b7d51a6bbe3b3b6e\\node_modules\\app-builder-lib\\templates\\nsis\\include\"\n!macro _isUpdated _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"updated\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isUpdated `\"\" isUpdated \"\"`\n\n!macro _isForceRun _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"force-run\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isForceRun `\"\" isForceRun \"\"`\n\n!macro _isKeepShortcuts _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"keep-shortcuts\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isKeepShortcuts `\"\" isKeepShortcuts \"\"`\n\n!macro _isNoDesktopShortcut _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"no-desktop-shortcut\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isNoDesktopShortcut `\"\" isNoDesktopShortcut \"\"`\n\n!macro _isDeleteAppData _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"delete-app-data\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isDeleteAppData `\"\" isDeleteAppData \"\"`\n\n!macro _isForAllUsers _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"allusers\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isForAllUsers `\"\" isForAllUsers \"\"`\n\n!macro _isForCurrentUser _a _b _t _f\n ${StdUtils.TestParameter} $R9 \"currentuser\"\n StrCmp \"$R9\" \"true\" `${_t}` `${_f}`\n!macroend\n!define isForCurrentUser `\"\" isForCurrentUser \"\"`\n\n!macro addLangs\n !insertmacro MUI_LANGUAGE \"English\"\n !insertmacro MUI_LANGUAGE \"German\"\n !insertmacro MUI_LANGUAGE \"French\"\n !insertmacro MUI_LANGUAGE \"SpanishInternational\"\n !insertmacro MUI_LANGUAGE \"SimpChinese\"\n !insertmacro MUI_LANGUAGE \"TradChinese\"\n !insertmacro MUI_LANGUAGE \"Japanese\"\n !insertmacro MUI_LANGUAGE \"Korean\"\n !insertmacro MUI_LANGUAGE \"Italian\"\n !insertmacro MUI_LANGUAGE \"Dutch\"\n !insertmacro MUI_LANGUAGE \"Danish\"\n !insertmacro MUI_LANGUAGE \"Swedish\"\n !insertmacro MUI_LANGUAGE \"Norwegian\"\n !insertmacro MUI_LANGUAGE \"Finnish\"\n !insertmacro MUI_LANGUAGE \"Russian\"\n !insertmacro MUI_LANGUAGE \"Portuguese\"\n !insertmacro MUI_LANGUAGE \"PortugueseBR\"\n !insertmacro MUI_LANGUAGE \"Polish\"\n !insertmacro MUI_LANGUAGE \"Ukrainian\"\n !insertmacro MUI_LANGUAGE \"Czech\"\n !insertmacro MUI_LANGUAGE \"Slovak\"\n !insertmacro MUI_LANGUAGE \"Hungarian\"\n !insertmacro MUI_LANGUAGE \"Arabic\"\n !insertmacro MUI_LANGUAGE \"Turkish\"\n !insertmacro MUI_LANGUAGE \"Thai\"\n !insertmacro MUI_LANGUAGE \"Vietnamese\"\n!macroend\n\n!addplugindir /x86-unicode \"C:\\Users\\zhang\\AppData\\Local\\electron-builder\\Cache\\nsis\\nsis-resources-3.4.1-nsis-resources-3.4.1\\plugins\\x86-unicode\"\n!include \"C:\\Users\\zhang\\AppData\\Local\\Temp\\t-GU2sm0\\6-messages.nsh\"\n\n!include \"common.nsh\"\n!include \"extractAppPackage.nsh\"\n\n# https://github.com/electron-userland/electron-builder/issues/3972#issuecomment-505171582\nCRCCheck off\nWindowIcon Off\nAutoCloseWindow True\nRequestExecutionLevel ${REQUEST_EXECUTION_LEVEL}\n\nFunction .onInit\n !ifndef SPLASH_IMAGE\n SetSilent silent\n !endif\n\n !insertmacro check64BitAndSetRegView\nFunctionEnd\n\nFunction .onGUIInit\n InitPluginsDir\n\n !ifdef SPLASH_IMAGE\n File /oname=$PLUGINSDIR\\splash.bmp \"${SPLASH_IMAGE}\"\n BgImage::SetBg $PLUGINSDIR\\splash.bmp\n BgImage::Redraw\n !endif\nFunctionEnd\n\nSection\n !ifdef SPLASH_IMAGE\n HideWindow\n !endif\n\n StrCpy $INSTDIR \"$PLUGINSDIR\\app\"\n !ifdef UNPACK_DIR_NAME\n StrCpy $INSTDIR \"$TEMP\\${UNPACK_DIR_NAME}\"\n !endif\n\n RMDir /r $INSTDIR\n SetOutPath $INSTDIR\n\n !ifdef APP_DIR_64\n !ifdef APP_DIR_ARM64\n !ifdef APP_DIR_32\n ${if} ${IsNativeARM64}\n File /r \"${APP_DIR_ARM64}\\*.*\"\n ${elseif} ${RunningX64}\n File /r \"${APP_DIR_64}\\*.*\"\n ${else}\n File /r \"${APP_DIR_32}\\*.*\"\n ${endIf}\n !else\n ${if} ${IsNativeARM64}\n File /r \"${APP_DIR_ARM64}\\*.*\"\n ${else}\n File /r \"${APP_DIR_64}\\*.*\"\n {endIf}\n !endif\n !else\n !ifdef APP_DIR_32\n ${if} ${RunningX64}\n File /r \"${APP_DIR_64}\\*.*\"\n ${else}\n File /r \"${APP_DIR_32}\\*.*\"\n ${endIf}\n !else\n File /r \"${APP_DIR_64}\\*.*\"\n !endif\n !endif\n !else\n !ifdef APP_DIR_32\n File /r \"${APP_DIR_32}\\*.*\"\n !else\n !insertmacro extractEmbeddedAppPackage\n !endif\n !endif\n\n System::Call 'Kernel32::SetEnvironmentVariable(t, t)i (\"PORTABLE_EXECUTABLE_DIR\", \"$EXEDIR\").r0'\n System::Call 'Kernel32::SetEnvironmentVariable(t, t)i (\"PORTABLE_EXECUTABLE_FILE\", \"$EXEPATH\").r0'\n System::Call 'Kernel32::SetEnvironmentVariable(t, t)i (\"PORTABLE_EXECUTABLE_APP_FILENAME\", \"${APP_FILENAME}\").r0'\n ${StdUtils.GetAllParameters} $R0 0\n\n !ifdef SPLASH_IMAGE\n BgImage::Destroy\n !endif\n\n\tExecWait \"$INSTDIR\\${APP_EXECUTABLE_FILENAME} $R0\" $0\n SetErrorLevel $0\n\n SetOutPath $EXEDIR\n\tRMDir /r $INSTDIR\nSectionEnd\n" diff --git a/build/release/win-arm64-unpacked/resources/app.asar b/build/release/win-arm64-unpacked/resources/app.asar index ec79ea816c6015cbd6ad035c878e873cff2943e6..4a3fd83e86275e210f44c0443a357eb9269f1f3e 100644 GIT binary patch delta 284760 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�O%c88W8)#EQX0s=$c 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 a`Lqmw-P~<3I}TI8r@qD@>mMjdaQQ!cN>u*< delta 197939 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%0D(-~$k%w#Y!q%ov3WH6W*G8twu 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

I{+=4rtW~`R3aR?c|h)Es1hjQcS#R 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 ajZ@*ggH1=h*`&W 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 diff --git a/package.json b/package.json index 3211a222..007b2a5a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "agent-company", - "version": "0.4.100", + "version": "0.4.133", "private": true, "type": "module", "description": "Cross-platform Electron desktop control plane for local-first AI agent companies.", diff --git a/packages/adapter-claude-local/src/cli/format-event.ts b/packages/adapter-claude-local/src/cli/format-event.ts index 08423d6e..30fe9d13 100644 --- a/packages/adapter-claude-local/src/cli/format-event.ts +++ b/packages/adapter-claude-local/src/cli/format-event.ts @@ -1,21 +1,5 @@ import pc from "picocolors"; - -function asErrorText(value: unknown): string { - if (typeof value === "string") return value; - if (typeof value !== "object" || value === null || Array.isArray(value)) return ""; - const obj = value as Record; - const message = - (typeof obj.message === "string" && obj.message) || - (typeof obj.error === "string" && obj.error) || - (typeof obj.code === "string" && obj.code) || - ""; - if (message) return message; - try { - return JSON.stringify(obj); - } catch { - return ""; - } -} +import { errorText as asErrorText } from "@agentcompany/adapter-utils/parse-utils"; export function printClaudeStreamEvent(raw: string, debug: boolean): void { const line = raw.trim(); diff --git a/packages/adapter-claude-local/src/server/index.ts b/packages/adapter-claude-local/src/server/index.ts index 41e20205..702c28cd 100644 --- a/packages/adapter-claude-local/src/server/index.ts +++ b/packages/adapter-claude-local/src/server/index.ts @@ -7,54 +7,6 @@ export { isClaudeUnknownSessionError, } from "./parse.js"; export { listClaudeSkills, syncClaudeSkills } from "./skills.js"; -import type { AdapterSessionCodec } from "@agentcompany/adapter-utils"; +import { createStandardSessionCodec } from "@agentcompany/adapter-utils/session-codec"; -function readNonEmptyString(value: unknown): string | null { - return typeof value === "string" && value.trim().length > 0 ? value.trim() : null; -} - -export const sessionCodec: AdapterSessionCodec = { - deserialize(raw: unknown) { - if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return null; - const record = raw as Record; - const sessionId = readNonEmptyString(record.sessionId) ?? readNonEmptyString(record.session_id); - if (!sessionId) return null; - const cwd = - readNonEmptyString(record.cwd) ?? - readNonEmptyString(record.workdir) ?? - readNonEmptyString(record.folder); - const workspaceId = readNonEmptyString(record.workspaceId) ?? readNonEmptyString(record.workspace_id); - const repoUrl = readNonEmptyString(record.repoUrl) ?? readNonEmptyString(record.repo_url); - const repoRef = readNonEmptyString(record.repoRef) ?? readNonEmptyString(record.repo_ref); - return { - sessionId, - ...(cwd ? { cwd } : {}), - ...(workspaceId ? { workspaceId } : {}), - ...(repoUrl ? { repoUrl } : {}), - ...(repoRef ? { repoRef } : {}), - }; - }, - serialize(params: Record | null) { - if (!params) return null; - const sessionId = readNonEmptyString(params.sessionId) ?? readNonEmptyString(params.session_id); - if (!sessionId) return null; - const cwd = - readNonEmptyString(params.cwd) ?? - readNonEmptyString(params.workdir) ?? - readNonEmptyString(params.folder); - const workspaceId = readNonEmptyString(params.workspaceId) ?? readNonEmptyString(params.workspace_id); - const repoUrl = readNonEmptyString(params.repoUrl) ?? readNonEmptyString(params.repo_url); - const repoRef = readNonEmptyString(params.repoRef) ?? readNonEmptyString(params.repo_ref); - return { - sessionId, - ...(cwd ? { cwd } : {}), - ...(workspaceId ? { workspaceId } : {}), - ...(repoUrl ? { repoUrl } : {}), - ...(repoRef ? { repoRef } : {}), - }; - }, - getDisplayId(params: Record | null) { - if (!params) return null; - return readNonEmptyString(params.sessionId) ?? readNonEmptyString(params.session_id); - }, -}; +export const sessionCodec = createStandardSessionCodec(); diff --git a/packages/adapter-claude-local/src/server/test.ts b/packages/adapter-claude-local/src/server/test.ts index 239635ed..a636f911 100644 --- a/packages/adapter-claude-local/src/server/test.ts +++ b/packages/adapter-claude-local/src/server/test.ts @@ -14,41 +14,9 @@ import { ensurePathInEnv, runChildProcess, } from "@agentcompany/adapter-utils/server-utils"; -import path from "node:path"; +import { summarizeStatus, isNonEmpty, commandLooksLike, summarizeProbeDetail } from "@agentcompany/adapter-utils/test-utils"; import { detectClaudeLoginRequired, parseClaudeStreamJson } from "./parse.js"; -function summarizeStatus(checks: AdapterEnvironmentCheck[]): AdapterEnvironmentTestResult["status"] { - if (checks.some((check) => check.level === "error")) return "fail"; - if (checks.some((check) => check.level === "warn")) return "warn"; - return "pass"; -} - -function isNonEmpty(value: unknown): value is string { - return typeof value === "string" && value.trim().length > 0; -} - -function firstNonEmptyLine(text: string): string { - return ( - text - .split(/\r?\n/) - .map((line) => line.trim()) - .find(Boolean) ?? "" - ); -} - -function commandLooksLike(command: string, expected: string): boolean { - const base = path.basename(command).toLowerCase(); - return base === expected || base === `${expected}.cmd` || base === `${expected}.exe`; -} - -function summarizeProbeDetail(stdout: string, stderr: string): string | null { - const raw = firstNonEmptyLine(stderr) || firstNonEmptyLine(stdout); - if (!raw) return null; - const clean = raw.replace(/\s+/g, " ").trim(); - const max = 240; - return clean.length > max ? `${clean.slice(0, max - 1)}…` : clean; -} - export async function testEnvironment( ctx: AdapterEnvironmentTestContext, ): Promise { diff --git a/packages/adapter-claude-local/src/ui/build-config.ts b/packages/adapter-claude-local/src/ui/build-config.ts index 5835ac47..595b528b 100644 --- a/packages/adapter-claude-local/src/ui/build-config.ts +++ b/packages/adapter-claude-local/src/ui/build-config.ts @@ -1,66 +1,5 @@ import type { CreateConfigValues } from "@agentcompany/adapter-utils"; - -function parseCommaArgs(value: string): string[] { - return value - .split(",") - .map((item) => item.trim()) - .filter(Boolean); -} - -function parseEnvVars(text: string): Record { - const env: Record = {}; - for (const line of text.split(/\r?\n/)) { - const trimmed = line.trim(); - if (!trimmed || trimmed.startsWith("#")) continue; - const eq = trimmed.indexOf("="); - if (eq <= 0) continue; - const key = trimmed.slice(0, eq).trim(); - const value = trimmed.slice(eq + 1); - if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) continue; - env[key] = value; - } - return env; -} - -function parseEnvBindings(bindings: unknown): Record { - if (typeof bindings !== "object" || bindings === null || Array.isArray(bindings)) return {}; - const env: Record = {}; - for (const [key, raw] of Object.entries(bindings)) { - if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) continue; - if (typeof raw === "string") { - env[key] = { type: "plain", value: raw }; - continue; - } - if (typeof raw !== "object" || raw === null || Array.isArray(raw)) continue; - const rec = raw as Record; - if (rec.type === "plain" && typeof rec.value === "string") { - env[key] = { type: "plain", value: rec.value }; - continue; - } - if (rec.type === "secret_ref" && typeof rec.secretId === "string") { - env[key] = { - type: "secret_ref", - secretId: rec.secretId, - ...(typeof rec.version === "number" || rec.version === "latest" - ? { version: rec.version } - : {}), - }; - } - } - return env; -} - -function parseJsonObject(text: string): Record | null { - const trimmed = text.trim(); - if (!trimmed) return null; - try { - const parsed = JSON.parse(trimmed); - if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return null; - return parsed as Record; - } catch { - return null; - } -} +import { parseCommaArgs, parseEnvVars, parseEnvBindings, parseJsonObject } from "@agentcompany/adapter-utils/config-utils"; export function buildClaudeLocalConfig(v: CreateConfigValues): Record { const ac: Record = {}; diff --git a/packages/adapter-claude-local/src/ui/parse-stdout.ts b/packages/adapter-claude-local/src/ui/parse-stdout.ts index cca5fd41..fda73ee2 100644 --- a/packages/adapter-claude-local/src/ui/parse-stdout.ts +++ b/packages/adapter-claude-local/src/ui/parse-stdout.ts @@ -1,39 +1,10 @@ import type { TranscriptEntry } from "@agentcompany/adapter-utils"; - -function asRecord(value: unknown): Record | null { - if (typeof value !== "object" || value === null || Array.isArray(value)) return null; - return value as Record; -} +import { asRecord, safeJsonParse, errorText } from "@agentcompany/adapter-utils/parse-utils"; function asNumber(value: unknown): number { return typeof value === "number" && Number.isFinite(value) ? value : 0; } -function errorText(value: unknown): string { - if (typeof value === "string") return value; - const rec = asRecord(value); - if (!rec) return ""; - const msg = - (typeof rec.message === "string" && rec.message) || - (typeof rec.error === "string" && rec.error) || - (typeof rec.code === "string" && rec.code) || - ""; - if (msg) return msg; - try { - return JSON.stringify(rec); - } catch { - return ""; - } -} - -function safeJsonParse(text: string): unknown { - try { - return JSON.parse(text); - } catch { - return null; - } -} - export function parseClaudeStdoutLine(line: string, ts: string): TranscriptEntry[] { const parsed = asRecord(safeJsonParse(line)); if (!parsed) { diff --git a/packages/adapter-codex-local/src/cli/format-event.ts b/packages/adapter-codex-local/src/cli/format-event.ts index 507d7624..c6294097 100644 --- a/packages/adapter-codex-local/src/cli/format-event.ts +++ b/packages/adapter-codex-local/src/cli/format-event.ts @@ -1,34 +1,5 @@ import pc from "picocolors"; - -function asRecord(value: unknown): Record | null { - if (typeof value !== "object" || value === null || Array.isArray(value)) return null; - return value as Record; -} - -function asString(value: unknown, fallback = ""): string { - return typeof value === "string" ? value : fallback; -} - -function asNumber(value: unknown, fallback = 0): number { - return typeof value === "number" && Number.isFinite(value) ? value : fallback; -} - -function errorText(value: unknown): string { - if (typeof value === "string") return value; - const rec = asRecord(value); - if (!rec) return ""; - const msg = - (typeof rec.message === "string" && rec.message) || - (typeof rec.error === "string" && rec.error) || - (typeof rec.code === "string" && rec.code) || - ""; - if (msg) return msg; - try { - return JSON.stringify(rec); - } catch { - return ""; - } -} +import { asRecord, errorText, asString, asNumber } from "@agentcompany/adapter-utils/parse-utils"; function printItemStarted(item: Record): boolean { const itemType = asString(item.type); diff --git a/packages/adapter-codex-local/src/server/execute.ts b/packages/adapter-codex-local/src/server/execute.ts index 2c99cef8..edbcdff8 100644 --- a/packages/adapter-codex-local/src/server/execute.ts +++ b/packages/adapter-codex-local/src/server/execute.ts @@ -19,6 +19,7 @@ import { runChildProcess, createManagedSkillSymlinks, } from "@agentcompany/adapter-utils/server-utils"; +import { firstNonEmptyLine } from "@agentcompany/adapter-utils/test-utils"; import { parseCodexJsonl, isCodexUnknownSessionError } from "./parse.js"; const __moduleDir = path.dirname(fileURLToPath(import.meta.url)); @@ -44,15 +45,6 @@ function stripCodexRolloutNoise(text: string): string { return kept.join("\n"); } -function firstNonEmptyLine(text: string): string { - return ( - text - .split(/\r?\n/) - .map((line) => line.trim()) - .find(Boolean) ?? "" - ); -} - function hasNonEmptyEnvValue(env: Record, key: string): boolean { const raw = env[key]; return typeof raw === "string" && raw.trim().length > 0; diff --git a/packages/adapter-codex-local/src/server/index.ts b/packages/adapter-codex-local/src/server/index.ts index da878bde..869b35fb 100644 --- a/packages/adapter-codex-local/src/server/index.ts +++ b/packages/adapter-codex-local/src/server/index.ts @@ -2,54 +2,6 @@ export { execute } from "./execute.js"; export { testEnvironment } from "./test.js"; export { parseCodexJsonl, isCodexUnknownSessionError } from "./parse.js"; export { listCodexSkills, syncCodexSkills } from "./skills.js"; -import type { AdapterSessionCodec } from "@agentcompany/adapter-utils"; +import { createStandardSessionCodec } from "@agentcompany/adapter-utils/session-codec"; -function readNonEmptyString(value: unknown): string | null { - return typeof value === "string" && value.trim().length > 0 ? value.trim() : null; -} - -export const sessionCodec: AdapterSessionCodec = { - deserialize(raw: unknown) { - if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return null; - const record = raw as Record; - const sessionId = readNonEmptyString(record.sessionId) ?? readNonEmptyString(record.session_id); - if (!sessionId) return null; - const cwd = - readNonEmptyString(record.cwd) ?? - readNonEmptyString(record.workdir) ?? - readNonEmptyString(record.folder); - const workspaceId = readNonEmptyString(record.workspaceId) ?? readNonEmptyString(record.workspace_id); - const repoUrl = readNonEmptyString(record.repoUrl) ?? readNonEmptyString(record.repo_url); - const repoRef = readNonEmptyString(record.repoRef) ?? readNonEmptyString(record.repo_ref); - return { - sessionId, - ...(cwd ? { cwd } : {}), - ...(workspaceId ? { workspaceId } : {}), - ...(repoUrl ? { repoUrl } : {}), - ...(repoRef ? { repoRef } : {}), - }; - }, - serialize(params: Record | null) { - if (!params) return null; - const sessionId = readNonEmptyString(params.sessionId) ?? readNonEmptyString(params.session_id); - if (!sessionId) return null; - const cwd = - readNonEmptyString(params.cwd) ?? - readNonEmptyString(params.workdir) ?? - readNonEmptyString(params.folder); - const workspaceId = readNonEmptyString(params.workspaceId) ?? readNonEmptyString(params.workspace_id); - const repoUrl = readNonEmptyString(params.repoUrl) ?? readNonEmptyString(params.repo_url); - const repoRef = readNonEmptyString(params.repoRef) ?? readNonEmptyString(params.repo_ref); - return { - sessionId, - ...(cwd ? { cwd } : {}), - ...(workspaceId ? { workspaceId } : {}), - ...(repoUrl ? { repoUrl } : {}), - ...(repoRef ? { repoRef } : {}), - }; - }, - getDisplayId(params: Record | null) { - if (!params) return null; - return readNonEmptyString(params.sessionId) ?? readNonEmptyString(params.session_id); - }, -}; +export const sessionCodec = createStandardSessionCodec(); diff --git a/packages/adapter-codex-local/src/server/test.ts b/packages/adapter-codex-local/src/server/test.ts index 5e62b96b..3284f211 100644 --- a/packages/adapter-codex-local/src/server/test.ts +++ b/packages/adapter-codex-local/src/server/test.ts @@ -13,41 +13,9 @@ import { ensurePathInEnv, runChildProcess, } from "@agentcompany/adapter-utils/server-utils"; -import path from "node:path"; +import { summarizeStatus, isNonEmpty, commandLooksLike, summarizeProbeDetail } from "@agentcompany/adapter-utils/test-utils"; import { parseCodexJsonl } from "./parse.js"; -function summarizeStatus(checks: AdapterEnvironmentCheck[]): AdapterEnvironmentTestResult["status"] { - if (checks.some((check) => check.level === "error")) return "fail"; - if (checks.some((check) => check.level === "warn")) return "warn"; - return "pass"; -} - -function isNonEmpty(value: unknown): value is string { - return typeof value === "string" && value.trim().length > 0; -} - -function firstNonEmptyLine(text: string): string { - return ( - text - .split(/\r?\n/) - .map((line) => line.trim()) - .find(Boolean) ?? "" - ); -} - -function commandLooksLike(command: string, expected: string): boolean { - const base = path.basename(command).toLowerCase(); - return base === expected || base === `${expected}.cmd` || base === `${expected}.exe`; -} - -function summarizeProbeDetail(stdout: string, stderr: string, parsedError: string | null): string | null { - const raw = parsedError?.trim() || firstNonEmptyLine(stderr) || firstNonEmptyLine(stdout); - if (!raw) return null; - const clean = raw.replace(/\s+/g, " ").trim(); - const max = 240; - return clean.length > max ? `${clean.slice(0, max - 1)}…` : clean; -} - const CODEX_AUTH_REQUIRED_RE = /(?:not\s+logged\s+in|login\s+required|authentication\s+required|unauthorized|invalid(?:\s+or\s+missing)?\s+api(?:[_\s-]?key)?|openai[_\s-]?api[_\s-]?key|api[_\s-]?key.*required|please\s+run\s+`?codex\s+login`?)/i; diff --git a/packages/adapter-codex-local/src/ui/build-config.ts b/packages/adapter-codex-local/src/ui/build-config.ts index f8e86978..b72af635 100644 --- a/packages/adapter-codex-local/src/ui/build-config.ts +++ b/packages/adapter-codex-local/src/ui/build-config.ts @@ -1,71 +1,10 @@ import type { CreateConfigValues } from "@agentcompany/adapter-utils"; +import { parseCommaArgs, parseEnvVars, parseEnvBindings, parseJsonObject } from "@agentcompany/adapter-utils/config-utils"; import { DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX, DEFAULT_CODEX_LOCAL_MODEL, } from "../index.js"; -function parseCommaArgs(value: string): string[] { - return value - .split(",") - .map((item) => item.trim()) - .filter(Boolean); -} - -function parseEnvVars(text: string): Record { - const env: Record = {}; - for (const line of text.split(/\r?\n/)) { - const trimmed = line.trim(); - if (!trimmed || trimmed.startsWith("#")) continue; - const eq = trimmed.indexOf("="); - if (eq <= 0) continue; - const key = trimmed.slice(0, eq).trim(); - const value = trimmed.slice(eq + 1); - if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) continue; - env[key] = value; - } - return env; -} - -function parseEnvBindings(bindings: unknown): Record { - if (typeof bindings !== "object" || bindings === null || Array.isArray(bindings)) return {}; - const env: Record = {}; - for (const [key, raw] of Object.entries(bindings)) { - if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) continue; - if (typeof raw === "string") { - env[key] = { type: "plain", value: raw }; - continue; - } - if (typeof raw !== "object" || raw === null || Array.isArray(raw)) continue; - const rec = raw as Record; - if (rec.type === "plain" && typeof rec.value === "string") { - env[key] = { type: "plain", value: rec.value }; - continue; - } - if (rec.type === "secret_ref" && typeof rec.secretId === "string") { - env[key] = { - type: "secret_ref", - secretId: rec.secretId, - ...(typeof rec.version === "number" || rec.version === "latest" - ? { version: rec.version } - : {}), - }; - } - } - return env; -} - -function parseJsonObject(text: string): Record | null { - const trimmed = text.trim(); - if (!trimmed) return null; - try { - const parsed = JSON.parse(trimmed); - if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return null; - return parsed as Record; - } catch { - return null; - } -} - export function buildCodexLocalConfig(v: CreateConfigValues): Record { const ac: Record = {}; if (v.cwd) ac.cwd = v.cwd; diff --git a/packages/adapter-codex-local/src/ui/parse-stdout.ts b/packages/adapter-codex-local/src/ui/parse-stdout.ts index 1ca4025c..68360397 100644 --- a/packages/adapter-codex-local/src/ui/parse-stdout.ts +++ b/packages/adapter-codex-local/src/ui/parse-stdout.ts @@ -3,19 +3,7 @@ import { redactHomePathUserSegmentsInValue, type TranscriptEntry, } from "@agentcompany/adapter-utils"; - -function safeJsonParse(text: string): unknown { - try { - return JSON.parse(text); - } catch { - return null; - } -} - -function asRecord(value: unknown): Record | null { - if (typeof value !== "object" || value === null || Array.isArray(value)) return null; - return value as Record; -} +import { asRecord, safeJsonParse, errorText } from "@agentcompany/adapter-utils/parse-utils"; function asString(value: unknown, fallback = ""): string { return typeof value === "string" ? value : fallback; @@ -25,23 +13,6 @@ function asNumber(value: unknown, fallback = 0): number { return typeof value === "number" && Number.isFinite(value) ? value : fallback; } -function errorText(value: unknown): string { - if (typeof value === "string") return value; - const rec = asRecord(value); - if (!rec) return ""; - const msg = - (typeof rec.message === "string" && rec.message) || - (typeof rec.error === "string" && rec.error) || - (typeof rec.code === "string" && rec.code) || - ""; - if (msg) return msg; - try { - return JSON.stringify(rec); - } catch { - return ""; - } -} - function stringifyUnknown(value: unknown): string { if (typeof value === "string") return redactHomePathUserSegments(value); if (value === null || value === undefined) return ""; diff --git a/packages/adapter-gemini-local/src/cli/format-event.ts b/packages/adapter-gemini-local/src/cli/format-event.ts index 777ef194..f1623bd5 100644 --- a/packages/adapter-gemini-local/src/cli/format-event.ts +++ b/packages/adapter-gemini-local/src/cli/format-event.ts @@ -1,44 +1,5 @@ import pc from "picocolors"; - -function asRecord(value: unknown): Record | null { - if (typeof value !== "object" || value === null || Array.isArray(value)) return null; - return value as Record; -} - -function asString(value: unknown, fallback = ""): string { - return typeof value === "string" ? value : fallback; -} - -function asNumber(value: unknown, fallback = 0): number { - return typeof value === "number" && Number.isFinite(value) ? value : fallback; -} - -function stringifyUnknown(value: unknown): string { - if (typeof value === "string") return value; - if (value === null || value === undefined) return ""; - try { - return JSON.stringify(value, null, 2); - } catch { - return String(value); - } -} - -function errorText(value: unknown): string { - if (typeof value === "string") return value; - const rec = asRecord(value); - if (!rec) return ""; - const msg = - (typeof rec.message === "string" && rec.message) || - (typeof rec.error === "string" && rec.error) || - (typeof rec.code === "string" && rec.code) || - ""; - if (msg) return msg; - try { - return JSON.stringify(rec); - } catch { - return ""; - } -} +import { asRecord, errorText, asString, asNumber, stringifyUnknown } from "@agentcompany/adapter-utils/parse-utils"; function printTextMessage(prefix: string, colorize: (text: string) => string, messageRaw: unknown): void { if (typeof messageRaw === "string") { diff --git a/packages/adapter-gemini-local/src/server/execute.ts b/packages/adapter-gemini-local/src/server/execute.ts index 381e0241..5d4b1271 100644 --- a/packages/adapter-gemini-local/src/server/execute.ts +++ b/packages/adapter-gemini-local/src/server/execute.ts @@ -28,7 +28,7 @@ import { isGeminiUnknownSessionError, parseGeminiJsonl, } from "./parse.js"; -import { firstNonEmptyLine } from "./utils.js"; +import { firstNonEmptyLine } from "@agentcompany/adapter-utils/test-utils"; const __moduleDir = path.dirname(fileURLToPath(import.meta.url)); const SKILLS_CANDIDATES = [ @@ -276,7 +276,9 @@ export async function execute(ctx: AdapterExecutionContext): Promise { - const notes: string[] = ["Prompt is passed to Gemini as the final positional argument."]; + const notes: string[] = [useStdin + ? "Prompt passed via stdin (exceeds command-line length limit)." + : "Prompt is passed to Gemini as the final positional argument."]; notes.push("Added --approval-mode yolo for unattended execution."); if (!instructionsFilePath) return notes; if (instructionsPrefix.length > 0) { @@ -305,6 +307,18 @@ export async function execute(ctx: AdapterExecutionContext): Promise SAFE_ARG_LIMIT; + let promptFilePath: string | null = null; + if (useStdin) { + promptFilePath = path.join(os.tmpdir(), `agentcompany-gemini-prompt-${runId}.txt`); + await fs.writeFile(promptFilePath, prompt, "utf8"); + } + const buildArgs = (resumeSessionId: string | null) => { const args = ["--output-format", "stream-json"]; if (resumeSessionId) args.push("--resume", resumeSessionId); @@ -316,8 +330,6 @@ export async function execute(ctx: AdapterExecutionContext): Promise 0) { - // Filter out flags the adapter already manages to prevent duplicates - // (e.g. user shell aliases that inject --approval-mode or --sandbox) const managedFlags = [ "--approval-mode", "--output-format", @@ -327,7 +339,9 @@ export async function execute(ctx: AdapterExecutionContext): Promise 0) args.push(...cleaned); } - args.push(prompt); + if (!useStdin) { + args.push(prompt); + } return args; }; @@ -354,6 +368,7 @@ export async function execute(ctx: AdapterExecutionContext): Promise {}); + } + } } diff --git a/packages/adapter-gemini-local/src/server/index.ts b/packages/adapter-gemini-local/src/server/index.ts index 8ffe7d56..c4538a48 100644 --- a/packages/adapter-gemini-local/src/server/index.ts +++ b/packages/adapter-gemini-local/src/server/index.ts @@ -8,64 +8,6 @@ export { isGeminiTurnLimitResult, } from "./parse.js"; export { listGeminiSkills, syncGeminiSkills } from "./skills.js"; -import type { AdapterSessionCodec } from "@agentcompany/adapter-utils"; +import { createStandardSessionCodec } from "@agentcompany/adapter-utils/session-codec"; -function readNonEmptyString(value: unknown): string | null { - return typeof value === "string" && value.trim().length > 0 ? value.trim() : null; -} - -export const sessionCodec: AdapterSessionCodec = { - deserialize(raw: unknown) { - if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return null; - const record = raw as Record; - const sessionId = - readNonEmptyString(record.sessionId) ?? - readNonEmptyString(record.session_id) ?? - readNonEmptyString(record.sessionID); - if (!sessionId) return null; - const cwd = - readNonEmptyString(record.cwd) ?? - readNonEmptyString(record.workdir) ?? - readNonEmptyString(record.folder); - const workspaceId = readNonEmptyString(record.workspaceId) ?? readNonEmptyString(record.workspace_id); - const repoUrl = readNonEmptyString(record.repoUrl) ?? readNonEmptyString(record.repo_url); - const repoRef = readNonEmptyString(record.repoRef) ?? readNonEmptyString(record.repo_ref); - return { - sessionId, - ...(cwd ? { cwd } : {}), - ...(workspaceId ? { workspaceId } : {}), - ...(repoUrl ? { repoUrl } : {}), - ...(repoRef ? { repoRef } : {}), - }; - }, - serialize(params: Record | null) { - if (!params) return null; - const sessionId = - readNonEmptyString(params.sessionId) ?? - readNonEmptyString(params.session_id) ?? - readNonEmptyString(params.sessionID); - if (!sessionId) return null; - const cwd = - readNonEmptyString(params.cwd) ?? - readNonEmptyString(params.workdir) ?? - readNonEmptyString(params.folder); - const workspaceId = readNonEmptyString(params.workspaceId) ?? readNonEmptyString(params.workspace_id); - const repoUrl = readNonEmptyString(params.repoUrl) ?? readNonEmptyString(params.repo_url); - const repoRef = readNonEmptyString(params.repoRef) ?? readNonEmptyString(params.repo_ref); - return { - sessionId, - ...(cwd ? { cwd } : {}), - ...(workspaceId ? { workspaceId } : {}), - ...(repoUrl ? { repoUrl } : {}), - ...(repoRef ? { repoRef } : {}), - }; - }, - getDisplayId(params: Record | null) { - if (!params) return null; - return ( - readNonEmptyString(params.sessionId) ?? - readNonEmptyString(params.session_id) ?? - readNonEmptyString(params.sessionID) - ); - }, -}; +export const sessionCodec = createStandardSessionCodec({ extraSessionIdKeys: ["sessionID"] }); diff --git a/packages/adapter-gemini-local/src/server/test.ts b/packages/adapter-gemini-local/src/server/test.ts index 0b7406bf..effd49ce 100644 --- a/packages/adapter-gemini-local/src/server/test.ts +++ b/packages/adapter-gemini-local/src/server/test.ts @@ -1,4 +1,3 @@ -import path from "node:path"; import type { AdapterEnvironmentCheck, AdapterEnvironmentTestContext, @@ -14,32 +13,9 @@ import { parseObject, runChildProcess, } from "@agentcompany/adapter-utils/server-utils"; +import { summarizeStatus, isNonEmpty, commandLooksLike, summarizeProbeDetail } from "@agentcompany/adapter-utils/test-utils"; import { DEFAULT_GEMINI_LOCAL_MODEL } from "../index.js"; import { detectGeminiAuthRequired, parseGeminiJsonl } from "./parse.js"; -import { firstNonEmptyLine } from "./utils.js"; - -function summarizeStatus(checks: AdapterEnvironmentCheck[]): AdapterEnvironmentTestResult["status"] { - if (checks.some((check) => check.level === "error")) return "fail"; - if (checks.some((check) => check.level === "warn")) return "warn"; - return "pass"; -} - -function isNonEmpty(value: unknown): value is string { - return typeof value === "string" && value.trim().length > 0; -} - -function commandLooksLike(command: string, expected: string): boolean { - const base = path.basename(command).toLowerCase(); - return base === expected || base === `${expected}.cmd` || base === `${expected}.exe`; -} - -function summarizeProbeDetail(stdout: string, stderr: string, parsedError: string | null): string | null { - const raw = parsedError?.trim() || firstNonEmptyLine(stderr) || firstNonEmptyLine(stdout); - if (!raw) return null; - const clean = raw.replace(/\s+/g, " ").trim(); - const max = 240; - return clean.length > max ? `${clean.slice(0, max - 1)}…` : clean; -} export async function testEnvironment( ctx: AdapterEnvironmentTestContext, diff --git a/packages/adapter-gemini-local/src/server/utils.ts b/packages/adapter-gemini-local/src/server/utils.ts deleted file mode 100644 index fb11c75d..00000000 --- a/packages/adapter-gemini-local/src/server/utils.ts +++ /dev/null @@ -1,8 +0,0 @@ -export function firstNonEmptyLine(text: string): string { - return ( - text - .split(/\r?\n/) - .map((line) => line.trim()) - .find(Boolean) ?? "" - ); -} diff --git a/packages/adapter-gemini-local/src/ui/build-config.ts b/packages/adapter-gemini-local/src/ui/build-config.ts index ad8ef161..d38af272 100644 --- a/packages/adapter-gemini-local/src/ui/build-config.ts +++ b/packages/adapter-gemini-local/src/ui/build-config.ts @@ -1,56 +1,7 @@ import type { CreateConfigValues } from "@agentcompany/adapter-utils"; +import { parseCommaArgs, parseEnvVars, parseEnvBindings } from "@agentcompany/adapter-utils/config-utils"; import { DEFAULT_GEMINI_LOCAL_MODEL } from "../index.js"; -function parseCommaArgs(value: string): string[] { - return value - .split(",") - .map((item) => item.trim()) - .filter(Boolean); -} - -function parseEnvVars(text: string): Record { - const env: Record = {}; - for (const line of text.split(/\r?\n/)) { - const trimmed = line.trim(); - if (!trimmed || trimmed.startsWith("#")) continue; - const eq = trimmed.indexOf("="); - if (eq <= 0) continue; - const key = trimmed.slice(0, eq).trim(); - const value = trimmed.slice(eq + 1); - if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) continue; - env[key] = value; - } - return env; -} - -function parseEnvBindings(bindings: unknown): Record { - if (typeof bindings !== "object" || bindings === null || Array.isArray(bindings)) return {}; - const env: Record = {}; - for (const [key, raw] of Object.entries(bindings)) { - if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) continue; - if (typeof raw === "string") { - env[key] = { type: "plain", value: raw }; - continue; - } - if (typeof raw !== "object" || raw === null || Array.isArray(raw)) continue; - const rec = raw as Record; - if (rec.type === "plain" && typeof rec.value === "string") { - env[key] = { type: "plain", value: rec.value }; - continue; - } - if (rec.type === "secret_ref" && typeof rec.secretId === "string") { - env[key] = { - type: "secret_ref", - secretId: rec.secretId, - ...(typeof rec.version === "number" || rec.version === "latest" - ? { version: rec.version } - : {}), - }; - } - } - return env; -} - export function buildGeminiLocalConfig(v: CreateConfigValues): Record { const ac: Record = {}; if (v.cwd) ac.cwd = v.cwd; diff --git a/packages/adapter-gemini-local/src/ui/parse-stdout.ts b/packages/adapter-gemini-local/src/ui/parse-stdout.ts index cc9d1c75..79e7303a 100644 --- a/packages/adapter-gemini-local/src/ui/parse-stdout.ts +++ b/packages/adapter-gemini-local/src/ui/parse-stdout.ts @@ -1,17 +1,5 @@ import type { TranscriptEntry } from "@agentcompany/adapter-utils"; - -function safeJsonParse(text: string): unknown { - try { - return JSON.parse(text); - } catch { - return null; - } -} - -function asRecord(value: unknown): Record | null { - if (typeof value !== "object" || value === null || Array.isArray(value)) return null; - return value as Record; -} +import { asRecord, safeJsonParse, errorText } from "@agentcompany/adapter-utils/parse-utils"; function asString(value: unknown, fallback = ""): string { return typeof value === "string" ? value : fallback; @@ -31,23 +19,6 @@ function stringifyUnknown(value: unknown): string { } } -function errorText(value: unknown): string { - if (typeof value === "string") return value; - const rec = asRecord(value); - if (!rec) return ""; - const msg = - (typeof rec.message === "string" && rec.message) || - (typeof rec.error === "string" && rec.error) || - (typeof rec.code === "string" && rec.code) || - ""; - if (msg) return msg; - try { - return JSON.stringify(rec); - } catch { - return ""; - } -} - function collectTextEntries(messageRaw: unknown, ts: string, kind: "assistant" | "user"): TranscriptEntry[] { if (typeof messageRaw === "string") { const text = messageRaw.trim(); diff --git a/packages/adapter-kimi-local/src/server/execute.ts b/packages/adapter-kimi-local/src/server/execute.ts index e665ed6d..15f8d35e 100644 --- a/packages/adapter-kimi-local/src/server/execute.ts +++ b/packages/adapter-kimi-local/src/server/execute.ts @@ -11,6 +11,7 @@ import { runChildProcess, createManagedSkillSymlinks, } from "@agentcompany/adapter-utils/server-utils"; +import { normalizeEnv } from "@agentcompany/adapter-utils/test-utils"; import { DEFAULT_KIMI_LOCAL_MODEL } from "../index.js"; function kimiSkillsHome(): string { @@ -25,15 +26,6 @@ async function ensureKimiSkillsInjected( await createManagedSkillSymlinks(managedSkills, kimiSkillsHome(), onLog); } -function normalizeEnv(input: unknown): Record { - if (typeof input !== "object" || input === null || Array.isArray(input)) return {}; - const env: Record = {}; - for (const [key, value] of Object.entries(input as Record)) { - if (typeof value === "string") env[key] = value; - } - return env; -} - export async function execute(ctx: AdapterExecutionContext): Promise { const { runId, config, context, onLog } = ctx; const command = asString(config.command, "kimi"); diff --git a/packages/adapter-kimi-local/src/server/test.ts b/packages/adapter-kimi-local/src/server/test.ts index e0b62523..1617ae8d 100644 --- a/packages/adapter-kimi-local/src/server/test.ts +++ b/packages/adapter-kimi-local/src/server/test.ts @@ -7,15 +7,7 @@ import { ensureCommandResolvable, ensurePathInEnv, } from "@agentcompany/adapter-utils/server-utils"; - -function normalizeEnv(input: unknown): Record { - if (typeof input !== "object" || input === null || Array.isArray(input)) return {}; - const env: Record = {}; - for (const [key, value] of Object.entries(input as Record)) { - if (typeof value === "string") env[key] = value; - } - return env; -} +import { normalizeEnv } from "@agentcompany/adapter-utils/test-utils"; export async function testEnvironment( ctx: AdapterEnvironmentTestContext, diff --git a/packages/adapter-kimi-local/src/ui/build-config.ts b/packages/adapter-kimi-local/src/ui/build-config.ts index fc083809..fac4517d 100644 --- a/packages/adapter-kimi-local/src/ui/build-config.ts +++ b/packages/adapter-kimi-local/src/ui/build-config.ts @@ -1,56 +1,7 @@ import type { CreateConfigValues } from "@agentcompany/adapter-utils"; +import { parseCommaArgs, parseEnvVars, parseEnvBindings } from "@agentcompany/adapter-utils/config-utils"; import { DEFAULT_KIMI_LOCAL_MODEL } from "../index.js"; -function parseCommaArgs(value: string): string[] { - return value - .split(",") - .map((item) => item.trim()) - .filter(Boolean); -} - -function parseEnvVars(text: string): Record { - const env: Record = {}; - for (const line of text.split(/\r?\n/)) { - const trimmed = line.trim(); - if (!trimmed || trimmed.startsWith("#")) continue; - const eq = trimmed.indexOf("="); - if (eq <= 0) continue; - const key = trimmed.slice(0, eq).trim(); - const value = trimmed.slice(eq + 1); - if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) continue; - env[key] = value; - } - return env; -} - -function parseEnvBindings(bindings: unknown): Record { - if (typeof bindings !== "object" || bindings === null || Array.isArray(bindings)) return {}; - const env: Record = {}; - for (const [key, raw] of Object.entries(bindings)) { - if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) continue; - if (typeof raw === "string") { - env[key] = { type: "plain", value: raw }; - continue; - } - if (typeof raw !== "object" || raw === null || Array.isArray(raw)) continue; - const rec = raw as Record; - if (rec.type === "plain" && typeof rec.value === "string") { - env[key] = { type: "plain", value: rec.value }; - continue; - } - if (rec.type === "secret_ref" && typeof rec.secretId === "string") { - env[key] = { - type: "secret_ref", - secretId: rec.secretId, - ...(typeof rec.version === "number" || rec.version === "latest" - ? { version: rec.version } - : {}), - }; - } - } - return env; -} - export function buildKimiLocalConfig(v: CreateConfigValues): Record { const config: Record = {}; if (v.cwd) config.cwd = v.cwd; diff --git a/packages/adapter-opencode-local/src/cli/format-event.ts b/packages/adapter-opencode-local/src/cli/format-event.ts index 58d2038d..9cd6f97c 100644 --- a/packages/adapter-opencode-local/src/cli/format-event.ts +++ b/packages/adapter-opencode-local/src/cli/format-event.ts @@ -1,43 +1,5 @@ import pc from "picocolors"; - -function safeJsonParse(text: string): unknown { - try { - return JSON.parse(text); - } catch { - return null; - } -} - -function asRecord(value: unknown): Record | null { - if (typeof value !== "object" || value === null || Array.isArray(value)) return null; - return value as Record; -} - -function asString(value: unknown, fallback = ""): string { - return typeof value === "string" ? value : fallback; -} - -function asNumber(value: unknown, fallback = 0): number { - return typeof value === "number" && Number.isFinite(value) ? value : fallback; -} - -function errorText(value: unknown): string { - if (typeof value === "string") return value; - const rec = asRecord(value); - if (!rec) return ""; - const data = asRecord(rec.data); - const message = - asString(rec.message) || - asString(data?.message) || - asString(rec.name) || - ""; - if (message) return message; - try { - return JSON.stringify(rec); - } catch { - return ""; - } -} +import { asRecord, safeJsonParse, asString, asNumber, errorText } from "@agentcompany/adapter-utils/parse-utils"; export function printOpenCodeStreamEvent(raw: string, _debug: boolean): void { const line = raw.trim(); diff --git a/packages/adapter-opencode-local/src/server/execute.ts b/packages/adapter-opencode-local/src/server/execute.ts index 68823dd4..c765182a 100644 --- a/packages/adapter-opencode-local/src/server/execute.ts +++ b/packages/adapter-opencode-local/src/server/execute.ts @@ -17,6 +17,7 @@ import { runChildProcess, createManagedSkillSymlinks, } from "@agentcompany/adapter-utils/server-utils"; +import { firstNonEmptyLine } from "@agentcompany/adapter-utils/test-utils"; import { isOpenCodeUnknownSessionError, parseOpenCodeJsonl } from "./parse.js"; import { ensureOpenCodeModelConfiguredAndAvailable } from "./models.js"; @@ -26,15 +27,6 @@ const SKILLS_CANDIDATES = [ path.resolve(__moduleDir, "../../../../../skills"), ]; -function firstNonEmptyLine(text: string): string { - return ( - text - .split(/\r?\n/) - .map((line) => line.trim()) - .find(Boolean) ?? "" - ); -} - function parseModelProvider(model: string | null): string | null { if (!model) return null; const trimmed = model.trim(); diff --git a/packages/adapter-opencode-local/src/server/index.ts b/packages/adapter-opencode-local/src/server/index.ts index 5b5b9e65..9865584d 100644 --- a/packages/adapter-opencode-local/src/server/index.ts +++ b/packages/adapter-opencode-local/src/server/index.ts @@ -1,64 +1,6 @@ -import type { AdapterSessionCodec } from "@agentcompany/adapter-utils"; +import { createStandardSessionCodec } from "@agentcompany/adapter-utils/session-codec"; -function readNonEmptyString(value: unknown): string | null { - return typeof value === "string" && value.trim().length > 0 ? value.trim() : null; -} - -export const sessionCodec: AdapterSessionCodec = { - deserialize(raw: unknown) { - if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return null; - const record = raw as Record; - const sessionId = - readNonEmptyString(record.sessionId) ?? - readNonEmptyString(record.session_id) ?? - readNonEmptyString(record.sessionID); - if (!sessionId) return null; - const cwd = - readNonEmptyString(record.cwd) ?? - readNonEmptyString(record.workdir) ?? - readNonEmptyString(record.folder); - const workspaceId = readNonEmptyString(record.workspaceId) ?? readNonEmptyString(record.workspace_id); - const repoUrl = readNonEmptyString(record.repoUrl) ?? readNonEmptyString(record.repo_url); - const repoRef = readNonEmptyString(record.repoRef) ?? readNonEmptyString(record.repo_ref); - return { - sessionId, - ...(cwd ? { cwd } : {}), - ...(workspaceId ? { workspaceId } : {}), - ...(repoUrl ? { repoUrl } : {}), - ...(repoRef ? { repoRef } : {}), - }; - }, - serialize(params: Record | null) { - if (!params) return null; - const sessionId = - readNonEmptyString(params.sessionId) ?? - readNonEmptyString(params.session_id) ?? - readNonEmptyString(params.sessionID); - if (!sessionId) return null; - const cwd = - readNonEmptyString(params.cwd) ?? - readNonEmptyString(params.workdir) ?? - readNonEmptyString(params.folder); - const workspaceId = readNonEmptyString(params.workspaceId) ?? readNonEmptyString(params.workspace_id); - const repoUrl = readNonEmptyString(params.repoUrl) ?? readNonEmptyString(params.repo_url); - const repoRef = readNonEmptyString(params.repoRef) ?? readNonEmptyString(params.repo_ref); - return { - sessionId, - ...(cwd ? { cwd } : {}), - ...(workspaceId ? { workspaceId } : {}), - ...(repoUrl ? { repoUrl } : {}), - ...(repoRef ? { repoRef } : {}), - }; - }, - getDisplayId(params: Record | null) { - if (!params) return null; - return ( - readNonEmptyString(params.sessionId) ?? - readNonEmptyString(params.session_id) ?? - readNonEmptyString(params.sessionID) - ); - }, -}; +export const sessionCodec = createStandardSessionCodec({ extraSessionIdKeys: ["sessionID"] }); export { execute } from "./execute.js"; export { testEnvironment } from "./test.js"; diff --git a/packages/adapter-opencode-local/src/server/models.ts b/packages/adapter-opencode-local/src/server/models.ts index b10e759f..7c5c3eca 100644 --- a/packages/adapter-opencode-local/src/server/models.ts +++ b/packages/adapter-opencode-local/src/server/models.ts @@ -5,6 +5,7 @@ import { ensurePathInEnv, runChildProcess, } from "@agentcompany/adapter-utils/server-utils"; +import { firstNonEmptyLine } from "@agentcompany/adapter-utils/test-utils"; const MODELS_CACHE_TTL_MS = 60_000; @@ -39,15 +40,6 @@ function sortModels(models: AdapterModel[]): AdapterModel[] { ); } -function firstNonEmptyLine(text: string): string { - return ( - text - .split(/\r?\n/) - .map((line) => line.trim()) - .find(Boolean) ?? "" - ); -} - function parseModelsOutput(stdout: string): AdapterModel[] { const parsed: AdapterModel[] = []; for (const raw of stdout.split(/\r?\n/)) { diff --git a/packages/adapter-opencode-local/src/server/test.ts b/packages/adapter-opencode-local/src/server/test.ts index 86322b52..1b31f515 100644 --- a/packages/adapter-opencode-local/src/server/test.ts +++ b/packages/adapter-opencode-local/src/server/test.ts @@ -12,41 +12,10 @@ import { ensurePathInEnv, runChildProcess, } from "@agentcompany/adapter-utils/server-utils"; +import { summarizeStatus, summarizeProbeDetail, normalizeEnv } from "@agentcompany/adapter-utils/test-utils"; import { discoverOpenCodeModels, ensureOpenCodeModelConfiguredAndAvailable } from "./models.js"; import { parseOpenCodeJsonl } from "./parse.js"; -function summarizeStatus(checks: AdapterEnvironmentCheck[]): AdapterEnvironmentTestResult["status"] { - if (checks.some((check) => check.level === "error")) return "fail"; - if (checks.some((check) => check.level === "warn")) return "warn"; - return "pass"; -} - -function firstNonEmptyLine(text: string): string { - return ( - text - .split(/\r?\n/) - .map((line) => line.trim()) - .find(Boolean) ?? "" - ); -} - -function summarizeProbeDetail(stdout: string, stderr: string, parsedError: string | null): string | null { - const raw = parsedError?.trim() || firstNonEmptyLine(stderr) || firstNonEmptyLine(stdout); - if (!raw) return null; - const clean = raw.replace(/\s+/g, " ").trim(); - const max = 240; - return clean.length > max ? `${clean.slice(0, max - 1)}...` : clean; -} - -function normalizeEnv(input: unknown): Record { - if (typeof input !== "object" || input === null || Array.isArray(input)) return {}; - const env: Record = {}; - for (const [key, value] of Object.entries(input as Record)) { - if (typeof value === "string") env[key] = value; - } - return env; -} - const OPENCODE_AUTH_REQUIRED_RE = /(?:auth(?:entication)?\s+required|api\s*key|invalid\s*api\s*key|not\s+logged\s+in|opencode\s+auth\s+login|free\s+usage\s+exceeded)/i; diff --git a/packages/adapter-opencode-local/src/ui/build-config.ts b/packages/adapter-opencode-local/src/ui/build-config.ts index c8784140..cd76e9af 100644 --- a/packages/adapter-opencode-local/src/ui/build-config.ts +++ b/packages/adapter-opencode-local/src/ui/build-config.ts @@ -1,54 +1,5 @@ import type { CreateConfigValues } from "@agentcompany/adapter-utils"; - -function parseCommaArgs(value: string): string[] { - return value - .split(",") - .map((item) => item.trim()) - .filter(Boolean); -} - -function parseEnvVars(text: string): Record { - const env: Record = {}; - for (const line of text.split(/\r?\n/)) { - const trimmed = line.trim(); - if (!trimmed || trimmed.startsWith("#")) continue; - const eq = trimmed.indexOf("="); - if (eq <= 0) continue; - const key = trimmed.slice(0, eq).trim(); - const value = trimmed.slice(eq + 1); - if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) continue; - env[key] = value; - } - return env; -} - -function parseEnvBindings(bindings: unknown): Record { - if (typeof bindings !== "object" || bindings === null || Array.isArray(bindings)) return {}; - const env: Record = {}; - for (const [key, raw] of Object.entries(bindings)) { - if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) continue; - if (typeof raw === "string") { - env[key] = { type: "plain", value: raw }; - continue; - } - if (typeof raw !== "object" || raw === null || Array.isArray(raw)) continue; - const rec = raw as Record; - if (rec.type === "plain" && typeof rec.value === "string") { - env[key] = { type: "plain", value: rec.value }; - continue; - } - if (rec.type === "secret_ref" && typeof rec.secretId === "string") { - env[key] = { - type: "secret_ref", - secretId: rec.secretId, - ...(typeof rec.version === "number" || rec.version === "latest" - ? { version: rec.version } - : {}), - }; - } - } - return env; -} +import { parseCommaArgs, parseEnvVars, parseEnvBindings } from "@agentcompany/adapter-utils/config-utils"; export function buildOpenCodeLocalConfig(v: CreateConfigValues): Record { const ac: Record = {}; diff --git a/packages/adapter-opencode-local/src/ui/parse-stdout.ts b/packages/adapter-opencode-local/src/ui/parse-stdout.ts index bf495040..71973340 100644 --- a/packages/adapter-opencode-local/src/ui/parse-stdout.ts +++ b/packages/adapter-opencode-local/src/ui/parse-stdout.ts @@ -1,17 +1,5 @@ import type { TranscriptEntry } from "@agentcompany/adapter-utils"; - -function safeJsonParse(text: string): unknown { - try { - return JSON.parse(text); - } catch { - return null; - } -} - -function asRecord(value: unknown): Record | null { - if (typeof value !== "object" || value === null || Array.isArray(value)) return null; - return value as Record; -} +import { asRecord, safeJsonParse } from "@agentcompany/adapter-utils/parse-utils"; function asString(value: unknown, fallback = ""): string { return typeof value === "string" ? value : fallback; diff --git a/packages/adapter-utils/src/config-utils.ts b/packages/adapter-utils/src/config-utils.ts new file mode 100644 index 00000000..cf5a26cf --- /dev/null +++ b/packages/adapter-utils/src/config-utils.ts @@ -0,0 +1,61 @@ +export function parseCommaArgs(value: string): string[] { + return value + .split(",") + .map((item) => item.trim()) + .filter(Boolean); +} + +export function parseEnvVars(text: string): Record { + const env: Record = {}; + for (const line of text.split(/\r?\n/)) { + const trimmed = line.trim(); + if (!trimmed || trimmed.startsWith("#")) continue; + const eq = trimmed.indexOf("="); + if (eq <= 0) continue; + const key = trimmed.slice(0, eq).trim(); + const value = trimmed.slice(eq + 1); + if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) continue; + env[key] = value; + } + return env; +} + +export function parseEnvBindings(bindings: unknown): Record { + if (typeof bindings !== "object" || bindings === null || Array.isArray(bindings)) return {}; + const env: Record = {}; + for (const [key, raw] of Object.entries(bindings)) { + if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) continue; + if (typeof raw === "string") { + env[key] = { type: "plain", value: raw }; + continue; + } + if (typeof raw !== "object" || raw === null || Array.isArray(raw)) continue; + const rec = raw as Record; + if (rec.type === "plain" && typeof rec.value === "string") { + env[key] = { type: "plain", value: rec.value }; + continue; + } + if (rec.type === "secret_ref" && typeof rec.secretId === "string") { + env[key] = { + type: "secret_ref", + secretId: rec.secretId, + ...(typeof rec.version === "number" || rec.version === "latest" + ? { version: rec.version } + : {}), + }; + } + } + return env; +} + +export function parseJsonObject(text: string): Record | null { + const trimmed = text.trim(); + if (!trimmed) return null; + try { + const parsed = JSON.parse(trimmed); + if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return null; + return parsed as Record; + } catch { + return null; + } +} diff --git a/packages/adapter-utils/src/parse-utils.ts b/packages/adapter-utils/src/parse-utils.ts new file mode 100644 index 00000000..a54ec734 --- /dev/null +++ b/packages/adapter-utils/src/parse-utils.ts @@ -0,0 +1,47 @@ +export function asRecord(value: unknown): Record | null { + if (typeof value !== "object" || value === null || Array.isArray(value)) return null; + return value as Record; +} + +export function safeJsonParse(text: string): unknown { + try { + return JSON.parse(text); + } catch { + return null; + } +} + +export function errorText(value: unknown): string { + if (typeof value === "string") return value; + const rec = asRecord(value); + if (!rec) return ""; + const msg = + (typeof rec.message === "string" && rec.message) || + (typeof rec.error === "string" && rec.error) || + (typeof rec.code === "string" && rec.code) || + ""; + if (msg) return msg; + try { + return JSON.stringify(rec); + } catch { + return ""; + } +} + +export function asString(value: unknown, fallback = ""): string { + return typeof value === "string" ? value : fallback; +} + +export function asNumber(value: unknown, fallback = 0): number { + return typeof value === "number" && Number.isFinite(value) ? value : fallback; +} + +export function stringifyUnknown(value: unknown): string { + if (typeof value === "string") return value; + if (value === null || value === undefined) return ""; + try { + return JSON.stringify(value, null, 2); + } catch { + return String(value); + } +} diff --git a/packages/adapter-utils/src/server-utils.ts b/packages/adapter-utils/src/server-utils.ts index 31255ef4..af964e6f 100644 --- a/packages/adapter-utils/src/server-utils.ts +++ b/packages/adapter-utils/src/server-utils.ts @@ -1,4 +1,4 @@ -import { spawn, type ChildProcess } from "node:child_process"; +import { spawn, execSync, type ChildProcess } from "node:child_process"; import { constants as fsConstants, promises as fs, type Dirent } from "node:fs"; import path from "node:path"; import { StringDecoder } from "node:string_decoder"; @@ -354,6 +354,7 @@ export async function runChildProcess( cwd: opts.cwd, env: mergedEnv, shell: false, + windowsHide: true, stdio: [opts.stdin != null ? "pipe" : "ignore", "pipe", "pipe"], }) as ChildProcessWithEvents; @@ -468,6 +469,37 @@ export async function runChildProcess( }); } +/** + * Kill a process and all its descendants. + * Windows: `taskkill /T /F` kills the full process tree. + * Unix: SIGKILL the process directly (CLI tools are leaf processes). + */ +function killProcessTree(pid: number): void { + if (process.platform === "win32") { + try { + execSync(`taskkill /T /F /PID ${pid}`, { stdio: "ignore", timeout: 5000 }); + } catch { /* process already exited */ } + } else { + try { + process.kill(pid, "SIGKILL"); + } catch { /* already dead */ } + } +} + +/** + * Force-kill every child process tracked in `runningProcesses` and clear the map. + * Called by the worker during shutdown to ensure no CLI processes survive app quit. + */ +export function shutdownAllRunning(): void { + for (const [runId, entry] of runningProcesses) { + const pid = entry.child.pid; + if (pid != null) { + killProcessTree(pid); + } + runningProcesses.delete(runId); + } +} + /** * Create symlinks for managed skills in the target directory. * Per D-13: uses 'junction' type on Windows to avoid Developer Mode requirement. diff --git a/packages/adapter-utils/src/session-codec.ts b/packages/adapter-utils/src/session-codec.ts new file mode 100644 index 00000000..d813984c --- /dev/null +++ b/packages/adapter-utils/src/session-codec.ts @@ -0,0 +1,61 @@ +import type { AdapterSessionCodec } from "./types.js"; + +function readNonEmptyString(value: unknown): string | null { + return typeof value === "string" && value.trim().length > 0 ? value.trim() : null; +} + +interface SessionCodecOptions { + /** Additional key aliases for sessionId beyond "sessionId" and "session_id" (e.g. "sessionID" for Gemini/OpenCode). */ + extraSessionIdKeys?: string[]; +} + +/** + * Creates a standard session codec shared across adapters. + * All adapters use the same serialize/deserialize/getDisplayId logic, + * differing only in which keys they accept for sessionId. + */ +export function createStandardSessionCodec(options?: SessionCodecOptions): AdapterSessionCodec { + const extraKeys = options?.extraSessionIdKeys ?? []; + + function readSessionId(record: Record): string | null { + return ( + readNonEmptyString(record.sessionId) ?? + readNonEmptyString(record.session_id) ?? + extraKeys.reduce((found, key) => found ?? readNonEmptyString(record[key]), null) + ); + } + + function extractFields(record: Record) { + const sessionId = readSessionId(record); + if (!sessionId) return null; + const cwd = + readNonEmptyString(record.cwd) ?? + readNonEmptyString(record.workdir) ?? + readNonEmptyString(record.folder); + const workspaceId = readNonEmptyString(record.workspaceId) ?? readNonEmptyString(record.workspace_id); + const repoUrl = readNonEmptyString(record.repoUrl) ?? readNonEmptyString(record.repo_url); + const repoRef = readNonEmptyString(record.repoRef) ?? readNonEmptyString(record.repo_ref); + return { + sessionId, + ...(cwd ? { cwd } : {}), + ...(workspaceId ? { workspaceId } : {}), + ...(repoUrl ? { repoUrl } : {}), + ...(repoRef ? { repoRef } : {}), + }; + } + + return { + deserialize(raw: unknown) { + if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return null; + return extractFields(raw as Record); + }, + serialize(params: Record | null) { + if (!params) return null; + return extractFields(params); + }, + getDisplayId(params: Record | null) { + if (!params) return null; + return readSessionId(params); + }, + }; +} diff --git a/packages/adapter-utils/src/test-utils.ts b/packages/adapter-utils/src/test-utils.ts new file mode 100644 index 00000000..8cbb8b69 --- /dev/null +++ b/packages/adapter-utils/src/test-utils.ts @@ -0,0 +1,43 @@ +import path from "node:path"; +import type { AdapterEnvironmentCheck, AdapterEnvironmentTestResult } from "./types.js"; + +export function summarizeStatus(checks: AdapterEnvironmentCheck[]): AdapterEnvironmentTestResult["status"] { + if (checks.some((check) => check.level === "error")) return "fail"; + if (checks.some((check) => check.level === "warn")) return "warn"; + return "pass"; +} + +export function isNonEmpty(value: unknown): value is string { + return typeof value === "string" && value.trim().length > 0; +} + +export function firstNonEmptyLine(text: string): string { + return ( + text + .split(/\r?\n/) + .map((line) => line.trim()) + .find(Boolean) ?? "" + ); +} + +export function commandLooksLike(command: string, expected: string): boolean { + const base = path.basename(command).toLowerCase(); + return base === expected || base === `${expected}.cmd` || base === `${expected}.exe`; +} + +export function summarizeProbeDetail(stdout: string, stderr: string, parsedError?: string | null): string | null { + const raw = parsedError?.trim() || firstNonEmptyLine(stderr) || firstNonEmptyLine(stdout); + if (!raw) return null; + const clean = raw.replace(/\s+/g, " ").trim(); + const max = 240; + return clean.length > max ? `${clean.slice(0, max - 1)}…` : clean; +} + +export function normalizeEnv(input: unknown): Record { + if (typeof input !== "object" || input === null || Array.isArray(input)) return {}; + const env: Record = {}; + for (const [key, value] of Object.entries(input as Record)) { + if (typeof value === "string") env[key] = value; + } + return env; +} diff --git a/packages/adapter-utils/src/types.ts b/packages/adapter-utils/src/types.ts index 5e1bf93e..064a67bf 100644 --- a/packages/adapter-utils/src/types.ts +++ b/packages/adapter-utils/src/types.ts @@ -1,7 +1,3 @@ -// --------------------------------------------------------------------------- -// Minimal adapter-facing interfaces (no drizzle dependency) -// --------------------------------------------------------------------------- - export interface AdapterAgent { id: string; companyId: string; @@ -20,10 +16,6 @@ export interface AdapterRuntime { taskKey: string | null; } -// --------------------------------------------------------------------------- -// Execution types (moved from server/src/adapters/types.ts) -// --------------------------------------------------------------------------- - export interface UsageSummary { inputTokens: number; outputTokens: number; @@ -137,10 +129,6 @@ export interface AdapterEnvironmentTestResult { testedAt: string; } -// --------------------------------------------------------------------------- -// Skill sync types -- adapter-level skill state and synchronization -// --------------------------------------------------------------------------- - export type AdapterSkillSyncMode = "unsupported" | "persistent" | "ephemeral"; export type AdapterSkillState = @@ -246,10 +234,6 @@ export interface ServerAdapterModule { ) => Promise; } -// --------------------------------------------------------------------------- -// UI types (moved from ui/src/adapters/types.ts) -// --------------------------------------------------------------------------- - export type TranscriptEntry = | { kind: "assistant"; ts: string; text: string; delta?: boolean } | { kind: "thinking"; ts: string; text: string; delta?: boolean } @@ -264,19 +248,11 @@ export type TranscriptEntry = export type StdoutLineParser = (line: string, ts: string) => TranscriptEntry[]; -// --------------------------------------------------------------------------- -// CLI types (moved from cli/src/adapters/types.ts) -// --------------------------------------------------------------------------- - export interface CLIAdapterModule { type: string; formatStdoutEvent: (line: string, debug: boolean) => void; } -// --------------------------------------------------------------------------- -// UI config form values (moved from ui/src/components/AgentConfigForm.tsx) -// --------------------------------------------------------------------------- - /** Skill reference passed from main process to worker for adapter injection. */ export interface ManagedSkillRef { /** Skill slug used as directory name in the adapter's skill directory */ diff --git a/src/main/api-server.ts b/src/main/api-server.ts index de7d106a..a22f3702 100644 --- a/src/main/api-server.ts +++ b/src/main/api-server.ts @@ -432,12 +432,20 @@ export class AgentApiServer { } catch { /* deliverable review interception is best-effort; fall through to normal flow */ } } + // Validate status transition + const effectiveStatus = update.status ?? task.status; + const VALID_STATUSES = new Set(["backlog", "todo", "in_progress", "in_review", "done", "blocked", "cancelled"]); + if (update.status && !VALID_STATUSES.has(update.status)) { + this.json(res, 400, { error: `Invalid task status: ${update.status}` }); + return; + } + const input: Record = { id: task.id, companyId: task.companyId, title: update.title ?? task.title, description: update.description ?? task.description, - status: update.status ?? task.status, + status: effectiveStatus, priority: update.priority ?? task.priority, projectId: task.projectId, goalId: task.goalId, @@ -447,6 +455,11 @@ export class AgentApiServer { }; this.db.saveTask(input as Parameters[0]); + // Apply status side-effect timestamps via advanceTaskStatus if status changed + if (update.status && update.status !== task.status) { + this.db.advanceTaskStatus(task.id, update.status); + } + if (update.comment) { const agent = this.db.getAgent(token.agentId); this.db.addComment({ @@ -861,6 +874,31 @@ export class AgentApiServer { return; } + // Prevent duplicate agents: reject if a non-terminated agent with the same name already exists + const existingAgents = this.db.listSnapshot().agents.filter( + (a) => a.companyId === companyId && a.status !== "terminated", + ); + const duplicateByName = existingAgents.find( + (a) => a.name.toLowerCase() === input.name.toLowerCase(), + ); + if (duplicateByName) { + this.json(res, 409, { error: `Agent "${input.name}" already exists in this company (id: ${duplicateByName.id}, role: ${duplicateByName.role}). Use the existing agent instead of creating a duplicate.` }); + return; + } + // Also check pending hire approvals with the same name to prevent concurrent duplicate requests + const pendingHires = this.db.listSnapshot().approvals.filter( + (a) => a.companyId === companyId && a.type === "hire_agent" && a.state === "pending", + ); + for (const pending of pendingHires) { + try { + const payload = pending.payloadJson ? JSON.parse(pending.payloadJson) as Record : {}; + if (typeof payload.name === "string" && payload.name.toLowerCase() === input.name.toLowerCase()) { + this.json(res, 409, { error: `A hire request for "${input.name}" is already pending approval.` }); + return; + } + } catch { /* invalid payloadJson, skip */ } + } + const managerLabel = input.reportsTo ? (() => { try { @@ -975,6 +1013,16 @@ export class AgentApiServer { const chain = this.db.getChainOfCommand(token.agentId); if (chain.length > 0 && chain[0].id !== token.agentId && !wokenForComment.has(chain[0].id)) { this.onWakeAgent(chain[0].id, task.companyId, "comment"); + wokenForComment.add(chain[0].id); + } + + // @mention detection: wake any mentioned agents not already woken + const mentionedIds = this.db.findMentionedAgentIds(task.companyId, input.body); + for (const mentionedId of mentionedIds) { + if (mentionedId !== token.agentId && !wokenForComment.has(mentionedId)) { + this.onWakeAgent(mentionedId, task.companyId, "comment_mentioned"); + wokenForComment.add(mentionedId); + } } this.json(res, 201, comment); @@ -1115,6 +1163,88 @@ export class AgentApiServer { this.json(res, 403, { error: "Approvals must be decided from the desktop board, not from an agent run token" }); }); + this.addRoute("GET", "/api/approvals/:approvalId/comments", (_req, res, params, token) => { + const approval = this.db.listSnapshot().approvals.find((a) => a.id === params.approvalId); + if (!approval) { this.json(res, 404, { error: "Approval not found" }); return; } + if (approval.companyId !== token.companyId) { this.json(res, 403, { error: "Company mismatch" }); return; } + const comments = this.db.listApprovalComments(params.approvalId!, approval.companyId); + this.json(res, 200, comments); + }); + + this.addRoute("POST", "/api/approvals/:approvalId/comments", (_req, res, params, token, body) => { + const approval = this.db.listSnapshot().approvals.find((a) => a.id === params.approvalId); + if (!approval) { this.json(res, 404, { error: "Approval not found" }); return; } + if (approval.companyId !== token.companyId) { this.json(res, 403, { error: "Company mismatch" }); return; } + const data = body as Record; + const commentBody = typeof data.body === "string" ? data.body.trim() : ""; + if (!commentBody) { this.json(res, 400, { error: "Comment body is required" }); return; } + const commentId = this.db.addApprovalComment({ + companyId: approval.companyId, + approvalId: approval.id, + authorAgentId: token.agentId ?? null, + body: commentBody, + }); + // Wake mentioned agents in comment + const mentionedIds = this.db.findMentionedAgentIds(approval.companyId, commentBody); + for (const mentionedId of mentionedIds) { + if (mentionedId !== token.agentId) { + this.onWakeAgent(mentionedId, approval.companyId, "approval_comment_mentioned"); + } + } + this.onDomainChanged(); + this.json(res, 201, { id: commentId }); + }); + + this.addRoute("POST", "/api/approvals/:approvalId/resubmit", (_req, res, params, token) => { + const approval = this.db.listSnapshot().approvals.find((a) => a.id === params.approvalId); + if (!approval) { this.json(res, 404, { error: "Approval not found" }); return; } + if (approval.companyId !== token.companyId) { this.json(res, 403, { error: "Company mismatch" }); return; } + if (approval.state !== "revision_requested") { + this.json(res, 422, { error: "Only revision_requested approvals can be resubmitted" }); + return; + } + if (token.agentId !== approval.requestedByAgentId) { + this.json(res, 403, { error: "Only the requesting agent can resubmit this approval" }); + return; + } + this.db.resubmitApproval(approval.id, approval.companyId); + this.onDomainChanged(); + this.json(res, 200, { resubmitted: true }); + }); + + this.addRoute("GET", "/api/approvals/:approvalId/tasks", (_req, res, params, token) => { + const approval = this.db.listSnapshot().approvals.find((a) => a.id === params.approvalId); + if (!approval) { this.json(res, 404, { error: "Approval not found" }); return; } + if (approval.companyId !== token.companyId) { this.json(res, 403, { error: "Company mismatch" }); return; } + const taskIds = this.db.listTasksForApproval(params.approvalId!); + this.json(res, 200, taskIds); + }); + + this.addRoute("POST", "/api/approvals/:approvalId/tasks", (_req, res, params, token, body) => { + const approval = this.db.listSnapshot().approvals.find((a) => a.id === params.approvalId); + if (!approval) { this.json(res, 404, { error: "Approval not found" }); return; } + if (approval.companyId !== token.companyId) { this.json(res, 403, { error: "Company mismatch" }); return; } + const data = body as Record; + const taskIds = Array.isArray(data.taskIds) ? data.taskIds.filter((id): id is string => typeof id === "string") : []; + if (taskIds.length === 0) { this.json(res, 400, { error: "taskIds array is required" }); return; } + for (const taskId of taskIds) { + if (!this.db.belongsToCompany("tasks", taskId, token.companyId)) { + this.json(res, 400, { error: `Task ${taskId} does not belong to this company` }); return; + } + } + this.db.linkManyTasksToApproval(params.approvalId!, taskIds, token.companyId, token.agentId ?? null); + this.onDomainChanged(); + this.json(res, 200, { linked: taskIds.length }); + }); + + this.addRoute("GET", "/api/companies/:companyId/documents/:documentId/revisions", (_req, res, params, token) => { + if (params.companyId !== token.companyId) { this.json(res, 403, { error: "Company mismatch" }); return; } + const documentId = params.documentId; + if (!documentId) { this.json(res, 400, { error: "Missing documentId" }); return; } + const revisions = this.db.listDocumentRevisions(documentId, token.companyId); + this.json(res, 200, revisions); + }); + this.addRoute("GET", "/api/companies/:companyId/agents", (_req, res, params, token) => { if (params.companyId !== token.companyId) { this.json(res, 403, { error: "Company mismatch" }); @@ -1506,6 +1636,180 @@ export class AgentApiServer { this.json(res, 200, docs); }); + this.addRoute("PATCH", "/api/companies/:companyId/documents/:documentId", (_req, res, params, token, body) => { + if (params.companyId !== token.companyId) { + this.json(res, 403, { error: "Company mismatch" }); + return; + } + const documentId = params.documentId; + if (!documentId) { + this.json(res, 400, { error: "Missing documentId" }); + return; + } + const snapshot = this.db.listSnapshot(); + const doc = snapshot.documents.find(d => d.id === documentId && d.companyId === token.companyId); + if (!doc) { + this.json(res, 404, { error: "Document not found in this company" }); + return; + } + const data = body as Record; + const VALID_STATUSES = new Set(["draft", "in_review", "approved", "archived", "superseded"]); + + // Conflict detection: if baseRevisionId provided, verify it matches current + if (typeof data.baseRevisionId === "string") { + const currentRevId = this.db.getDocumentLatestRevisionId(documentId); + if (currentRevId && data.baseRevisionId !== currentRevId) { + this.json(res, 409, { error: "Document was updated by someone else", currentRevisionId: currentRevId }); + return; + } + } + + if (data.status !== undefined) { + const newStatus = String(data.status); + if (!VALID_STATUSES.has(newStatus)) { + this.json(res, 400, { error: `Invalid status "${newStatus}". Must be one of: ${[...VALID_STATUSES].join(", ")}` }); + return; + } + this.db.updateDocumentStatus(documentId, token.companyId, newStatus); + } + + // Content update → create revision for audit trail + if (data.content !== undefined) { + const newContent = String(data.content); + this.db.createDocumentRevision({ + documentId, + companyId: token.companyId, + body: newContent, + changeSummary: typeof data.changeSummary === "string" ? data.changeSummary : null, + createdByAgentId: token.agentId ?? null, + }); + } + + // Field updates (title, reviewer, tags, etc.) + const reviewerAgentId = data.reviewerAgentId !== undefined + ? (data.reviewerAgentId ? String(data.reviewerAgentId) : null) + : doc.reviewerAgentId; + if (data.reviewerAgentId !== undefined && reviewerAgentId && !this.db.belongsToCompany("agents", reviewerAgentId, token.companyId)) { + this.json(res, 400, { error: "Reviewer agent does not belong to the current company" }); + return; + } + this.db.saveDocument({ + id: documentId, + companyId: token.companyId, + type: data.type ? String(data.type) : doc.type, + title: data.title ? String(data.title) : doc.title, + content: data.content !== undefined ? String(data.content) : doc.content, + authorAgentId: doc.authorAgentId, + reviewerAgentId, + projectId: doc.projectId, + goalId: doc.goalId, + status: data.status ? String(data.status) : doc.status, + tagsJson: data.tagsJson ? String(data.tagsJson) : doc.tagsJson, + }); + + this.onDomainChanged(); + this.json(res, 200, { updated: true, latestRevisionId: this.db.getDocumentLatestRevisionId(documentId) }); + }); + + // ── Work Products ── + + this.addRoute("GET", "/api/issues/:issueId/work-products", (_req, res, params, token) => { + try { + const task = this.db.getTask(params.issueId!); + if (task.companyId !== token.companyId) { this.json(res, 404, { error: "Task not found" }); return; } + const products = this.db.listWorkProductsForTask(task.id, task.companyId); + this.json(res, 200, products); + } catch { this.json(res, 404, { error: "Task not found" }); } + }); + + this.addRoute("POST", "/api/issues/:issueId/work-products", (_req, res, params, token, body) => { + try { + const task = this.db.getTask(params.issueId!); + if (task.companyId !== token.companyId) { this.json(res, 404, { error: "Task not found" }); return; } + const data = body as Record; + if (!data.type || !data.provider || !data.title) { + this.json(res, 400, { error: "type, provider, and title are required" }); return; + } + const id = this.db.createWorkProduct({ + companyId: task.companyId, + taskId: task.id, + projectId: typeof data.projectId === "string" ? data.projectId : task.projectId, + type: String(data.type), + provider: String(data.provider), + externalId: typeof data.externalId === "string" ? data.externalId : null, + title: String(data.title), + url: typeof data.url === "string" ? data.url : null, + status: typeof data.status === "string" ? data.status : "active", + reviewState: typeof data.reviewState === "string" ? data.reviewState : "none", + isPrimary: data.isPrimary === true, + summary: typeof data.summary === "string" ? data.summary : null, + metadataJson: data.metadata ? JSON.stringify(data.metadata) : null, + createdByRunId: token.runId ?? null, + }); + this.onDomainChanged(); + this.json(res, 201, { id }); + } catch { this.json(res, 404, { error: "Task not found" }); } + }); + + this.addRoute("PATCH", "/api/work-products/:workProductId", (_req, res, params, token, body) => { + const wpId = params.workProductId; + if (!wpId) { this.json(res, 400, { error: "Missing workProductId" }); return; } + const data = body as Record; + this.db.updateWorkProduct(wpId, token.companyId, data); + this.onDomainChanged(); + this.json(res, 200, { updated: true }); + }); + + this.addRoute("DELETE", "/api/work-products/:workProductId", (_req, res, params, token) => { + const wpId = params.workProductId; + if (!wpId) { this.json(res, 400, { error: "Missing workProductId" }); return; } + this.db.deleteWorkProduct(wpId, token.companyId); + this.onDomainChanged(); + this.json(res, 200, { deleted: true }); + }); + + // ── Task-Document Links ── + + this.addRoute("GET", "/api/issues/:issueId/documents", (_req, res, params, token) => { + try { + const task = this.db.getTask(params.issueId!); + if (task.companyId !== token.companyId) { this.json(res, 404, { error: "Task not found" }); return; } + const links = this.db.listDocumentsForTask(task.id, task.companyId); + this.json(res, 200, links); + } catch { this.json(res, 404, { error: "Task not found" }); } + }); + + this.addRoute("PUT", "/api/issues/:issueId/documents/:key", (_req, res, params, token, body) => { + try { + const task = this.db.getTask(params.issueId!); + if (task.companyId !== token.companyId) { this.json(res, 404, { error: "Task not found" }); return; } + const key = String(params.key ?? "").trim().toLowerCase(); + if (!key || !/^[a-z0-9][a-z0-9_-]*$/.test(key) || key.length > 64) { + this.json(res, 400, { error: "Invalid document key. Must be lowercase alphanumeric with _ or -, 1-64 chars." }); return; + } + const data = body as Record; + const documentId = typeof data.documentId === "string" ? data.documentId : null; + if (!documentId) { this.json(res, 400, { error: "documentId is required" }); return; } + if (!this.db.belongsToCompany("documents", documentId, token.companyId)) { + this.json(res, 400, { error: "Document does not belong to this company" }); return; + } + const linkId = this.db.linkDocumentToTask(task.id, documentId, task.companyId, key); + this.onDomainChanged(); + this.json(res, 200, { id: linkId, key }); + } catch { this.json(res, 404, { error: "Task not found" }); } + }); + + this.addRoute("DELETE", "/api/issues/:issueId/documents/:key", (_req, res, params, token) => { + try { + const task = this.db.getTask(params.issueId!); + if (task.companyId !== token.companyId) { this.json(res, 404, { error: "Task not found" }); return; } + const key = String(params.key ?? "").trim().toLowerCase(); + this.db.unlinkDocumentFromTask(task.id, key, task.companyId); + this.onDomainChanged(); + this.json(res, 200, { unlinked: true }); + } catch { this.json(res, 404, { error: "Task not found" }); } + }); + this.addRoute("POST", "/api/companies/:companyId/meetings", (_req, res, params, token, body) => { if (params.companyId !== token.companyId) { this.json(res, 403, { error: "Company mismatch" }); @@ -1597,7 +1901,7 @@ export class AgentApiServer { // Log but skip invalid meeting action items rather than failing the whole request continue; } - const taskId = this.db.saveTask({ + this.db.saveTask({ companyId: token.companyId, title: item.title, description: item.description ?? `Action item from meeting: ${data.title ?? existing.title}`, @@ -1608,7 +1912,6 @@ export class AgentApiServer { if (item.assigneeAgentId) { this.onWakeAgent(item.assigneeAgentId, token.companyId, "assignment"); } - void taskId; } } } diff --git a/src/main/automation-service.ts b/src/main/automation-service.ts index 97a8dd19..aa4481d0 100644 --- a/src/main/automation-service.ts +++ b/src/main/automation-service.ts @@ -73,6 +73,126 @@ interface AutomationDependencies { isQuitting: () => boolean; } +const DEPARTMENT_SKILL_KEYWORDS: Record = { + engineering: ["code", "engineer", "develop", "program", "software", "api", "backend", "frontend", "full-stack", "fullstack", "devops", "infrastructure", "system", "architect", "debug", "test", "ci", "cd", "deploy", "docker", "kubernetes", "database", "sql", "git", "typescript", "javascript", "python", "rust", "go", "java", "react", "node", "css", "html", "web"], + product: ["product", "feature", "requirement", "roadmap", "user story", "ux", "ui", "design", "prototype", "wireframe", "specification", "prd"], + marketing: ["market", "content", "seo", "social media", "brand", "campaign", "analytics", "growth", "copywrite", "blog", "newsletter", "email"], + sales: ["sales", "crm", "lead", "pipeline", "deal", "revenue", "prospect", "outbound", "cold"], + hr: ["hr", "human resource", "hiring", "recruit", "onboard", "performance", "culture", "talent", "people"], + finance: ["finance", "budget", "accounting", "cost", "revenue", "profit", "spend", "invoice", "tax", "payroll"], + design: ["design", "ui", "ux", "visual", "figma", "sketch", "prototype", "illustration", "typography", "layout", "color", "icon"], + research: ["research", "analysis", "data", "study", "survey", "experiment", "insight", "benchmark", "report"], + operations: ["operations", "process", "workflow", "efficiency", "supply chain", "logistics", "coordination"], + customer_support: ["support", "customer", "ticket", "helpdesk", "troubleshoot", "faq", "documentation"], + legal: ["legal", "compliance", "contract", "regulation", "policy", "privacy", "ip", "intellectual property"], + executive: ["strategy", "leadership", "management", "executive", "ceo", "cto", "coo", "cfo", "cmo", "vp"], +}; + +function parseDocumentIdsFromPayload(payloadJson: string | null): string[] { + if (!payloadJson) return []; + try { + const parsed = JSON.parse(payloadJson) as Record; + const ids = parsed.documentIds; + if (Array.isArray(ids)) return ids.filter((id): id is string => typeof id === "string"); + } catch { /* invalid JSON */ } + return []; +} + +function scoreSkillAgentMatch( + skill: { name: string; description: string | null; markdown: string }, + agent: { role: string; department: string | null; title: string | null; capabilities: string }, +): number { + const agentText = [ + agent.role, + agent.department ?? "", + agent.title ?? "", + agent.capabilities, + ].join(" ").toLowerCase(); + + const skillText = [ + skill.name, + skill.description ?? "", + skill.markdown.slice(0, 500), + ].join(" ").toLowerCase(); + + let score = 0; + + const dept = agent.department ?? ""; + const deptKeywords = DEPARTMENT_SKILL_KEYWORDS[dept] ?? []; + for (const keyword of deptKeywords) { + if (skillText.includes(keyword)) { + score += 2; + } + } + + const agentWords = agentText + .replace(/[^a-z0-9\s-]/g, " ") + .split(/\s+/) + .filter((w) => w.length >= 3); + for (const word of agentWords) { + if (skillText.includes(word)) { + score += 1; + } + } + + // Executives need awareness of all domains + const executiveRoles = ["ceo", "cto", "coo", "cfo", "cmo", "vp", "chief", "director", "head", "lead"]; + const roleLower = agent.role.toLowerCase(); + if (executiveRoles.some((r) => roleLower.includes(r))) { + score += 1; + } + + return score; +} + +export function autoAssignSkillsToAgent( + db: AppDatabase, + logger: { info: (...args: unknown[]) => void; warn: (...args: unknown[]) => void }, + companyId: string, + agentId: string, +): number { + const agent = db.getAgent(agentId); + if (!agent || agent.companyId !== companyId) return 0; + + const allSkills = db.listCompanySkills(companyId); + if (allSkills.length === 0) return 0; + + const existingAssignments = new Set(db.listAgentSkillAssignments(agentId)); + + const scored = allSkills + .filter((skill) => !existingAssignments.has(skill.id)) + .map((skill) => ({ + skill, + score: scoreSkillAgentMatch(skill, agent), + })) + .sort((a, b) => b.score - a.score); + + const MIN_SCORE = 3; + let assigned = 0; + for (const { skill, score } of scored) { + if (score < MIN_SCORE) continue; + try { + db.assignSkillToAgent(agentId, skill.id); + assigned++; + logger.info( + `[skill-autoassign] Assigned "${skill.name}" to ${agent.name} (${agent.role}) — score ${score}`, + ); + } catch (err) { + logger.warn( + `[skill-autoassign] Failed to assign "${skill.name}" to ${agent.name}: ${err instanceof Error ? err.message : String(err)}`, + ); + } + } + + if (assigned === 0) { + logger.info( + `[skill-autoassign] No matching skills for ${agent.name} (${agent.role}); agent will run without skills until manually assigned`, + ); + } + + return assigned; +} + interface RunFinishedEvent { status: RunStatus; summary: string | null; @@ -202,10 +322,9 @@ export function createAutomationService({ } function matchesConditions( - rule: { conditionsJson: string; sourceDepartment: string | null; targetDepartment: string | null }, + rule: { conditionsJson: string; sourceDepartment: string | null }, ctx: AutomationEventContext, ) { - void rule.targetDepartment; return matchesEventConfig(rule.conditionsJson, rule.sourceDepartment, ctx); } @@ -1067,11 +1186,30 @@ export function createAutomationService({ entityId: agent.id, detail: `${agent.name} hire approved and activated.`, }); + + const skillsAssigned = autoAssignSkillsToAgent(db, logger, companyId, agent.id); + if (skillsAssigned > 0) { + db.addActivity({ + companyId, + actor: "system", + action: "skills.auto_assigned", + entityType: "agent", + entityId: agent.id, + detail: `Auto-assigned ${skillsAssigned} skill(s) to ${agent.name} based on role/department matching.`, + }); + } + dispatchAutomation("hire_approved", { companyId, agentId: agent.id, }); wakeAgentIfPossible(agent.id, companyId, "assignment"); + + const ceo = db.getCeoForCompany(companyId); + if (ceo && ceo.id !== agent.id) { + wakeAgentIfPossible(ceo.id, companyId, "assignment"); + } + publishDomainChanged(); notify({ title: "Agent Hired", @@ -1086,39 +1224,58 @@ export function createAutomationService({ } } - if (approval.type === "deliverable_review" && approval.relatedTaskId) { + if (approval.type === "deliverable_review") { try { - const task = db.getTask(approval.relatedTaskId); - // Re-enable heartbeat for the producing agent now that the user has decided - if (task.assigneeAgentId) { + // Update linked document statuses from payloadJson + const documentIds = parseDocumentIdsFromPayload(approval.payloadJson); + const docStatus = decision === "approved" ? "approved" : decision === "rejected" ? "draft" : "in_review"; + for (const docId of documentIds) { + db.updateDocumentStatus(docId, companyId, docStatus); + } + + if (approval.relatedTaskId) { + const task = db.getTask(approval.relatedTaskId); + if (task.assigneeAgentId) { + try { + const agent = db.getAgent(task.assigneeAgentId); + if (!agent.heartbeatEnabled) { + db.setHeartbeat(task.assigneeAgentId, true, agent.heartbeatIntervalSec || 120); + logger.info(`[deliverable-review] Resumed heartbeat for ${agent.name} after user ${decision}.`); + } + } catch { /* agent lookup non-fatal */ } + } + if (decision === "approved") { + db.advanceTaskStatus(task.id, "done", "Board approved deliverable."); + handleTaskStatusChange(task.id, companyId, task.status, "done"); + db.addActivity({ companyId, actor: "board", action: "deliverable.approved", entityType: "task", entityId: task.id, detail: approval.decisionNote || "Deliverable approved by board." }); + } else if (decision === "rejected") { + db.advanceTaskStatus(task.id, "in_progress", `Board rejected deliverable: ${approval.decisionNote || "No reason given."}`); + handleTaskStatusChange(task.id, companyId, task.status, "in_progress"); + if (task.assigneeAgentId) { + wakeAgentIfPossible(task.assigneeAgentId, companyId, "revision_needed"); + } + } else if (decision === "revision_requested") { + if (task.assigneeAgentId) { + wakeAgentIfPossible(task.assigneeAgentId, companyId, "revision_needed"); + } + } + } else if (approval.requestedByAgentId) { + // Document-only review (no task) — resume the producing agent try { - const agent = db.getAgent(task.assigneeAgentId); + const agent = db.getAgent(approval.requestedByAgentId); if (!agent.heartbeatEnabled) { - db.setHeartbeat(task.assigneeAgentId, true, agent.heartbeatIntervalSec || 120); + db.setHeartbeat(approval.requestedByAgentId, true, agent.heartbeatIntervalSec || 120); logger.info(`[deliverable-review] Resumed heartbeat for ${agent.name} after user ${decision}.`); } - } catch { /* best effort */ } - } - if (decision === "approved") { - db.advanceTaskStatus(task.id, "done", "Board approved deliverable."); - handleTaskStatusChange(task.id, companyId, task.status, "done"); - db.addActivity({ companyId, actor: "board", action: "deliverable.approved", entityType: "task", entityId: task.id, detail: approval.decisionNote || "Deliverable approved by board." }); - publishDomainChanged(); - } else if (decision === "rejected") { - db.advanceTaskStatus(task.id, "in_progress", `Board rejected deliverable: ${approval.decisionNote || "No reason given."}`); - handleTaskStatusChange(task.id, companyId, task.status, "in_progress"); - if (task.assigneeAgentId) { - wakeAgentIfPossible(task.assigneeAgentId, companyId, "revision_needed"); + } catch { /* agent lookup non-fatal */ } + if (decision !== "approved") { + wakeAgentIfPossible(approval.requestedByAgentId, companyId, "revision_needed"); } - publishDomainChanged(); - } else if (decision === "revision_requested") { - if (task.assigneeAgentId) { - wakeAgentIfPossible(task.assigneeAgentId, companyId, "revision_needed"); - } - publishDomainChanged(); } + + publishDomainChanged(); } catch { - // Deliverable review follow-up is best-effort. + // Deliverable review follow-up is non-fatal — approval state is already committed. } } diff --git a/src/main/bootstrap-application.ts b/src/main/bootstrap-application.ts index d9c24865..e08d3948 100644 --- a/src/main/bootstrap-application.ts +++ b/src/main/bootstrap-application.ts @@ -67,7 +67,7 @@ export async function bootstrapApplication({ }: BootstrapApplicationDependencies) { await app.whenReady(); log.initialize(); - await prepareHostEnvironment({ iconPath, logger: log }); + await prepareHostEnvironment({ logger: log }); const db = appDatabaseFactory(profileDir); db.init(); @@ -280,6 +280,43 @@ export async function bootstrapApplication({ serviceGraph.getOrchestrationService()?.resumeQueuedRuns(); + // Resume tasks that were interrupted by a clean shutdown. + // The worker-service destroy() marks running/queued runs as "interrupted" with + // summary "Application shut down." but does NOT reset the tasks, so agents + // never re-wake to continue them. Fix: reset these tasks back to "todo" and + // wake the assigned agents via heartbeat. + try { + const snapshot = db.listSnapshot(); + const shutdownRuns = snapshot.runs.filter( + (r) => r.status === "interrupted" && + (r.summary === "Application shut down." || r.summary === "Worker process crashed."), + ); + if (shutdownRuns.length > 0) { + const resumedAgents = new Set(); + for (const run of shutdownRuns) { + try { + const task = db.getTask(run.taskId); + if (task.status === "in_progress" || task.status === "blocked") { + db.advanceTaskStatus(run.taskId, "todo", "Auto-resumed after app restart."); + db.releaseTaskLock(run.taskId, run.id); + } + if (!resumedAgents.has(run.agentId)) { + resumedAgents.add(run.agentId); + wakeAgentIfPossible(run.agentId, run.companyId, "app_restart_resume"); + } + } catch { + // Task or agent may have been deleted — skip + } + } + if (resumedAgents.size > 0) { + log.info(`[bootstrap] Resumed ${shutdownRuns.length} interrupted task(s) across ${resumedAgents.size} agent(s) after clean shutdown recovery.`); + publishDomainChanged(); + } + } + } catch (err) { + log.warn(`[bootstrap] Shutdown recovery failed: ${err instanceof Error ? err.message : String(err)}`); + } + return { db, apiServer, diff --git a/src/main/browser-action-service.ts b/src/main/browser-action-service.ts index f10e3631..f2dbf402 100644 --- a/src/main/browser-action-service.ts +++ b/src/main/browser-action-service.ts @@ -29,13 +29,12 @@ export function createBrowserActionService({ throw new Error(`Browser action ${actionId} is ${action.status} and cannot be dispatched.`); } if (action.approvalId) { - const approval = (() => { - try { - return db.getApprovalRecord(action.approvalId); - } catch { - return null; - } - })(); + let approval: ReturnType | null = null; + try { + approval = db.getApprovalRecord(action.approvalId); + } catch { + // Record not found + } if (!approval || approval.companyId !== companyId) { throw new Error(`Browser action approval ${action.approvalId} does not belong to company ${companyId}.`); } diff --git a/src/main/connector-auth-service.ts b/src/main/connector-auth-service.ts index aa936869..731d4291 100644 --- a/src/main/connector-auth-service.ts +++ b/src/main/connector-auth-service.ts @@ -10,49 +10,11 @@ function escapeAppleScript(value: string) { return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"'); } -function connectorAuthSpec(connectorId: ConnectorId, command: string) { - switch (connectorId) { - case "codex_local": - return { - title: "Codex Login", - shellCommand: `${quoteShell(command)} login`, - intro: "AgentCompany is opening the Codex login flow.", - }; - case "claude_local": - return { - title: "Claude Code Login", - shellCommand: `${quoteShell(command)} auth login`, - intro: "AgentCompany is opening the Claude Code login flow.", - }; - case "gemini_local": - return { - title: "Gemini CLI Login", - shellCommand: `${quoteShell(command)}`, - intro: "AgentCompany is opening Gemini CLI. If authentication is required, use /auth in the Gemini session.", - }; - } -} - -function buildTerminalCommand(connectorId: ConnectorId, command: string, cwd: string) { - const spec = connectorAuthSpec(connectorId, command); - const shell = process.env.SHELL || "/bin/zsh"; - const script = [ - "clear", - `echo ${quoteShell(spec.intro)}`, - "echo", - `cd ${quoteShell(cwd)}`, - spec.shellCommand, - "echo", - `echo ${quoteShell("You can close this terminal after the login flow completes.")}`, - `exec ${quoteShell(shell)} -l`, - ].join("; "); - return { title: spec.title, script }; -} - -export async function openConnectorAuthTerminal(connectorId: ConnectorId, command: string, cwd?: string) { - const targetCwd = cwd || process.env.HOME || homedir() || process.cwd(); - const { script } = buildTerminalCommand(connectorId, command, targetCwd); +/* ------------------------------------------------------------------ */ +/* Shared terminal spawning — used by both auth and generic commands */ +/* ------------------------------------------------------------------ */ +function spawnTerminalWithScript(script: string, title: string, cwd: string): boolean { if (process.platform === "darwin") { const appleScript = `tell application "Terminal" to do script "${escapeAppleScript(script)}"\ntell application "Terminal" to activate`; const child = spawn("osascript", ["-e", appleScript], { @@ -64,18 +26,7 @@ export async function openConnectorAuthTerminal(connectorId: ConnectorId, comman } if (process.platform === "win32") { - const spec = connectorAuthSpec(connectorId, command); - const winScript = [ - `@echo off`, - `echo ${spec.intro}`, - `echo.`, - `cd /d "${targetCwd}"`, - spec.shellCommand, - `echo.`, - `echo You can close this terminal after the login flow completes.`, - `pause`, - ].join(" & "); - const child = spawn("cmd.exe", ["/c", "start", "", "cmd.exe", "/k", winScript], { + const child = spawn("cmd.exe", ["/c", "start", "", "cmd.exe", "/k", script], { detached: true, stdio: "ignore", shell: false, @@ -84,6 +35,7 @@ export async function openConnectorAuthTerminal(connectorId: ConnectorId, comman return true; } + // Linux — try multiple terminal emulators const linuxCandidates: Array<[string, string[]]> = [ ["x-terminal-emulator", ["-e", "sh", "-lc", script]], ["gnome-terminal", ["--", "sh", "-lc", script]], @@ -110,5 +62,101 @@ export async function openConnectorAuthTerminal(connectorId: ConnectorId, comman } } - throw new Error("No supported terminal application was found for connector login."); + throw new Error("No supported terminal application was found."); +} + +/* ------------------------------------------------------------------ */ +/* Connector auth terminal (existing API — unchanged behavior) */ +/* ------------------------------------------------------------------ */ + +function connectorAuthSpec(connectorId: ConnectorId, command: string) { + switch (connectorId) { + case "codex_local": + return { + title: "Codex Login", + shellCommand: `${quoteShell(command)} login`, + intro: "AgentCompany is opening the Codex login flow.", + }; + case "claude_local": + return { + title: "Claude Code Login", + shellCommand: `${quoteShell(command)} auth login`, + intro: "AgentCompany is opening the Claude Code login flow.", + }; + case "gemini_local": + return { + title: "Gemini CLI Login", + shellCommand: `${quoteShell(command)}`, + intro: "AgentCompany is opening Gemini CLI. If authentication is required, use /auth in the Gemini session.", + }; + } +} + +export async function openConnectorAuthTerminal(connectorId: ConnectorId, command: string, cwd?: string) { + const targetCwd = cwd || process.env.HOME || homedir() || process.cwd(); + const spec = connectorAuthSpec(connectorId, command); + + if (process.platform === "win32") { + // Windows: build a CMD-compatible script directly + const winScript = [ + `@echo off`, + `echo ${spec.intro}`, + `echo.`, + `cd /d "${targetCwd}"`, + spec.shellCommand.replace(/'/g, ""), // Remove shell quotes for CMD + `echo.`, + `echo You can close this terminal after the login flow completes.`, + `pause`, + ].join(" & "); + return spawnTerminalWithScript(winScript, spec.title, targetCwd); + } + + // Unix: build a shell script + const shell = process.env.SHELL || "/bin/zsh"; + const script = [ + "clear", + `echo ${quoteShell(spec.intro)}`, + "echo", + `cd ${quoteShell(targetCwd)}`, + spec.shellCommand, + "echo", + `echo ${quoteShell("You can close this terminal after the login flow completes.")}`, + `exec ${quoteShell(shell)} -l`, + ].join("; "); + return spawnTerminalWithScript(script, spec.title, targetCwd); +} + +/* ------------------------------------------------------------------ */ +/* Generic terminal command (for install flows, etc.) */ +/* ------------------------------------------------------------------ */ + +export async function openGenericTerminal(input: { title: string; command: string }) { + const cwd = process.env.HOME || homedir() || process.cwd(); + + if (process.platform === "win32") { + const winScript = [ + `@echo off`, + `echo AgentCompany - ${input.title}`, + `echo.`, + `cd /d "${cwd}"`, + input.command, + `echo.`, + `echo Done. You can close this terminal.`, + `pause`, + ].join(" & "); + return spawnTerminalWithScript(winScript, input.title, cwd); + } + + const shell = process.env.SHELL || "/bin/zsh"; + const script = [ + "clear", + `echo ${quoteShell(`AgentCompany — ${input.title}`)}`, + "echo", + `cd ${quoteShell(cwd)}`, + input.command, + "echo", + `echo ${quoteShell("Done. You can close this terminal.")}`, + `exec ${quoteShell(shell)} -l`, + ].join("; "); + return spawnTerminalWithScript(script, input.title, cwd); } diff --git a/src/main/connector-health-service.ts b/src/main/connector-health-service.ts index 2362e136..f24d7af6 100644 --- a/src/main/connector-health-service.ts +++ b/src/main/connector-health-service.ts @@ -103,27 +103,51 @@ export function createConnectorHealthService({ new Promise((_, reject) => setTimeout(() => reject(new Error("Connector health check timed out after 45 seconds")), 45_000)), ]); - const authRequired = result.checks.some((check) => - /auth_required|login_required/i.test(check.code) || - /login is required|authentication is not ready|auth(?:entication)? required/i.test(check.message) || - /run .*login|use \/auth|configure .*api key/i.test(check.hint ?? ""), + // Check if the CLI command itself is missing before inspecting auth status. + // Without this, info-level hints like "run `gemini auth login`" would wrongly + // trigger auth_required even when the CLI binary doesn't exist. + const commandMissing = result.checks.some((check) => + /command_unresolvable|command_not_found/i.test(check.code) && check.level === "error", + ); + + // Only consider warn/error-level checks for auth detection. + // Info-level checks (like gemini_api_key_missing) carry advisory hints + // that match auth patterns but do NOT indicate actual auth failure. + const authRequired = !commandMissing && result.checks.some((check) => + check.level !== "info" && ( + /auth_required|login_required/i.test(check.code) || + /login is required|authentication is not ready|auth(?:entication)? required/i.test(check.message) || + /run .*login|use \/auth|configure .*api key/i.test(check.hint ?? "") + ), ); let authState: "ok" | "required" | "error" = "ok"; - if (authRequired) { + if (commandMissing) { + authState = "error"; + } else if (authRequired) { authState = "required"; } else if (result.status === "fail") { authState = "error"; } - const version = await parseVersion(connector.command); + const version = commandMissing ? null : await parseVersion(connector.command); + + // claude_compatible requires explicit env bindings (API key + base URL) to be + // considered ready. Without them, it just uses the official claude CLI auth + // which is not what the user intends for a compatible provider. + const needsCompatConfig = id.startsWith("claude_compat") + && !connector.envBindingText.includes("ANTHROPIC_BASE_URL"); db.updateConnectorHealth({ id, status: - authRequired - ? "auth_required" - : result.status === "pass" || result.status === "warn" - ? "ready" - : "error", + commandMissing + ? "not_installed" + : needsCompatConfig + ? "auth_required" + : authRequired + ? "auth_required" + : result.status === "pass" || result.status === "warn" + ? "ready" + : "error", authState, version, lastError: diff --git a/src/main/connector-matching.ts b/src/main/connector-matching.ts index 016519a7..63ace854 100644 --- a/src/main/connector-matching.ts +++ b/src/main/connector-matching.ts @@ -1,20 +1,7 @@ -/** - * Deterministic connector-matching heuristic. - * - * Maps task types to the best available connector based on a static - * preference table. Provides fallback logic when preferred connectors - * are offline or unavailable. - */ import type { ConnectorId, ConnectorStatus, TaskType } from "@shared/types"; -// --------------------------------------------------------------------------- -// Types -// --------------------------------------------------------------------------- - -export interface ConnectorMatchInput { +interface ConnectorMatchInput { taskType: TaskType; - agentRole: string; - agentDepartment: string | null; availableConnectors: Array<{ id: ConnectorId; status: ConnectorStatus; @@ -22,30 +9,20 @@ export interface ConnectorMatchInput { }>; } -export interface ConnectorMatchResult { +interface ConnectorMatchResult { recommendedConnectorId: ConnectorId; fallbackConnectorId: ConnectorId | null; reason: string; } -// --------------------------------------------------------------------------- -// Static preference tables -// --------------------------------------------------------------------------- - -/** - * For each task type, connectors ordered from most preferred to least. - */ export const TASK_TYPE_PREFERENCE: Record = { - code: ["claude_local", "codex_local", "gemini_local"], - research: ["gemini_local", "claude_local", "codex_local"], - content: ["claude_local", "gemini_local", "codex_local"], - management: ["claude_local", "gemini_local", "codex_local"], - general: ["claude_local", "codex_local", "gemini_local"], + code: ["claude_local", "codex_local", "claude_compatible", "claude_compat_2", "claude_compat_3", "claude_compat_4", "claude_compat_5", "claude_compat_6", "claude_compat_7", "claude_compat_8", "claude_compat_9", "claude_compat_10", "gemini_local"], + research: ["gemini_local", "claude_local", "claude_compatible", "claude_compat_2", "claude_compat_3", "claude_compat_4", "claude_compat_5", "claude_compat_6", "claude_compat_7", "claude_compat_8", "claude_compat_9", "claude_compat_10", "codex_local"], + content: ["claude_local", "claude_compatible", "claude_compat_2", "claude_compat_3", "claude_compat_4", "claude_compat_5", "claude_compat_6", "claude_compat_7", "claude_compat_8", "claude_compat_9", "claude_compat_10", "gemini_local", "codex_local"], + management: ["claude_local", "claude_compatible", "claude_compat_2", "claude_compat_3", "claude_compat_4", "claude_compat_5", "claude_compat_6", "claude_compat_7", "claude_compat_8", "claude_compat_9", "claude_compat_10", "gemini_local", "codex_local"], + general: ["claude_local", "codex_local", "claude_compatible", "claude_compat_2", "claude_compat_3", "claude_compat_4", "claude_compat_5", "claude_compat_6", "claude_compat_7", "claude_compat_8", "claude_compat_9", "claude_compat_10", "gemini_local"], }; -/** - * Maps department strings to the most likely task type for that department. - */ export const ROLE_DEPARTMENT_HINTS: Record = { engineering: "code", research: "research", @@ -61,28 +38,37 @@ export const ROLE_DEPARTMENT_HINTS: Record = { legal: "management", }; -/** - * Human-readable capability descriptions per connector. - */ export const CONNECTOR_STRENGTHS: Record = { claude_local: "Best for code generation, content writing, complex reasoning. Supports session resume, cost tracking.", + claude_compatible: + "Claude Code CLI with third-party API provider (DeepSeek, OpenRouter, Ollama, etc.). Cost-effective for worker agents.", + claude_compat_2: + "Claude Code CLI with third-party API provider (DeepSeek, OpenRouter, Ollama, etc.). Cost-effective for worker agents.", + claude_compat_3: + "Claude Code CLI with third-party API provider (DeepSeek, OpenRouter, Ollama, etc.). Cost-effective for worker agents.", + claude_compat_4: + "Claude Code CLI with third-party API provider (DeepSeek, OpenRouter, Ollama, etc.). Cost-effective for worker agents.", + claude_compat_5: + "Claude Code CLI with third-party API provider (DeepSeek, OpenRouter, Ollama, etc.). Cost-effective for worker agents.", + claude_compat_6: + "Claude Code CLI with third-party API provider (DeepSeek, OpenRouter, Ollama, etc.). Cost-effective for worker agents.", + claude_compat_7: + "Claude Code CLI with third-party API provider (DeepSeek, OpenRouter, Ollama, etc.). Cost-effective for worker agents.", + claude_compat_8: + "Claude Code CLI with third-party API provider (DeepSeek, OpenRouter, Ollama, etc.). Cost-effective for worker agents.", + claude_compat_9: + "Claude Code CLI with third-party API provider (DeepSeek, OpenRouter, Ollama, etc.). Cost-effective for worker agents.", + claude_compat_10: + "Claude Code CLI with third-party API provider (DeepSeek, OpenRouter, Ollama, etc.). Cost-effective for worker agents.", codex_local: "Optimized for code editing and generation. Supports session resume, structured output.", gemini_local: "Strong at research, analysis, and large-context tasks. Good for data processing.", }; -// --------------------------------------------------------------------------- -// Functions -// --------------------------------------------------------------------------- - const READY_STATUSES: Set = new Set(["ready"]); -/** - * Infer the most likely task type from a department name. - * Returns 'general' for null, undefined, or unrecognised departments. - */ export function inferTaskType( department: string | null | undefined, ): TaskType { @@ -91,25 +77,10 @@ export function inferTaskType( return ROLE_DEPARTMENT_HINTS[lower] ?? "general"; } -/** - * Get a human-readable description of a connector's strengths. - */ export function getConnectorStrengths(connectorId: ConnectorId): string { return CONNECTOR_STRENGTHS[connectorId] ?? "General-purpose AI connector."; } -/** - * Select the best connector for a given task type and set of available - * connectors. Falls back gracefully when preferred connectors are offline. - * - * Algorithm: - * 1. Filter connectors to those with "ready" status. - * 2. Walk the preference list for the given task type. - * 3. Return the first ready match as recommended. - * 4. Set fallback to the next *different* ready connector in the list. - * 5. If no connectors are ready, use the first available connector. - * 6. If no connectors at all, default to 'claude_local'. - */ export function matchConnector(input: ConnectorMatchInput): ConnectorMatchResult { const { taskType, availableConnectors } = input; const prefList = TASK_TYPE_PREFERENCE[taskType] ?? TASK_TYPE_PREFERENCE.general; diff --git a/src/main/connectors.ts b/src/main/connectors.ts index 96fb5030..917abf5a 100644 --- a/src/main/connectors.ts +++ b/src/main/connectors.ts @@ -87,6 +87,256 @@ const CONNECTORS: ConnectorDefinition[] = [ }, listModels: async () => claudeModels, }, + { + id: "claude_compatible", + label: "Claude Code Compatible API", + description: "Claude Code CLI connected to a third-party API provider (e.g. DeepSeek, OpenRouter, Ollama).", + defaultCommand: "claude", + defaultModel: null, + notes: "", + capabilityMatrix: { + sessionResume: true, + gracefulCancel: true, + modelDiscovery: false, + structuredTranscript: true, + costAttribution: false, + }, + configurationDoc: claudeDoc, + module: { + type: "claude_local", + execute: claudeExecute, + testEnvironment: claudeTestEnvironment, + sessionCodec: claudeSessionCodec, + nativeContextManagement: true, + models: claudeModels, + }, + listModels: async () => claudeModels, + }, + { + id: "claude_compat_2", + label: "Claude Code Compatible API (2)", + description: "Second Claude Code CLI compatible API slot for a third-party provider.", + defaultCommand: "claude", + defaultModel: null, + notes: "", + capabilityMatrix: { + sessionResume: true, + gracefulCancel: true, + modelDiscovery: false, + structuredTranscript: true, + costAttribution: false, + }, + configurationDoc: claudeDoc, + module: { + type: "claude_local", + execute: claudeExecute, + testEnvironment: claudeTestEnvironment, + sessionCodec: claudeSessionCodec, + nativeContextManagement: true, + models: claudeModels, + }, + listModels: async () => claudeModels, + }, + { + id: "claude_compat_3", + label: "Claude Code Compatible API (3)", + description: "Third Claude Code CLI compatible API slot for a third-party provider.", + defaultCommand: "claude", + defaultModel: null, + notes: "", + capabilityMatrix: { + sessionResume: true, + gracefulCancel: true, + modelDiscovery: false, + structuredTranscript: true, + costAttribution: false, + }, + configurationDoc: claudeDoc, + module: { + type: "claude_local", + execute: claudeExecute, + testEnvironment: claudeTestEnvironment, + sessionCodec: claudeSessionCodec, + nativeContextManagement: true, + models: claudeModels, + }, + listModels: async () => claudeModels, + }, + { + id: "claude_compat_4", + label: "Claude Code Compatible API (4)", + description: "Claude Code CLI compatible API slot 4 for a third-party provider.", + defaultCommand: "claude", + defaultModel: null, + notes: "", + capabilityMatrix: { + sessionResume: true, + gracefulCancel: true, + modelDiscovery: false, + structuredTranscript: true, + costAttribution: false, + }, + configurationDoc: claudeDoc, + module: { + type: "claude_local", + execute: claudeExecute, + testEnvironment: claudeTestEnvironment, + sessionCodec: claudeSessionCodec, + nativeContextManagement: true, + models: claudeModels, + }, + listModels: async () => claudeModels, + }, + { + id: "claude_compat_5", + label: "Claude Code Compatible API (5)", + description: "Claude Code CLI compatible API slot 5 for a third-party provider.", + defaultCommand: "claude", + defaultModel: null, + notes: "", + capabilityMatrix: { + sessionResume: true, + gracefulCancel: true, + modelDiscovery: false, + structuredTranscript: true, + costAttribution: false, + }, + configurationDoc: claudeDoc, + module: { + type: "claude_local", + execute: claudeExecute, + testEnvironment: claudeTestEnvironment, + sessionCodec: claudeSessionCodec, + nativeContextManagement: true, + models: claudeModels, + }, + listModels: async () => claudeModels, + }, + { + id: "claude_compat_6", + label: "Claude Code Compatible API (6)", + description: "Claude Code CLI compatible API slot 6 for a third-party provider.", + defaultCommand: "claude", + defaultModel: null, + notes: "", + capabilityMatrix: { + sessionResume: true, + gracefulCancel: true, + modelDiscovery: false, + structuredTranscript: true, + costAttribution: false, + }, + configurationDoc: claudeDoc, + module: { + type: "claude_local", + execute: claudeExecute, + testEnvironment: claudeTestEnvironment, + sessionCodec: claudeSessionCodec, + nativeContextManagement: true, + models: claudeModels, + }, + listModels: async () => claudeModels, + }, + { + id: "claude_compat_7", + label: "Claude Code Compatible API (7)", + description: "Claude Code CLI compatible API slot 7 for a third-party provider.", + defaultCommand: "claude", + defaultModel: null, + notes: "", + capabilityMatrix: { + sessionResume: true, + gracefulCancel: true, + modelDiscovery: false, + structuredTranscript: true, + costAttribution: false, + }, + configurationDoc: claudeDoc, + module: { + type: "claude_local", + execute: claudeExecute, + testEnvironment: claudeTestEnvironment, + sessionCodec: claudeSessionCodec, + nativeContextManagement: true, + models: claudeModels, + }, + listModels: async () => claudeModels, + }, + { + id: "claude_compat_8", + label: "Claude Code Compatible API (8)", + description: "Claude Code CLI compatible API slot 8 for a third-party provider.", + defaultCommand: "claude", + defaultModel: null, + notes: "", + capabilityMatrix: { + sessionResume: true, + gracefulCancel: true, + modelDiscovery: false, + structuredTranscript: true, + costAttribution: false, + }, + configurationDoc: claudeDoc, + module: { + type: "claude_local", + execute: claudeExecute, + testEnvironment: claudeTestEnvironment, + sessionCodec: claudeSessionCodec, + nativeContextManagement: true, + models: claudeModels, + }, + listModels: async () => claudeModels, + }, + { + id: "claude_compat_9", + label: "Claude Code Compatible API (9)", + description: "Claude Code CLI compatible API slot 9 for a third-party provider.", + defaultCommand: "claude", + defaultModel: null, + notes: "", + capabilityMatrix: { + sessionResume: true, + gracefulCancel: true, + modelDiscovery: false, + structuredTranscript: true, + costAttribution: false, + }, + configurationDoc: claudeDoc, + module: { + type: "claude_local", + execute: claudeExecute, + testEnvironment: claudeTestEnvironment, + sessionCodec: claudeSessionCodec, + nativeContextManagement: true, + models: claudeModels, + }, + listModels: async () => claudeModels, + }, + { + id: "claude_compat_10", + label: "Claude Code Compatible API (10)", + description: "Claude Code CLI compatible API slot 10 for a third-party provider.", + defaultCommand: "claude", + defaultModel: null, + notes: "", + capabilityMatrix: { + sessionResume: true, + gracefulCancel: true, + modelDiscovery: false, + structuredTranscript: true, + costAttribution: false, + }, + configurationDoc: claudeDoc, + module: { + type: "claude_local", + execute: claudeExecute, + testEnvironment: claudeTestEnvironment, + sessionCodec: claudeSessionCodec, + nativeContextManagement: true, + models: claudeModels, + }, + listModels: async () => claudeModels, + }, { id: "gemini_local", label: "Gemini CLI", diff --git a/src/main/database.ts b/src/main/database.ts index 0740bd83..4e4622e8 100644 --- a/src/main/database.ts +++ b/src/main/database.ts @@ -580,9 +580,9 @@ export class AppDatabase { ...companyArgs, ), tasks: this.readAll( - `select id, company_id as companyId, project_id as projectId, goal_id as goalId, parent_id as parentId, title, description, assignee_agent_id as assigneeAgentId, workspace_id as workspaceId, status, priority, active_run_id as activeRunId, session_json as sessionJson, session_display_id as sessionDisplayId, cost_usd as costUsd, requires_user_review as requiresUserReview, created_at as createdAt, updated_at as updatedAt from tasks${companyWhere} order by created_at desc`, + `select id, company_id as companyId, project_id as projectId, goal_id as goalId, parent_id as parentId, title, description, assignee_agent_id as assigneeAgentId, workspace_id as workspaceId, status, priority, active_run_id as activeRunId, session_json as sessionJson, session_display_id as sessionDisplayId, cost_usd as costUsd, requires_user_review as requiresUserReview, started_at as startedAt, completed_at as completedAt, cancelled_at as cancelledAt, created_at as createdAt, updated_at as updatedAt from tasks${companyWhere} order by created_at desc`, ...companyArgs, - ).map((record) => ({ ...record, requiresUserReview: toBoolean(record.requiresUserReview) })) as TaskRecord[], + ).map((record) => ({ ...record, requiresUserReview: toBoolean(record.requiresUserReview), startedAt: record.startedAt ?? null, completedAt: record.completedAt ?? null, cancelledAt: record.cancelledAt ?? null })) as TaskRecord[], approvals: this.readAll( `select id, company_id as companyId, related_task_id as relatedTaskId, related_agent_id as relatedAgentId, requested_by_agent_id as requestedByAgentId, type, payload_summary as payloadSummary, impact_summary as impactSummary, payload_json as payloadJson, decision_note as decisionNote, state, created_at as createdAt, updated_at as updatedAt from approvals${companyWhere} order by created_at desc`, ...companyArgs, @@ -635,13 +635,13 @@ export class AppDatabase { actionItemsJson: r.action_items_json, status: r.status, createdAt: r.created_at, updatedAt: r.updated_at, })), documents: this.readAll( - `select id, company_id, type, title, content, author_agent_id, reviewer_agent_id, project_id, goal_id, parent_doc_id, version, status, tags_json, created_at, updated_at from documents${companyWhere} order by updated_at desc`, + `select id, company_id, type, title, content, author_agent_id, reviewer_agent_id, project_id, goal_id, parent_doc_id, version, status, tags_json, latest_revision_id, created_at, updated_at from documents${companyWhere} order by updated_at desc`, ...companyArgs, ).map((r) => ({ id: r.id, companyId: r.company_id, type: r.type, title: r.title, content: r.content, authorAgentId: r.author_agent_id, reviewerAgentId: r.reviewer_agent_id, projectId: r.project_id, goalId: r.goal_id, parentDocId: r.parent_doc_id, version: r.version, status: r.status, - tagsJson: r.tags_json, createdAt: r.created_at, updatedAt: r.updated_at, + tagsJson: r.tags_json, latestRevisionId: r.latest_revision_id ?? null, createdAt: r.created_at, updatedAt: r.updated_at, })), knowledgeBase: this.readAll( `select id, company_id, category, topic, content, author_agent_id, importance, tags_json, referenced_entity_type, referenced_entity_id, created_at, updated_at from knowledge_base${companyWhere} order by updated_at desc`, @@ -1131,11 +1131,14 @@ export class AppDatabase { getTask(id: string): TaskRecord { const row = this.db .prepare( - "select id, company_id as companyId, project_id as projectId, goal_id as goalId, parent_id as parentId, title, description, assignee_agent_id as assigneeAgentId, workspace_id as workspaceId, status, priority, active_run_id as activeRunId, session_json as sessionJson, session_display_id as sessionDisplayId, cost_usd as costUsd, requires_user_review as requiresUserReview, created_at as createdAt, updated_at as updatedAt from tasks where id = ?", + "select id, company_id as companyId, project_id as projectId, goal_id as goalId, parent_id as parentId, title, description, assignee_agent_id as assigneeAgentId, workspace_id as workspaceId, status, priority, active_run_id as activeRunId, session_json as sessionJson, session_display_id as sessionDisplayId, cost_usd as costUsd, requires_user_review as requiresUserReview, started_at as startedAt, completed_at as completedAt, cancelled_at as cancelledAt, created_at as createdAt, updated_at as updatedAt from tasks where id = ?", ) .get(id) as TaskRecord | undefined; if (!row) throw new Error(`Task not found: ${id}`); row.requiresUserReview = Boolean(row.requiresUserReview); + row.startedAt = row.startedAt ?? null; + row.completedAt = row.completedAt ?? null; + row.cancelledAt = row.cancelledAt ?? null; return row; } @@ -2124,90 +2127,62 @@ export class AppDatabase { ).map((record) => ({ ...record, heartbeatEnabled: toBoolean(record.heartbeatEnabled) })) as AgentRecord[]; } - enqueueWakeupRequest(companyId: string, agentId: string, trigger: string, detail: string): void { + enqueueWakeupRequest(companyId: string, agentId: string, trigger: string, detail: string, context?: Record): void { const ts = nowIso(); this.transaction(() => { - // D-07: Per-agent scope -- check for existing queued or deferred wake for this agent const existing = this.db .prepare( - `SELECT id, trigger_detail, coalesced_count + `SELECT id, trigger_detail, coalesced_count, context_snapshot FROM wakeup_requests WHERE agent_id = ? AND company_id = ? AND status IN ('queued', 'deferred') LIMIT 1`, ) .get(agentId, companyId) as - | { id: string; trigger_detail: string | null; coalesced_count: number } + | { id: string; trigger_detail: string | null; coalesced_count: number; context_snapshot: string | null } | undefined; if (existing) { - // D-06: Coalesce -- append trigger to JSON array const triggers: Array<{ trigger: string; at: string; detail: string }> = existing.trigger_detail ? JSON.parse(existing.trigger_detail) : []; triggers.push({ trigger, at: ts, detail }); + // Merge context snapshots (Paperclip pattern: incoming overwrites existing, preserve commentId) + let mergedContext: string | null = existing.context_snapshot; + if (context) { + const prev: Record = existing.context_snapshot ? JSON.parse(existing.context_snapshot) : {}; + const merged = { ...prev, ...context }; + mergedContext = JSON.stringify(merged); + } this.db .prepare( `UPDATE wakeup_requests SET trigger_detail = ?, coalesced_count = coalesced_count + 1, + context_snapshot = ?, updated_at = ? WHERE id = ?`, ) - .run(JSON.stringify(triggers), ts, existing.id); + .run(JSON.stringify(triggers), mergedContext, ts, existing.id); } else { - // New wakeup request const triggerDetail = JSON.stringify([{ trigger, at: ts, detail }]); + const contextJson = context ? JSON.stringify(context) : null; this.db .prepare( `INSERT INTO wakeup_requests - (id, company_id, agent_id, source, trigger_detail, status, coalesced_count, requested_at, created_at, updated_at) - VALUES (?, ?, ?, ?, ?, 'queued', 0, ?, ?, ?)`, + (id, company_id, agent_id, source, trigger_detail, status, coalesced_count, context_snapshot, requested_at, created_at, updated_at) + VALUES (?, ?, ?, ?, ?, 'queued', 0, ?, ?, ?, ?)`, ) - .run(randomUUID(), companyId, agentId, trigger, triggerDetail, ts, ts, ts); + .run(randomUUID(), companyId, agentId, trigger, triggerDetail, contextJson, ts, ts, ts); } }); } - claimWakeupRequest(agentId: string, companyId: string, runId: string): { id: string; triggerDetail: string | null } | null { - let result: { id: string; triggerDetail: string | null } | null = null; - this.transaction(() => { - const row = this.db - .prepare( - `SELECT id, trigger_detail AS triggerDetail - FROM wakeup_requests - WHERE agent_id = ? AND company_id = ? AND status = 'queued' - ORDER BY requested_at ASC - LIMIT 1`, - ) - .get(agentId, companyId) as { id: string; triggerDetail: string | null } | undefined; - if (!row) return; - const ts = nowIso(); - this.db - .prepare( - `UPDATE wakeup_requests SET status = 'claimed', claimed_at = ?, run_id = ?, updated_at = ? WHERE id = ?`, - ) - .run(ts, runId, ts, row.id); - result = row; - }); - return result; - } - - completeWakeupRequest(wakeupId: string): void { - const ts = nowIso(); - this.db - .prepare( - `UPDATE wakeup_requests SET status = 'completed', finished_at = ?, updated_at = ? WHERE id = ? AND status = 'claimed'`, - ) - .run(ts, ts, wakeupId); - } - - deferWakeupRequest(agentId: string, companyId: string): void { - const ts = nowIso(); - this.db - .prepare( - `UPDATE wakeup_requests SET status = 'deferred', updated_at = ? WHERE agent_id = ? AND company_id = ? AND status = 'queued'`, - ) - .run(ts, agentId, companyId); + private mergeContextSnapshots(existingJson: string | null, incomingJson: string | null): string | null { + if (!incomingJson) return existingJson; + if (!existingJson) return incomingJson; + const existing: Record = JSON.parse(existingJson); + const incoming: Record = JSON.parse(incomingJson); + return JSON.stringify({ ...existing, ...incoming }); } promoteWakeupRequests(agentId: string, companyId: string): number { @@ -2215,36 +2190,35 @@ export class AppDatabase { this.transaction(() => { const queued = this.db .prepare( - `SELECT id, trigger_detail FROM wakeup_requests + `SELECT id, trigger_detail, context_snapshot FROM wakeup_requests WHERE agent_id = ? AND company_id = ? AND status = 'queued' LIMIT 1`, ) - .get(agentId, companyId) as { id: string; trigger_detail: string | null } | undefined; - const deferred = this.readAll<{ id: string; trigger_detail: string | null; coalesced_count: number }>( - `SELECT id, trigger_detail, coalesced_count FROM wakeup_requests + .get(agentId, companyId) as { id: string; trigger_detail: string | null; context_snapshot: string | null } | undefined; + const deferred = this.readAll<{ id: string; trigger_detail: string | null; coalesced_count: number; context_snapshot: string | null }>( + `SELECT id, trigger_detail, coalesced_count, context_snapshot FROM wakeup_requests WHERE agent_id = ? AND company_id = ? AND status = 'deferred'`, agentId, companyId, ); if (deferred.length === 0) return; const ts = nowIso(); if (queued) { - // Merge deferred triggers into existing queued wake const queuedTriggers: Array<{ trigger: string; at: string; detail: string }> = queued.trigger_detail ? JSON.parse(queued.trigger_detail) : []; let addedCount = 0; + let mergedCtx = queued.context_snapshot; for (const d of deferred) { const dTriggers: Array<{ trigger: string; at: string; detail: string }> = d.trigger_detail ? JSON.parse(d.trigger_detail) : []; queuedTriggers.push(...dTriggers); addedCount += d.coalesced_count + 1; + mergedCtx = this.mergeContextSnapshots(mergedCtx, d.context_snapshot); } this.db.prepare( - `UPDATE wakeup_requests SET trigger_detail = ?, coalesced_count = coalesced_count + ?, updated_at = ? WHERE id = ?`, - ).run(JSON.stringify(queuedTriggers), addedCount, ts, queued.id); - // Delete the merged deferred rows + `UPDATE wakeup_requests SET trigger_detail = ?, coalesced_count = coalesced_count + ?, context_snapshot = ?, updated_at = ? WHERE id = ?`, + ).run(JSON.stringify(queuedTriggers), addedCount, mergedCtx, ts, queued.id); for (const d of deferred) { this.db.prepare("DELETE FROM wakeup_requests WHERE id = ?").run(d.id); } promoted = deferred.length; } else { - // No queued wake -- promote first deferred to queued, merge rest const [first, ...rest] = deferred; this.db.prepare( `UPDATE wakeup_requests SET status = 'queued', updated_at = ? WHERE id = ?`, @@ -2252,14 +2226,16 @@ export class AppDatabase { if (rest.length > 0) { const firstTriggers: Array<{ trigger: string; at: string; detail: string }> = first!.trigger_detail ? JSON.parse(first!.trigger_detail) : []; let addedCount = 0; + let mergedCtx = first!.context_snapshot; for (const d of rest) { const dTriggers: Array<{ trigger: string; at: string; detail: string }> = d.trigger_detail ? JSON.parse(d.trigger_detail) : []; firstTriggers.push(...dTriggers); addedCount += d.coalesced_count + 1; + mergedCtx = this.mergeContextSnapshots(mergedCtx, d.context_snapshot); } this.db.prepare( - `UPDATE wakeup_requests SET trigger_detail = ?, coalesced_count = coalesced_count + ?, updated_at = ? WHERE id = ?`, - ).run(JSON.stringify(firstTriggers), addedCount, ts, first!.id); + `UPDATE wakeup_requests SET trigger_detail = ?, coalesced_count = coalesced_count + ?, context_snapshot = ?, updated_at = ? WHERE id = ?`, + ).run(JSON.stringify(firstTriggers), addedCount, mergedCtx, ts, first!.id); for (const d of rest) { this.db.prepare("DELETE FROM wakeup_requests WHERE id = ?").run(d.id); } @@ -2597,14 +2573,6 @@ export class AppDatabase { return row ? this.mapSkillRow(row) : null; } - /** Get a single skill by canonical key within a company. */ - getCompanySkillByKey(companyId: string, key: string): SkillRecord | null { - const row = this.db - .prepare("SELECT * FROM company_skills WHERE company_id = ? AND key = ?") - .get(companyId, key) as SqliteRow | undefined; - return row ? this.mapSkillRow(row) : null; - } - /** Delete a skill record. Cascade deletes agent_skill_assignments via FK. */ deleteCompanySkill(companyId: string, skillId: string): boolean { const result = this.db @@ -2982,10 +2950,246 @@ export class AppDatabase { return id; } + updateDocumentStatus(id: string, companyId: string, status: string): void { + this.db.prepare( + "UPDATE documents SET status = ?, updated_at = ? WHERE id = ? AND company_id = ?", + ).run(status, nowIso(), id, companyId); + } + deleteDocument(id: string, companyId: string) { this.db.prepare("delete from documents where id = ? and company_id = ?").run(id, companyId); } + createDocumentRevision(input: { + documentId: string; companyId: string; body: string; + changeSummary?: string | null; createdByAgentId?: string | null; createdByUserId?: string | null; + }): { id: string; revisionNumber: number } { + const id = randomUUID(); + const ts = nowIso(); + const current = this.db.prepare( + "SELECT version FROM documents WHERE id = ? AND company_id = ?", + ).get(input.documentId, input.companyId) as { version: number } | undefined; + if (!current) throw new Error(`Document ${input.documentId} not found`); + const revisionNumber = current.version + 1; + this.db.prepare( + "INSERT INTO document_revisions (id, company_id, document_id, revision_number, body, change_summary, created_by_agent_id, created_by_user_id, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", + ).run(id, input.companyId, input.documentId, revisionNumber, input.body, input.changeSummary ?? null, input.createdByAgentId ?? null, input.createdByUserId ?? null, ts); + this.db.prepare( + "UPDATE documents SET version = ?, latest_revision_id = ?, updated_at = ? WHERE id = ?", + ).run(revisionNumber, id, ts, input.documentId); + return { id, revisionNumber }; + } + + getDocumentLatestRevisionId(documentId: string): string | null { + const row = this.db.prepare( + "SELECT latest_revision_id FROM documents WHERE id = ?", + ).get(documentId) as { latest_revision_id: string | null } | undefined; + return row?.latest_revision_id ?? null; + } + + listDocumentRevisions(documentId: string, companyId: string) { + return this.readAll<{ + id: string; company_id: string; document_id: string; revision_number: number; + body: string; change_summary: string | null; created_by_agent_id: string | null; + created_by_user_id: string | null; created_at: string; + }>( + "SELECT id, company_id, document_id, revision_number, body, change_summary, created_by_agent_id, created_by_user_id, created_at FROM document_revisions WHERE document_id = ? AND company_id = ? ORDER BY revision_number ASC", + documentId, companyId, + ).map((r) => ({ + id: r.id, companyId: r.company_id, documentId: r.document_id, + revisionNumber: r.revision_number, body: r.body, + changeSummary: r.change_summary, createdByAgentId: r.created_by_agent_id, + createdByUserId: r.created_by_user_id, createdAt: r.created_at, + })); + } + + addApprovalComment(input: { + companyId: string; approvalId: string; authorAgentId?: string | null; + authorUserId?: string | null; body: string; + }): string { + const id = randomUUID(); + const ts = nowIso(); + this.db.prepare( + "INSERT INTO approval_comments (id, company_id, approval_id, author_agent_id, author_user_id, body, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", + ).run(id, input.companyId, input.approvalId, input.authorAgentId ?? null, input.authorUserId ?? null, input.body, ts, ts); + return id; + } + + listApprovalComments(approvalId: string, companyId: string) { + return this.readAll<{ + id: string; company_id: string; approval_id: string; author_agent_id: string | null; + author_user_id: string | null; body: string; created_at: string; updated_at: string; + }>( + "SELECT id, company_id, approval_id, author_agent_id, author_user_id, body, created_at, updated_at FROM approval_comments WHERE approval_id = ? AND company_id = ? ORDER BY created_at ASC", + approvalId, companyId, + ).map((r) => ({ + id: r.id, companyId: r.company_id, approvalId: r.approval_id, + authorAgentId: r.author_agent_id, authorUserId: r.author_user_id, + body: r.body, createdAt: r.created_at, updatedAt: r.updated_at, + })); + } + + findMentionedAgentIds(companyId: string, text: string): string[] { + const mentionRe = /\B@([^\s@,!?.]+)/g; + const tokens = new Set(); + let m: RegExpExecArray | null; + while ((m = mentionRe.exec(text)) !== null) { + tokens.add(m[1]!.toLowerCase()); + } + if (tokens.size === 0) return []; + const agents = this.readAll<{ id: string; name: string }>( + "SELECT id, name FROM agents WHERE company_id = ?", companyId, + ); + const matched: string[] = []; + for (const agent of agents) { + if (tokens.has(agent.name.toLowerCase())) { + matched.push(agent.id); + } + } + return matched; + } + + resubmitApproval(approvalId: string, companyId: string): void { + const ts = nowIso(); + this.db.prepare( + "UPDATE approvals SET state = 'pending', decision_note = '', updated_at = ? WHERE id = ? AND company_id = ? AND state = 'revision_requested'", + ).run(ts, approvalId, companyId); + } + + linkTaskToApproval(taskId: string, approvalId: string, companyId: string, linkedByAgentId?: string | null): void { + this.db.prepare( + "INSERT OR IGNORE INTO task_approval_links (task_id, approval_id, company_id, linked_by_agent_id, created_at) VALUES (?, ?, ?, ?, ?)", + ).run(taskId, approvalId, companyId, linkedByAgentId ?? null, nowIso()); + } + + unlinkTaskFromApproval(taskId: string, approvalId: string): void { + this.db.prepare( + "DELETE FROM task_approval_links WHERE task_id = ? AND approval_id = ?", + ).run(taskId, approvalId); + } + + listApprovalsForTask(taskId: string): string[] { + return this.readAll<{ approval_id: string }>( + "SELECT approval_id FROM task_approval_links WHERE task_id = ?", taskId, + ).map((r) => r.approval_id); + } + + listTasksForApproval(approvalId: string): string[] { + return this.readAll<{ task_id: string }>( + "SELECT task_id FROM task_approval_links WHERE approval_id = ?", approvalId, + ).map((r) => r.task_id); + } + + linkManyTasksToApproval(approvalId: string, taskIds: string[], companyId: string, linkedByAgentId?: string | null): void { + const ts = nowIso(); + for (const taskId of taskIds) { + this.db.prepare( + "INSERT OR IGNORE INTO task_approval_links (task_id, approval_id, company_id, linked_by_agent_id, created_at) VALUES (?, ?, ?, ?, ?)", + ).run(taskId, approvalId, companyId, linkedByAgentId ?? null, ts); + } + } + + // ── Work Products ── + + createWorkProduct(input: { + companyId: string; taskId: string; projectId?: string | null; + type: string; provider: string; externalId?: string | null; + title: string; url?: string | null; status?: string; reviewState?: string; + isPrimary?: boolean; summary?: string | null; metadataJson?: string | null; + createdByRunId?: string | null; + }): string { + const id = randomUUID(); + const ts = nowIso(); + if (input.isPrimary) { + this.db.prepare( + "UPDATE work_products SET is_primary = 0, updated_at = ? WHERE company_id = ? AND task_id = ? AND type = ?", + ).run(ts, input.companyId, input.taskId, input.type); + } + this.db.prepare( + `INSERT INTO work_products (id, company_id, project_id, task_id, type, provider, external_id, title, url, status, review_state, is_primary, summary, metadata_json, created_by_run_id, created_at, updated_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, + ).run( + id, input.companyId, input.projectId ?? null, input.taskId, + input.type, input.provider, input.externalId ?? null, + input.title, input.url ?? null, input.status ?? "active", + input.reviewState ?? "none", input.isPrimary ? 1 : 0, + input.summary ?? null, input.metadataJson ?? null, + input.createdByRunId ?? null, ts, ts, + ); + return id; + } + + updateWorkProduct(id: string, companyId: string, patch: Record): void { + const ts = nowIso(); + const sets: string[] = ["updated_at = ?"]; + const values: unknown[] = [ts]; + const ALLOWED = new Set(["type", "provider", "external_id", "title", "url", "status", "review_state", "is_primary", "summary", "metadata_json"]); + for (const [key, value] of Object.entries(patch)) { + const col = key.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`); + if (ALLOWED.has(col)) { + sets.push(`${col} = ?`); + values.push(col === "is_primary" ? (value ? 1 : 0) : value ?? null); + } + } + values.push(id, companyId); + this.db.prepare(`UPDATE work_products SET ${sets.join(", ")} WHERE id = ? AND company_id = ?`).run(...values); + } + + listWorkProductsForTask(taskId: string, companyId: string) { + return this.readAll<{ + id: string; company_id: string; project_id: string | null; task_id: string; + type: string; provider: string; external_id: string | null; title: string; + url: string | null; status: string; review_state: string; is_primary: number; + summary: string | null; metadata_json: string | null; created_by_run_id: string | null; + created_at: string; updated_at: string; + }>( + "SELECT * FROM work_products WHERE task_id = ? AND company_id = ? ORDER BY is_primary DESC, updated_at DESC", + taskId, companyId, + ).map((r) => ({ + id: r.id, companyId: r.company_id, projectId: r.project_id, taskId: r.task_id, + type: r.type, provider: r.provider, externalId: r.external_id, title: r.title, + url: r.url, status: r.status, reviewState: r.review_state, + isPrimary: Boolean(r.is_primary), summary: r.summary, + metadataJson: r.metadata_json, createdByRunId: r.created_by_run_id, + createdAt: r.created_at, updatedAt: r.updated_at, + })); + } + + deleteWorkProduct(id: string, companyId: string): void { + this.db.prepare("DELETE FROM work_products WHERE id = ? AND company_id = ?").run(id, companyId); + } + + // ── Task-Document Links ── + + linkDocumentToTask(taskId: string, documentId: string, companyId: string, key: string): string { + const id = randomUUID(); + const ts = nowIso(); + this.db.prepare( + "INSERT OR REPLACE INTO task_documents (id, company_id, task_id, document_id, key, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)", + ).run(id, companyId, taskId, documentId, key.toLowerCase(), ts, ts); + return id; + } + + unlinkDocumentFromTask(taskId: string, key: string, companyId: string): void { + this.db.prepare( + "DELETE FROM task_documents WHERE task_id = ? AND key = ? AND company_id = ?", + ).run(taskId, key.toLowerCase(), companyId); + } + + listDocumentsForTask(taskId: string, companyId: string) { + return this.readAll<{ + id: string; company_id: string; task_id: string; document_id: string; + key: string; created_at: string; updated_at: string; + }>( + "SELECT * FROM task_documents WHERE task_id = ? AND company_id = ? ORDER BY key ASC", + taskId, companyId, + ).map((r) => ({ + id: r.id, companyId: r.company_id, taskId: r.task_id, + documentId: r.document_id, key: r.key, + createdAt: r.created_at, updatedAt: r.updated_at, + })); + } + saveKnowledgeEntry(input: { id?: string | null; companyId: string; category: string; topic: string; content: string; authorAgentId?: string | null; importance?: string; tagsJson?: string; @@ -3319,13 +3523,45 @@ export class AppDatabase { ); } + private static readonly VALID_TASK_STATUSES = new Set(["backlog", "todo", "in_progress", "in_review", "done", "blocked", "cancelled"]); + advanceTaskStatus(taskId: string, newStatus: string, comment?: string): { previousStatus: string } { + if (!AppDatabase.VALID_TASK_STATUSES.has(newStatus)) { + throw new Error(`Invalid task status: ${newStatus}`); + } const task = this.db.prepare("select status, company_id from tasks where id = ?").get(taskId) as { status: string; company_id: string } | undefined; if (!task) throw new Error(`Task not found: ${taskId}`); const previousStatus = task.status; if (previousStatus === newStatus) return { previousStatus }; const ts = nowIso(); - this.db.prepare("update tasks set status = ?, updated_at = ? where id = ?").run(newStatus, ts, taskId); + + // Status side-effect timestamps (Paperclip pattern) + const timestampSets: string[] = ["status = ?", "updated_at = ?"]; + const timestampValues: (string | null)[] = [newStatus, ts]; + + if (newStatus === "in_progress") { + // Set startedAt only once (first time entering in_progress) + timestampSets.push("started_at = COALESCE(started_at, ?)"); + timestampValues.push(ts); + } + if (newStatus === "done") { + timestampSets.push("completed_at = ?"); + timestampValues.push(ts); + } else { + timestampSets.push("completed_at = NULL"); + } + if (newStatus === "cancelled") { + timestampSets.push("cancelled_at = ?"); + timestampValues.push(ts); + } else { + timestampSets.push("cancelled_at = NULL"); + } + if (newStatus !== "in_progress") { + timestampSets.push("checkout_run_id = NULL"); + } + + this.db.prepare(`UPDATE tasks SET ${timestampSets.join(", ")} WHERE id = ?`).run(...timestampValues, taskId); + if (comment) { this.addComment({ companyId: task.company_id, @@ -3335,11 +3571,9 @@ export class AppDatabase { body: comment, }); } - // Track sprint velocity: increment completed_points when task moves to "done" if (newStatus === "done" && previousStatus !== "done") { this.incrementActiveSprintVelocity(task.company_id, 1); } - // Decrement if task moves back from done if (previousStatus === "done" && newStatus !== "done") { this.incrementActiveSprintVelocity(task.company_id, -1); } @@ -3405,17 +3639,6 @@ export class AppDatabase { return manager ? { ...manager, companyId: agent.company_id } : null; } - activateWorkflow(id: string, companyId: string) { - const row = this.db.prepare("select name, status from workflow_pipelines where id = ? and company_id = ?").get(id, companyId) as { name: string; status: string } | undefined; - if (!row) throw new Error(`Workflow not found: ${id}`); - if (row.status === "active") throw new Error("Workflow is already running."); - const ts = nowIso(); - this.db.prepare( - "update workflow_pipelines set status = 'active', current_step_index = 0, run_count = run_count + 1, last_run_at = ?, updated_at = ? where id = ?", - ).run(ts, ts, id); - this.addActivity({ companyId, actor: "system", action: "started", entityType: "workflow", entityId: id, detail: `Started workflow: ${row.name}` }); - } - listTriggerableWorkflows(companyId: string, triggerType: string): WorkflowPipelineRecord[] { return this.readAll( "select id, company_id as companyId, name, description, steps_json as stepsJson, trigger_type as triggerType, trigger_config_json as triggerConfigJson, status, current_step_index as currentStepIndex, run_count as runCount, last_run_at as lastRunAt, created_at as createdAt, updated_at as updatedAt from workflow_pipelines where company_id = ? and trigger_type = ? and status = 'active' order by created_at asc", @@ -3987,6 +4210,123 @@ export class AppDatabase { log.info(`Budget migration: converted ${agents.length} agent budget(s) to policy rows`); }, }, + { + version: 19, + name: "add_document_revisions_and_approval_comments", + fn: () => { + this.db.exec(` + CREATE TABLE IF NOT EXISTS document_revisions ( + id TEXT PRIMARY KEY, + company_id TEXT NOT NULL, + document_id TEXT NOT NULL, + revision_number INTEGER NOT NULL, + body TEXT NOT NULL, + change_summary TEXT, + created_by_agent_id TEXT, + created_by_user_id TEXT, + created_at TEXT NOT NULL, + FOREIGN KEY (document_id) REFERENCES documents(id) ON DELETE CASCADE + ); + CREATE UNIQUE INDEX IF NOT EXISTS idx_doc_rev_doc_num ON document_revisions(document_id, revision_number); + CREATE INDEX IF NOT EXISTS idx_doc_rev_company ON document_revisions(company_id, document_id, created_at); + + CREATE TABLE IF NOT EXISTS approval_comments ( + id TEXT PRIMARY KEY, + company_id TEXT NOT NULL, + approval_id TEXT NOT NULL, + author_agent_id TEXT, + author_user_id TEXT, + body TEXT NOT NULL, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + FOREIGN KEY (approval_id) REFERENCES approvals(id) ON DELETE CASCADE + ); + CREATE INDEX IF NOT EXISTS idx_approval_comments_approval ON approval_comments(approval_id, created_at); + `); + // Add latest_revision_id to documents (may already exist via ensureOptionalColumns) + try { this.db.prepare("ALTER TABLE documents ADD COLUMN latest_revision_id TEXT").run(); } catch { /* column already exists */ } + }, + }, + { + version: 20, + name: "add_task_timestamps_and_task_approval_links", + fn: () => { + const addCol = (sql: string) => { try { this.db.prepare(sql).run(); } catch { /* already exists */ } }; + addCol("ALTER TABLE tasks ADD COLUMN started_at TEXT"); + addCol("ALTER TABLE tasks ADD COLUMN completed_at TEXT"); + addCol("ALTER TABLE tasks ADD COLUMN cancelled_at TEXT"); + this.db.exec(` + CREATE TABLE IF NOT EXISTS task_approval_links ( + task_id TEXT NOT NULL, + approval_id TEXT NOT NULL, + company_id TEXT NOT NULL, + linked_by_agent_id TEXT, + created_at TEXT NOT NULL, + PRIMARY KEY (task_id, approval_id), + FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE, + FOREIGN KEY (approval_id) REFERENCES approvals(id) ON DELETE CASCADE + ); + CREATE INDEX IF NOT EXISTS idx_task_approval_links_task ON task_approval_links(task_id); + CREATE INDEX IF NOT EXISTS idx_task_approval_links_approval ON task_approval_links(approval_id); + `); + // Backfill: set started_at for tasks already in_progress/in_review/done + this.db.prepare( + "UPDATE tasks SET started_at = updated_at WHERE started_at IS NULL AND status IN ('in_progress', 'in_review', 'done')", + ).run(); + this.db.prepare( + "UPDATE tasks SET completed_at = updated_at WHERE completed_at IS NULL AND status = 'done'", + ).run(); + this.db.prepare( + "UPDATE tasks SET cancelled_at = updated_at WHERE cancelled_at IS NULL AND status = 'cancelled'", + ).run(); + }, + }, + { + version: 21, + name: "add_work_products_task_documents_wakeup_context", + fn: () => { + this.db.exec(` + CREATE TABLE IF NOT EXISTS work_products ( + id TEXT PRIMARY KEY, + company_id TEXT NOT NULL, + project_id TEXT, + task_id TEXT NOT NULL, + type TEXT NOT NULL, + provider TEXT NOT NULL, + external_id TEXT, + title TEXT NOT NULL, + url TEXT, + status TEXT NOT NULL DEFAULT 'active', + review_state TEXT NOT NULL DEFAULT 'none', + is_primary INTEGER NOT NULL DEFAULT 0, + summary TEXT, + metadata_json TEXT, + created_by_run_id TEXT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE + ); + CREATE INDEX IF NOT EXISTS idx_work_products_task ON work_products(company_id, task_id, type); + CREATE INDEX IF NOT EXISTS idx_work_products_updated ON work_products(company_id, updated_at); + + CREATE TABLE IF NOT EXISTS task_documents ( + id TEXT PRIMARY KEY, + company_id TEXT NOT NULL, + task_id TEXT NOT NULL, + document_id TEXT NOT NULL, + key TEXT NOT NULL, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE, + FOREIGN KEY (document_id) REFERENCES documents(id) ON DELETE CASCADE + ); + CREATE UNIQUE INDEX IF NOT EXISTS idx_task_documents_task_key ON task_documents(company_id, task_id, key); + CREATE UNIQUE INDEX IF NOT EXISTS idx_task_documents_doc ON task_documents(document_id); + `); + // Add context_snapshot column to wakeup_requests for rich context merging + try { this.db.prepare("ALTER TABLE wakeup_requests ADD COLUMN context_snapshot TEXT").run(); } catch { /* already exists */ } + }, + }, ]; for (const migration of migrations) { diff --git a/src/main/desktop-shell-service.ts b/src/main/desktop-shell-service.ts index 307d855a..a8564a94 100644 --- a/src/main/desktop-shell-service.ts +++ b/src/main/desktop-shell-service.ts @@ -6,6 +6,7 @@ import { app, BrowserWindow, dialog, + ipcMain, Menu, nativeImage, nativeTheme, @@ -153,7 +154,13 @@ export function createDesktopShellService({ callback(false); }); app.on("web-contents-created", (_event, contents) => { - contents.setWindowOpenHandler(() => ({ action: "deny" })); + contents.setWindowOpenHandler(({ url }) => { + // Allow external https URLs to open in the user's default browser + if (url.startsWith("https://") || url.startsWith("http://")) { + shell.openExternal(url); + } + return { action: "deny" }; + }); contents.on("will-attach-webview", (event) => { event.preventDefault(); }); @@ -198,6 +205,8 @@ export function createDesktopShellService({ async function createWindow() { const windowIcon = nativeImage.createFromPath(iconPath); const savedWindowState = loadWindowState(windowStatePath); + const isWindows = process.platform === "win32"; + const isLinux = process.platform === "linux"; mainWindow = new BrowserWindow({ title: "AgentCompany", icon: windowIcon.isEmpty() ? undefined : windowIcon, @@ -208,7 +217,9 @@ export function createDesktopShellService({ minWidth: 1180, minHeight: 760, backgroundColor: "#ffffff", + frame: process.platform === "darwin", titleBarStyle: process.platform === "darwin" ? "hiddenInset" : "default", + ...(isWindows || isLinux ? { titleBarOverlay: false } : {}), webPreferences: { preload: preloadPath, contextIsolation: true, @@ -367,7 +378,15 @@ export function createDesktopShellService({ ], }, ]; - Menu.setApplicationMenu(Menu.buildFromTemplate(template)); + const menu = Menu.buildFromTemplate(template); + if (process.platform === "darwin") { + Menu.setApplicationMenu(menu); + } else { + // Frameless windows: hide native menu bar but keep keyboard accelerators active + Menu.setApplicationMenu(menu); + mainWindow?.setMenuBarVisibility(false); + mainWindow?.setAutoHideMenuBar(true); + } } function createTray() { @@ -456,6 +475,18 @@ export function createDesktopShellService({ registerProtocol(); buildMenu(); createTray(); + + // Window control IPC for custom title bar (Windows/Linux frameless windows) + ipcMain.handle("window:minimize", () => { mainWindow?.minimize(); }); + ipcMain.handle("window:maximize", () => { + if (mainWindow?.isMaximized()) { + mainWindow.unmaximize(); + } else { + mainWindow?.maximize(); + } + }); + ipcMain.handle("window:close", () => { mainWindow?.close(); }); + ipcMain.handle("window:isMaximized", () => mainWindow?.isMaximized() ?? false); } return { diff --git a/src/main/host-environment-service.ts b/src/main/host-environment-service.ts index 2e15e998..5cf9192b 100644 --- a/src/main/host-environment-service.ts +++ b/src/main/host-environment-service.ts @@ -5,7 +5,6 @@ import { delimiter as pathDelimiter, join } from "node:path"; import { app } from "electron"; interface HostEnvironmentDependencies { - iconPath: string; logger: { info: (...args: unknown[]) => void; }; @@ -53,7 +52,6 @@ function enrichWindowsPath(logger: HostEnvironmentDependencies["logger"]) { } export async function prepareHostEnvironment({ - iconPath, logger, }: HostEnvironmentDependencies) { if (process.platform === "win32") { diff --git a/src/main/ipc-core-admin-handlers.ts b/src/main/ipc-core-admin-handlers.ts index 3bf9bdb0..47553893 100644 --- a/src/main/ipc-core-admin-handlers.ts +++ b/src/main/ipc-core-admin-handlers.ts @@ -1,8 +1,10 @@ +import { execSync } from "node:child_process"; import { IPC_CHANNELS, companyInputSchema, connectorInputSchema, deleteEntitySchema, + openTerminalCommandSchema, secretInputSchema, } from "@shared/contracts"; import { fail, ok, type RegisterCoreHandlersDependencies } from "./ipc-core-common"; @@ -14,9 +16,10 @@ export function registerCoreAdminHandlers({ publishDomainChanged, checkConnector, openConnectorAuthTerminal, + openGenericTerminal, }: Pick< RegisterCoreHandlersDependencies, - "registerHandle" | "db" | "ensureCompanyExists" | "publishDomainChanged" | "checkConnector" | "openConnectorAuthTerminal" + "registerHandle" | "db" | "ensureCompanyExists" | "publishDomainChanged" | "checkConnector" | "openConnectorAuthTerminal" | "openGenericTerminal" >) { registerHandle(IPC_CHANNELS.saveCompany, async (_event, payload) => { const parsed = companyInputSchema.parse(payload); @@ -80,6 +83,21 @@ export function registerCoreAdminHandlers({ return ok(true); }); + registerHandle(IPC_CHANNELS.checkNodeInstalled, async () => { + try { + const raw = execSync("node --version", { encoding: "utf8", timeout: 10000 }).trim(); + return ok({ installed: true, version: raw || null }); + } catch { + return ok({ installed: false, version: null }); + } + }); + + registerHandle(IPC_CHANNELS.openTerminalCommand, async (_event, payload) => { + const parsed = openTerminalCommandSchema.parse(payload); + await openGenericTerminal(parsed); + return ok(true); + }); + registerHandle(IPC_CHANNELS.saveSecret, async (_event, payload) => { const parsed = secretInputSchema.parse(payload); const companyError = ensureCompanyExists(parsed.companyId); diff --git a/src/main/ipc-core-common.ts b/src/main/ipc-core-common.ts index 75db01f8..e98f1da3 100644 --- a/src/main/ipc-core-common.ts +++ b/src/main/ipc-core-common.ts @@ -1,9 +1,9 @@ import type { IpcMainInvokeEvent } from "electron"; import type { DesktopResult } from "@shared/contracts"; -import type { SectionId } from "@shared/types"; +import type { DesktopEvent, SectionId } from "@shared/types"; import type { AppDatabase } from "./database"; -export type CompanyScopedTable = "workspaces" | "agents" | "goals" | "projects" | "tasks" | "approvals" | "runs" | "secrets"; +type CompanyScopedTable = "workspaces" | "agents" | "goals" | "projects" | "tasks" | "approvals" | "runs" | "secrets"; export interface RegisterCoreHandlersDependencies { registerHandle: ( @@ -17,7 +17,7 @@ export interface RegisterCoreHandlersDependencies { refs: Array<{ id: string | null | undefined; table: CompanyScopedTable; label: string }>, ) => { id: string | null | undefined; table: CompanyScopedTable; label: string } | null; publishDomainChanged: () => void; - emitEvent: (event: any) => void; + emitEvent: (event: DesktopEvent) => void; wakeAgentIfPossible: (agentId: string | null | undefined, companyId: string, trigger: string) => string | null; handleTaskCreated: (taskId: string, companyId: string) => void; handleTaskStatusChange: (taskId: string, companyId: string, previousStatus: string, newStatus: string) => void; @@ -26,6 +26,7 @@ export interface RegisterCoreHandlersDependencies { queueTaskRun: (taskId: string, trigger: string, actor: string) => DesktopResult; checkConnector: (id: any) => Promise; openConnectorAuthTerminal: (id: any) => Promise; + openGenericTerminal: (input: { title: string; command: string }) => Promise; checkForUpdates: () => Promise; getWorkerProcess: () => { postMessage: (message: unknown) => void } | null; resetAfterRestore: () => void; diff --git a/src/main/ipc-domain-common.ts b/src/main/ipc-domain-common.ts index ca4f8ee0..76ee1efb 100644 --- a/src/main/ipc-domain-common.ts +++ b/src/main/ipc-domain-common.ts @@ -2,11 +2,12 @@ import type { IpcMainInvokeEvent } from "electron"; import { z } from "zod"; import type { DesktopResult } from "@shared/contracts"; import type { bootstrapOnboardingSchema } from "@shared/contracts"; +import type { DesktopEvent } from "@shared/types"; import type { AppDatabase } from "./database"; import type { createSkillService } from "./skill-service"; import type { createBudgetEnforcementService } from "./budget-enforcement-service"; -export interface BrowserActionControl { +interface BrowserActionControl { clearSocialAccountData: (socialAccountId: string, screenshotPaths?: string[]) => Promise; cancelAction: (actionId: string) => boolean; launchLoginBrowser: (socialAccountId: string, platform: string, loginUrl?: string) => Promise<{ @@ -33,7 +34,7 @@ export interface RegisterDomainHandlersDependencies { refs: Array<{ id: string | null | undefined; table: string; label: string }>, ) => { id: string | null | undefined; table: string; label: string } | null; publishDomainChanged: () => void; - emitEvent: (event: any) => void; + emitEvent: (event: DesktopEvent) => void; wakeAgentIfPossible: (agentId: string | null | undefined, companyId: string, trigger: string) => string | null; dispatchAutomation: (trigger: string, ctx: { companyId: string; [key: string]: unknown }) => void; runWorkflowPipeline: (workflowId: string, companyId: string) => Promise; diff --git a/src/main/main-runtime-support.ts b/src/main/main-runtime-support.ts index fc030b72..84f7de29 100644 --- a/src/main/main-runtime-support.ts +++ b/src/main/main-runtime-support.ts @@ -2,7 +2,7 @@ import log from "electron-log/main.js"; import type { AgentApiServer } from "./api-server"; import { initializeAgentTokenSigningKey } from "./agent-auth"; import { bootstrapApplication } from "./bootstrap-application"; -import { openConnectorAuthTerminal as openConnectorAuthTerminalImpl } from "./connector-auth-service"; +import { openConnectorAuthTerminal as openConnectorAuthTerminalImpl, openGenericTerminal as openGenericTerminalImpl } from "./connector-auth-service"; import { getConnectorDefinition } from "./connectors"; import type { AppDatabase } from "./database"; import { seedDefaultAutomationRules as seedDefaultAutomationRulesImpl } from "./default-automation-rules"; @@ -138,6 +138,7 @@ export function createMainRuntimeSupport(state: MainRuntimeState) { const connector = requireDb().getConnector(id); return openConnectorAuthTerminalImpl(id, connector.command); }, + openGenericTerminal: (input) => openGenericTerminalImpl(input), checkForUpdates: () => requireUpdaterService().checkForUpdates(), getWorkerProcess: () => requireServiceGraph().getWorkerService()?.getWorker() ?? null, resetAfterRestore: () => { @@ -147,6 +148,13 @@ export function createMainRuntimeSupport(state: MainRuntimeState) { getApiPort: () => state.apiServer?.getPort() ?? 0, notify: (options) => requireIpcSupport().notify(options), listConnectorModels: async (connectorId) => { + // For claude_compatible, return user-configured models from the DB + // (stored as comma-separated values in the connector's model field) + if (connectorId.startsWith("claude_compat")) { + const connector = requireDb().getConnector(connectorId); + const raw = connector.model ?? ""; + return raw.split(",").map((m) => m.trim()).filter(Boolean).map((m) => ({ id: m, label: m })); + } const definition = getConnectorDefinition(connectorId as Parameters[0]); return definition.listModels ? definition.listModels() : []; }, diff --git a/src/main/onboarding-service.ts b/src/main/onboarding-service.ts index c4ede7f4..ba4e10f9 100644 --- a/src/main/onboarding-service.ts +++ b/src/main/onboarding-service.ts @@ -21,6 +21,7 @@ interface BootstrapInput { goalTitle: string; goalDescription: string; connectorId?: ConnectorId; + connectorModel?: string; } interface OnboardingDependencies { @@ -32,6 +33,8 @@ interface OnboardingDependencies { error?: { code: string; message: string }; }; publishDomainChanged: () => void; + /** Scan workspace directories for skills and import them. Best-effort — may be undefined during early init. */ + scanAndAssignSkills?: (companyId: string, agentId: string) => Promise; } const DEFERRABLE_RUN_ERRORS = new Set([ @@ -69,6 +72,7 @@ export function createOnboardingService({ seedDefaultAutomationRules, queueTaskRun, publishDomainChanged, + scanAndAssignSkills, }: OnboardingDependencies) { function updateAgentWorkspaceBinding(agentId: string, workspaceId: string | null) { if (!workspaceId) return; @@ -217,7 +221,7 @@ export function createOnboardingService({ reportsTo: null, connectorId: selectedConnectorId, workspaceId, - model: null, + model: input.connectorModel?.trim() || null, capabilities: "Executive leadership, strategic planning, team building, goal decomposition, delegation, and organizational management. Responsible for hiring the leadership team, setting strategy, and coordinating all company operations.", budgetMonthlyUsd: 250, @@ -227,6 +231,10 @@ export function createOnboardingService({ db.setCurrentCompany(companyId); seedDefaultAutomationRules(companyId); + if (scanAndAssignSkills) { + void scanAndAssignSkills(companyId, ceoId).catch(() => {}); + } + const kickoff = createInitialExecutionLoop(companyId, workspaceId); db.addActivity({ diff --git a/src/main/orchestration-service.ts b/src/main/orchestration-service.ts index 57502602..82d3c2b8 100644 --- a/src/main/orchestration-service.ts +++ b/src/main/orchestration-service.ts @@ -68,9 +68,13 @@ interface OrchestrationDependencies { hasWorkerReady: () => boolean; enqueueWorkerRun: (payload: EnqueueRunPayload) => void; isQuitting: () => boolean; - listRuntimeSkillEntries: (companyId: string, agentId: string, connectorId: string) => Array<{ runtimeName: string; sourcePath: string }>; + listRuntimeSkillEntries: (companyId: string, agentId: string, connectorId: string) => Array<{ runtimeName: string; sourcePath: string; name?: string }>; budgetService: ReturnType; getSessionHandoff?: (taskId: string) => string | null; + evaluatePreRunSessionRotation?: (taskId: string, connectorId: string) => { + rotated: boolean; + handoff: string | null; + }; } export function createOrchestrationService({ @@ -88,6 +92,7 @@ export function createOrchestrationService({ listRuntimeSkillEntries, budgetService, getSessionHandoff, + evaluatePreRunSessionRotation, }: OrchestrationDependencies) { let heartbeatTimer: ReturnType | null = null; const scheduleLastFiredMap = new Map(); @@ -132,31 +137,6 @@ export function createOrchestrationService({ return { workspace: null, lockMode: "none", source: "none" }; } - // DEPRECATED: Superseded by BudgetEnforcementService.evaluateBudgetGate (Phase 5) - function autoPauseBudgetExceededAgent(agent: { id: string; companyId: string; name: string; spentMonthlyUsd: number; budgetMonthlyUsd: number }) { - if (!(agent.budgetMonthlyUsd > 0) || agent.spentMonthlyUsd < agent.budgetMonthlyUsd) { - return false; - } - db.updateAgentStatus(agent.id, "paused"); - db.addActivity({ - companyId: agent.companyId, - actor: "system", - action: "agent.auto_paused", - entityType: "agent", - entityId: agent.id, - detail: `Budget exhausted at ${agent.spentMonthlyUsd.toFixed(2)} / ${agent.budgetMonthlyUsd.toFixed(2)} USD.`, - }); - notify({ - title: "Agent Paused", - body: `${agent.name} paused -- budget limit reached`, - urgency: "informational", - navigation: { section: "agents", entityId: agent.id }, - batchKey: "agent_paused", - }); - emitEvent({ type: "agent-updated", agentId: agent.id, action: "paused" }); - return true; - } - function ensureAgentHeartbeatEnabled(agentId: string) { const agent = db.getAgent(agentId); if (!agent.heartbeatEnabled) { @@ -246,6 +226,16 @@ export function createOrchestrationService({ } } + let managedSkills: Array<{ runtimeName: string; sourcePath: string; name?: string }> = []; + try { + managedSkills = listRuntimeSkillEntries(companyId, agent.id, connector.id); + } catch (err) { + logger.warn(`[run] Failed to fetch managed skills for agent ${agent.name}: ${err instanceof Error ? err.message : String(err)}`); + } + const skillNames = managedSkills + .map((s) => s.name ?? s.runtimeName) + .filter(Boolean); + const systemPrompt = apiUrl ? buildTaskPrompt({ agent, apiUrl, @@ -298,6 +288,7 @@ export function createOrchestrationService({ .slice(0, 5), allConnectors: snapshot.connectors.map((c) => ({ id: c.id, label: c.label, status: c.status })), sessionHandoff, + skillNames, }) : null; if (apiUrl) { @@ -312,12 +303,27 @@ export function createOrchestrationService({ // SESS-01: Prefer task_sessions table, fall back to legacy tasks.session_json const activeSession = db.getActiveTaskSession(task.id); - const taskSession = activeSession + let taskSession = activeSession ? { sessionParams: activeSession.sessionParamsJson ? JSON.parse(activeSession.sessionParamsJson) as Record : null, sessionDisplayId: activeSession.sessionDisplayId, } : db.getTaskSession(task.id); + + // Pre-execution session compaction (Paperclip pattern): evaluate BEFORE run starts + if (evaluatePreRunSessionRotation && activeSession) { + const rotationResult = evaluatePreRunSessionRotation(task.id, connector.id); + if (rotationResult.rotated) { + // Session was rotated: clear session params so adapter starts fresh + taskSession = { sessionParams: null, sessionDisplayId: null }; + // Handoff will be picked up by getSessionHandoff() above (already loaded from rotated session) + if (!sessionHandoff && rotationResult.handoff) { + sessionHandoff = rotationResult.handoff; + } + logger.info(`[session] Pre-run compaction for task ${task.id}: session rotated before execution`); + } + } + let thinkingEffort: string | null = null; try { const meta = JSON.parse(agent.metadataJson || "{}"); @@ -328,14 +334,6 @@ export function createOrchestrationService({ thinkingEffort = null; } - // Fetch managed skills for this agent -- best-effort, never blocks run dispatch - let managedSkills: Array<{ runtimeName: string; sourcePath: string }> = []; - try { - managedSkills = listRuntimeSkillEntries(companyId, agent.id, connector.id); - } catch (err) { - logger.warn(`[run] Failed to fetch managed skills for agent ${agent.name}: ${err instanceof Error ? err.message : String(err)}`); - } - enqueueWorkerRun({ runId, companyId, @@ -521,7 +519,7 @@ export function createOrchestrationService({ return run.id; } - function wakeAgentIfPossible(agentId: string | null | undefined, companyId: string, trigger: string) { + function wakeAgentIfPossible(agentId: string | null | undefined, companyId: string, trigger: string, context?: Record) { if (!agentId || isQuitting()) return null; try { const agent = db.getAgent(agentId); @@ -540,15 +538,13 @@ export function createOrchestrationService({ const agentBusy = hasActiveRun({ agentId, companyId }); if (agentBusy) { - // Agent is busy — enqueue wakeup with lifecycle tracking (D-05) - db.enqueueWakeupRequest(companyId, agentId, trigger, `Wake for agent: ${trigger}`); + db.enqueueWakeupRequest(companyId, agentId, trigger, `Wake for agent: ${trigger}`, context); return null; } const runId = startAgentHeartbeatRun(agentId, companyId, trigger); if (!runId) { - // Run failed to start but agent not busy — still enqueue for retry - db.enqueueWakeupRequest(companyId, agentId, trigger, `Wake for agent (deferred): ${trigger}`); + db.enqueueWakeupRequest(companyId, agentId, trigger, `Wake for agent (deferred): ${trigger}`, context); } return runId; } @@ -877,7 +873,6 @@ export function createOrchestrationService({ return { resolveWorkspace, - autoPauseBudgetExceededAgent, wakeAgentIfPossible, dispatchRunToWorker, queueTaskRun, diff --git a/src/main/orchestrator/worker.ts b/src/main/orchestrator/worker.ts index e20ff545..d66d0f6b 100644 --- a/src/main/orchestrator/worker.ts +++ b/src/main/orchestrator/worker.ts @@ -1,4 +1,4 @@ -import { runningProcesses } from "@agentcompany/adapter-utils/server-utils"; +import { runningProcesses, shutdownAllRunning } from "@agentcompany/adapter-utils/server-utils"; import { getConnectorDefinition } from "@main/connectors"; import { buildSanitizedRuntimeEnv } from "@main/runtime-env"; import type { ConnectorId, RunStatus } from "@shared/types"; @@ -47,7 +47,8 @@ interface RunJob { type ParentMessage = | { type: "enqueue-run"; payload: RunJob } - | { type: "cancel-run"; runId: string }; + | { type: "cancel-run"; runId: string } + | { type: "shutdown" }; type ChildMessage = | { type: "run-log"; runId: string; stream: "stdout" | "stderr"; chunk: string } @@ -114,6 +115,16 @@ function buildConnectorExecutionConfig(job: RunJob, sanitizedEnv: Record { } if (message.type === "cancel-run") { cancelRun(message.runId); + return; + } + if (message.type === "shutdown") { + // Kill every running CLI process (claude, codex, gemini, etc.) and exit. + // This is the only reliable way to ensure child processes don't survive app quit, + // because the main process cannot kill grandchildren directly. + shutdownAllRunning(); + process.exit(0); } }); diff --git a/src/main/prompt-builder.ts b/src/main/prompt-builder.ts index 95139745..832662e4 100644 --- a/src/main/prompt-builder.ts +++ b/src/main/prompt-builder.ts @@ -33,6 +33,8 @@ interface PromptContext { allConnectors?: Array<{ id: string; label: string; status: string }>; /** D-07: Handoff markdown from a rotated session, injected as context for the agent */ sessionHandoff?: string | null; + /** Names of skills injected into this agent's runtime environment */ + skillNames?: string[]; } export function buildSystemPrompt(ctx: PromptContext): string { @@ -59,6 +61,7 @@ Today is ${dayOfWeek}, ${dateStr} at ${timeStr} UTC. You are ${ctx.agent.name}, a ${ctx.agent.role}${ctx.agent.title ? ` (${ctx.agent.title})` : ""} at ${ctx.companyName}. ${ctx.agent.capabilities ? `Your capabilities: ${ctx.agent.capabilities}` : ""} Your monthly budget: $${ctx.agent.budgetMonthlyUsd.toFixed(2)} | Spent this month: $${ctx.agent.spentMonthlyUsd.toFixed(2)}${ctx.agent.budgetMonthlyUsd > 0 ? ` (${Math.round((ctx.agent.spentMonthlyUsd / ctx.agent.budgetMonthlyUsd) * 100)}% used)` : ""} +${ctx.skillNames && ctx.skillNames.length > 0 ? `Your domain skills: ${ctx.skillNames.join(", ")}. These skills are loaded into your environment and provide domain expertise — use them when relevant to your work.` : ""} `); if (ctx.companyDescription) { @@ -711,6 +714,54 @@ Body: { ### List Company Documents GET /api/companies/${ctx.agent.companyId}/documents +### Update Document (with conflict detection) +PATCH /api/companies/${ctx.agent.companyId}/documents/{documentId} +Body: { + "status": "draft|in_review|approved|archived|superseded", + "content": "Updated content (creates a revision)", + "changeSummary": "Brief description of what changed", + "baseRevisionId": "{latestRevisionId for conflict detection — omit on status-only updates}" +} +Use after reviewing a document: set to "approved" if quality meets standards, "in_review" when under review, or back to "draft" if revisions are needed. +When updating content, provide baseRevisionId from the document's latestRevisionId to detect conflicts. + +### List Document Revisions +GET /api/companies/${ctx.agent.companyId}/documents/{documentId}/revisions + +### Comment on Approvals +POST /api/approvals/{approvalId}/comments +Body: { "body": "Your comment text. Use @AgentName to notify specific agents." } + +### Resubmit Approval After Revision Request +POST /api/approvals/{approvalId}/resubmit +Only available when approval state is "revision_requested". Resets to "pending" for re-review. + +### Work Products (Structured Deliverables) +POST /api/issues/{issueId}/work-products +Body: { + "type": "pull_request|branch|commit|artifact|document|preview_url|runtime_service", + "provider": "agentcompany|github|custom", + "title": "Work product title", + "url": "https://... (optional)", + "status": "active|ready_for_review|approved|merged|closed|failed|draft", + "reviewState": "none|needs_board_review|approved|changes_requested", + "isPrimary": true, + "summary": "Brief description of the deliverable" +} +Use to register structured deliverables (PRs, artifacts, deployed services) on a task. + +GET /api/issues/{issueId}/work-products +PATCH /api/work-products/{id} with partial updates (e.g. {"reviewState": "approved"}) +DELETE /api/work-products/{id} + +### Link Document to Task (Semantic Classification) +PUT /api/issues/{issueId}/documents/{key} +Body: { "documentId": "{existingDocumentId}" } +Key must be lowercase alphanumeric with _ or - (e.g. "plan", "spec", "design", "test-plan"). +Links a document to a task under a semantic key. One document per key per task. + +GET /api/issues/{issueId}/documents — list all linked documents for a task + ### Add Knowledge Entry (lessons learned, best practices) POST /api/companies/${ctx.agent.companyId}/knowledge Body: { @@ -989,15 +1040,29 @@ If there are NO active goals, this is your top priority — create strategic goa -d '{"title":"Goal title","description":"Measurable success criteria","ownerAgentId":"${ctx.agent.id}","status":"active"}' Then decompose each goal into projects, and each project into tasks assigned to department leads. -## Priority 2: Review Completed Work (SOP-004) +## Priority 2: Ensure All Agents Have Skills (SOP-002b) +Every agent needs domain skills to produce quality work. Check and fix immediately: +1. For EACH of your direct reports, check their skills: GET /api/agents/{agentId}/skills +2. If an agent has ZERO skills assigned, this is urgent — assign skills NOW: + a. GET /api/companies/${ctx.agent.companyId}/skills to list available skills + b. For each skill matching the agent's role: POST /api/agents/{agentId}/skills with {"skillId": ""} + c. Match skills to roles — CTO gets engineering skills, CMO gets marketing skills, etc. +3. This MUST happen before delegating any work — agents without skills produce poor output + +## Priority 3: Review Completed Work (SOP-004) When tasks from your reports have status "in_review": - Read ALL comments on the task to understand what was done -- If satisfactory: PATCH /api/issues/{issueId} with status "done" + approving comment -- If changes needed: PATCH /api/issues/{issueId} with status "in_progress" + detailed, specific feedback +- Review any documents the agent created: GET /api/companies/${ctx.agent.companyId}/documents +- If satisfactory: + - PATCH /api/issues/{issueId} with status "done" + approving comment + - Update document status: PATCH /api/companies/${ctx.agent.companyId}/documents/{documentId} with {"status": "approved"} +- If changes needed: + - PATCH /api/issues/{issueId} with status "in_progress" + detailed, specific feedback + - Update document status: PATCH /api/companies/${ctx.agent.companyId}/documents/{documentId} with {"status": "draft"} - This is YOUR HIGHEST PRIORITY after standup — reviews unblock your entire team - NEVER let review requests sit — they cascade-block everyone downstream -## Priority 3: Goal Decomposition & Delegation (SOP-003) +## Priority 4: Goal Decomposition & Delegation (SOP-003) When you have active goals without projects or tasks: 1. Create a project for each major workstream: POST /api/companies/${ctx.agent.companyId}/projects with goalId, leadAgentId, description @@ -1018,14 +1083,14 @@ When you have active goals without projects or tasks: 6. Wake the assigned agents so they start immediately: POST /api/agents/{agentId}/wake with reason explaining the new assignment -## Priority 4: Unblock & Coordinate +## Priority 5: Unblock & Coordinate - Review blocked tasks: read the blocker comments and take action - For credential needs: create secret_access approvals via POST /api/companies/${ctx.agent.companyId}/approvals - For cross-department dependencies: send direct messages to the relevant department lead - For Board-level decisions: create an approval with clear context and options - Review failed runs from your reports: check what went wrong and decide whether to retry or reassign -## Priority 5: Grow the Team +## Priority 6: Grow the Team When workload exceeds capacity or new capabilities are needed: - Assess: count open tasks vs active agents per department - If a department is overloaded: propose hiring via POST /api/companies/${ctx.agent.companyId}/agents @@ -1033,7 +1098,7 @@ When workload exceeds capacity or new capabilities are needed: - Each hire needs: clear role, specific capabilities, budget justification, department assignment - After hire approval, create onboarding tasks for the new agent -## Priority 6: Strategic Communication & Reporting +## Priority 7: Strategic Communication & Reporting - Schedule all-hands meetings when major milestones are reached: POST /api/companies/${ctx.agent.companyId}/meetings with type "all_hands" - Create status_report documents summarizing company progress: diff --git a/src/main/service-graph.ts b/src/main/service-graph.ts index faf75c30..f6b572ae 100644 --- a/src/main/service-graph.ts +++ b/src/main/service-graph.ts @@ -2,7 +2,7 @@ import { app } from "electron"; import type { AgentApiServer } from "./api-server"; import type { AppDatabase } from "./database"; import { BrowserManager } from "./browser-manager"; -import { createAutomationService } from "./automation-service"; +import { createAutomationService, autoAssignSkillsToAgent } from "./automation-service"; import { createBrowserActionService } from "./browser-action-service"; import { createConnectorHealthService } from "./connector-health-service"; import { createDesktopShellService } from "./desktop-shell-service"; @@ -241,6 +241,22 @@ export function createServiceGraph({ return null; } }, + evaluatePreRunSessionRotation: (taskId: string, connectorId: string) => { + try { + const sessionSvc = getOrCreateSessionManagementService(); + const activeSession = db.getActiveTaskSession(taskId); + if (!activeSession) return { rotated: false, handoff: null }; + const result = sessionSvc.evaluateRotation(activeSession, connectorId); + if (result.shouldRotate) { + sessionSvc.rotateSession(activeSession); + const handoff = sessionSvc.getHandoffContext(taskId); + return { rotated: true, handoff }; + } + return { rotated: false, handoff: null }; + } catch { + return { rotated: false, handoff: null }; + } + }, }); workerService.createWorker(); @@ -260,6 +276,11 @@ export function createServiceGraph({ seedDefaultAutomationRules, queueTaskRun, publishDomainChanged, + scanAndAssignSkills: async (companyId: string, agentId: string) => { + const svc = getOrCreateSkillService(); + await svc.scanWorkspaceSkills(companyId); + autoAssignSkillsToAgent(db, logger, companyId, agentId); + }, }); browserActionService = createBrowserActionService({ diff --git a/src/main/skill-format.ts b/src/main/skill-format.ts index c3448b18..1a3949a5 100644 --- a/src/main/skill-format.ts +++ b/src/main/skill-format.ts @@ -1,15 +1,6 @@ -// --------------------------------------------------------------------------- -// SKILL.md format parser, inventory classifier, and trust level derivation -// --------------------------------------------------------------------------- - import { extname } from "node:path"; import type { FileInventoryEntry, TrustLevel } from "./skill-types.js"; -// --------------------------------------------------------------------------- -// Minimal YAML frontmatter parsing (no external YAML library) -// Follows the Paperclip reference pattern for SKILL.md files. -// --------------------------------------------------------------------------- - function isPlainRecord(value: unknown): value is Record { return typeof value === "object" && value !== null && !Array.isArray(value); } @@ -137,10 +128,6 @@ function parseYamlFrontmatter(raw: string): Record { return isPlainRecord(parsed.value) ? parsed.value : {}; } -// --------------------------------------------------------------------------- -// Public API -// --------------------------------------------------------------------------- - /** * Parse a SKILL.md file with optional YAML frontmatter. * Normalizes CRLF to LF before parsing. diff --git a/src/main/skill-github.ts b/src/main/skill-github.ts index 36c46a72..01172422 100644 --- a/src/main/skill-github.ts +++ b/src/main/skill-github.ts @@ -1,9 +1,3 @@ -// --------------------------------------------------------------------------- -// GitHub REST API skill fetcher -- imports skills without git clone (D-02) -// Public repos only (D-03). Uses raw.githubusercontent.com for content -// downloads (does not count against API rate limits per research). -// --------------------------------------------------------------------------- - /** * Data returned for each skill found in a GitHub repository. */ @@ -21,10 +15,6 @@ interface Logger { error: (...args: unknown[]) => void; } -// --------------------------------------------------------------------------- -// Commit SHA resolution -// --------------------------------------------------------------------------- - /** * Resolve the latest commit SHA for a given ref (branch, tag, or HEAD). * Returns the 40-character hex SHA on success, null on error. @@ -61,10 +51,6 @@ export async function resolveGitHubCommitSha( } } -// --------------------------------------------------------------------------- -// GitHub tree + SKILL.md fetcher -// --------------------------------------------------------------------------- - /** * Fetch all SKILL.md files from a GitHub repository via the REST API. * diff --git a/src/main/skill-keys.ts b/src/main/skill-keys.ts index 15ae0510..27ecb2db 100644 --- a/src/main/skill-keys.ts +++ b/src/main/skill-keys.ts @@ -1,15 +1,7 @@ -// --------------------------------------------------------------------------- -// Canonical skill key derivation and skill import source resolution -// --------------------------------------------------------------------------- - import { createHash } from "node:crypto"; import { resolve } from "node:path"; import type { SkillSourceType } from "./skill-types.js"; -// --------------------------------------------------------------------------- -// Slug normalization helpers -// --------------------------------------------------------------------------- - const SLUG_DELIM_RE = /[^a-z0-9]+/g; const SLUG_TRIM_RE = /^-+|-+$/g; @@ -30,10 +22,6 @@ export function normalizeSkillSlug( return normalized.length > 0 ? normalized : null; } -// --------------------------------------------------------------------------- -// Hashing -// --------------------------------------------------------------------------- - /** * Compute the first 10 characters of a SHA-256 hex digest. * Used for hash segments in canonical keys. @@ -42,10 +30,6 @@ export function hashSkillValue(value: string): string { return createHash("sha256").update(value).digest("hex").slice(0, 10); } -// --------------------------------------------------------------------------- -// Canonical key derivation -// --------------------------------------------------------------------------- - function asString(value: unknown): string | null { return typeof value === "string" && value.length > 0 ? value : null; } @@ -113,10 +97,6 @@ export function deriveCanonicalSkillKey( return `company/${companyId}/${slug}`; } -// --------------------------------------------------------------------------- -// Skill import source resolution -// --------------------------------------------------------------------------- - // Three-part key: org/repo/skill const THREE_PART_KEY_RE = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/; diff --git a/src/main/skill-service.ts b/src/main/skill-service.ts index 7e227295..a949f890 100644 --- a/src/main/skill-service.ts +++ b/src/main/skill-service.ts @@ -1,7 +1,5 @@ -// --------------------------------------------------------------------------- // SkillService -- full skill lifecycle: import, CRUD, assignment, token budget, // update detection. Factory pattern following createOrchestrationService. -// --------------------------------------------------------------------------- import { randomUUID } from "node:crypto"; import { existsSync, mkdirSync, readdirSync, readFileSync, statSync } from "node:fs"; @@ -35,10 +33,7 @@ import { } from "./skill-github.js"; import { TOKEN_BUDGETS } from "./skill-types.js"; -// --------------------------------------------------------------------------- // Types -// --------------------------------------------------------------------------- - interface SkillServiceDependencies { db: AppDatabase; profileDir: string; @@ -49,10 +44,7 @@ interface SkillServiceDependencies { }; } -// --------------------------------------------------------------------------- // Factory -// --------------------------------------------------------------------------- - export function createSkillService({ db, profileDir, logger }: SkillServiceDependencies) { // ---- Result helpers ---- function ok(data: T): DesktopResult { @@ -75,8 +67,6 @@ export function createSkillService({ db, profileDir, logger }: SkillServiceDepen return join(skillsRoot(companyId), "__runtime__"); } - // ---- File materialization helpers ---- - /** * Write SKILL.md (and tracked inventory files from GitHub downloads) * to the local skill directory. @@ -101,8 +91,6 @@ export function createSkillService({ db, profileDir, logger }: SkillServiceDepen } } - // ---- GitHub URL parser ---- - function parseGitHubUrl(url: string): { owner: string; repo: string } | null { try { const parsed = new URL(url); @@ -118,8 +106,6 @@ export function createSkillService({ db, profileDir, logger }: SkillServiceDepen } } - // ---- Import routing ---- - /** * Import skills from any supported source. * Routes to the correct handler based on parseSkillImportSource. @@ -178,8 +164,6 @@ export function createSkillService({ db, profileDir, logger }: SkillServiceDepen } } - // ---- GitHub import (SKILL-01) ---- - async function importFromGitHub( companyId: string, url: string, @@ -296,8 +280,6 @@ export function createSkillService({ db, profileDir, logger }: SkillServiceDepen return results; } - // ---- Local path import (SKILL-02, D-04) ---- - async function importFromLocal( companyId: string, localPath: string, @@ -416,8 +398,6 @@ export function createSkillService({ db, profileDir, logger }: SkillServiceDepen return results; } - // ---- URL import (SKILL-03, D-05) ---- - async function importFromUrl( companyId: string, url: string, @@ -487,8 +467,6 @@ export function createSkillService({ db, profileDir, logger }: SkillServiceDepen return results; } - // ---- CRUD ---- - function listForCompany(companyId: string): SkillRecord[] { return db.listCompanySkills(companyId); } @@ -522,8 +500,6 @@ export function createSkillService({ db, profileDir, logger }: SkillServiceDepen } } - // ---- Agent assignment (SKILL-07) ---- - function assignToAgent( companyId: string, agentId: string, @@ -544,8 +520,6 @@ export function createSkillService({ db, profileDir, logger }: SkillServiceDepen return ok(undefined); } - // ---- Update detection (SKILL-11, D-11) ---- - async function checkUpdateStatus( companyId: string, skillId: string, @@ -603,8 +577,6 @@ export function createSkillService({ db, profileDir, logger }: SkillServiceDepen }); } - // ---- Runtime skill entries (SKILL-09 token budget) ---- - /** * Build the list of RuntimeSkillEntry for adapter injection. * Applies token budget enforcement: skills sorted by creation date, @@ -617,12 +589,7 @@ export function createSkillService({ db, profileDir, logger }: SkillServiceDepen ): RuntimeSkillEntry[] { const allSkills = db.listCompanySkills(companyId); const agentAssignments = db.listAgentSkillAssignments(agentId); - - // If agent has specific assignments, filter to those; otherwise use all - const skills = - agentAssignments.length > 0 - ? allSkills.filter((s) => agentAssignments.includes(s.id)) - : allSkills; + const skills = allSkills.filter((s) => agentAssignments.includes(s.id)); // Sort by creation date (oldest first -- first imported gets priority) const sorted = [...skills].sort( @@ -653,8 +620,6 @@ export function createSkillService({ db, profileDir, logger }: SkillServiceDepen return entries; } - // ---- Local directory walker ---- - function findSkillMdFiles(rootDir: string): string[] { const found: string[] = []; function walk(dir: string) { @@ -701,8 +666,6 @@ export function createSkillService({ db, profileDir, logger }: SkillServiceDepen return inventory; } - // ---- Workspace .agents/skills/ scanning (Bug 6) ---- - /** * Scan all workspace local paths for a company, looking for * `.agents/skills/` directories containing SKILL.md files. @@ -761,8 +724,6 @@ export function createSkillService({ db, profileDir, logger }: SkillServiceDepen return allResults; } - // ---- Public API ---- - return { importFromSource, importFromGitHub, diff --git a/src/main/skill-types.ts b/src/main/skill-types.ts index 43cfe4f1..9186cd16 100644 --- a/src/main/skill-types.ts +++ b/src/main/skill-types.ts @@ -1,7 +1,3 @@ -// --------------------------------------------------------------------------- -// Skill system type definitions and constants -// --------------------------------------------------------------------------- - /** * Source type for a skill -- matches the company_skills.source_type column. */ diff --git a/src/main/task-quality-gates.ts b/src/main/task-quality-gates.ts index 4e0e61d1..3f1b8e28 100644 --- a/src/main/task-quality-gates.ts +++ b/src/main/task-quality-gates.ts @@ -5,10 +5,6 @@ * minimum description quality, acceptance criteria, and capability matching. */ -// --------------------------------------------------------------------------- -// Types -// --------------------------------------------------------------------------- - export interface TaskValidationResult { valid: boolean; errors: string[]; @@ -28,9 +24,6 @@ export interface CapabilityMatchDb { getCompanySkill?(companyId: string, skillId: string): { name: string; description: string | null; slug: string } | null; } -// --------------------------------------------------------------------------- -// Constants -// --------------------------------------------------------------------------- const MIN_DESCRIPTION_LENGTH = 50; @@ -49,9 +42,6 @@ export const ACCEPTANCE_CRITERIA_KEYWORDS: readonly string[] = [ "exit criteria", ]; -// --------------------------------------------------------------------------- -// checkAcceptanceCriteria -// --------------------------------------------------------------------------- export function checkAcceptanceCriteria(description: string): { hasCriteria: boolean; suggestion: string } { const lower = description.toLowerCase(); @@ -68,9 +58,6 @@ export function checkAcceptanceCriteria(description: string): { hasCriteria: boo }; } -// --------------------------------------------------------------------------- -// validateTaskCreation -// --------------------------------------------------------------------------- export function validateTaskCreation( input: { title: string; description: string }, @@ -102,9 +89,6 @@ export function validateTaskCreation( return { valid: errors.length === 0, errors, warnings }; } -// --------------------------------------------------------------------------- -// checkCapabilityMatch -// --------------------------------------------------------------------------- /** Tokenize text into words >3 chars, same pattern as database.ts autoAssignTask */ function tokenize(text: string): string[] { @@ -162,9 +146,6 @@ export function checkCapabilityMatch( }; } -// --------------------------------------------------------------------------- -// TASK-04: Stale Review Escalation -// --------------------------------------------------------------------------- export const REVIEW_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes (D-08) diff --git a/src/main/worker-service.ts b/src/main/worker-service.ts index 9d6ec473..0dc9b0b3 100644 --- a/src/main/worker-service.ts +++ b/src/main/worker-service.ts @@ -498,25 +498,46 @@ export function createWorkerService({ pendingRetryTimers.clear(); if (worker) { - // Cancel all running/queued runs in the worker before killing it. - // This tells the worker to SIGTERM all child CLI processes (claude, codex, etc.) - const snapshot = db.listSnapshot(); - for (const run of snapshot.runs) { - if (run.status === "running" || run.status === "queued") { - try { - worker.postMessage({ type: "cancel-run", runId: run.id }); - } catch { /* worker may already be dead */ } - } - } + // Tell the worker to kill all its child CLI processes and exit. + // Previous approach sent individual cancel-run messages then immediately + // killed the worker — a race condition that left CLI processes as orphans + // because the worker died before it could forward SIGTERM to its children. + try { + worker.postMessage({ type: "shutdown" }); + } catch { /* worker may already be dead */ } - worker.kill(); - // Force-kill after 2s if SIGTERM didn't work (child CLI processes may keep it alive) + // Safety net: force-kill worker after 2s if shutdown didn't complete const ref = worker; setTimeout(() => { try { ref.kill(); } catch { /* already dead */ } }, 2000); worker = null; } + + // Mark all running/queued runs as interrupted so DB state is clean on restart + try { + const snapshot = db.listSnapshot(); + for (const run of snapshot.runs) { + if (run.status === "running" || run.status === "queued") { + db.finishRun({ + runId: run.id, + status: "interrupted", + summary: "Application shut down.", + errorMessage: null, + exitCode: null, + signal: null, + model: null, + sessionDisplayId: null, + costUsd: null, + unattributedCost: true, + }); + if (run.workspaceId) { + db.releaseWorkspaceLock(run.workspaceId, run.id); + } + db.releaseTaskLock(run.taskId, run.id); + } + } + } catch { /* best effort during shutdown */ } } return { diff --git a/src/preload/index.ts b/src/preload/index.ts index 2f4ce660..042a149c 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -51,6 +51,8 @@ const api: DesktopApi = { getAgentMetrics: (input) => ipcRenderer.invoke(IPC_CHANNELS.getAgentMetrics, input), getStandupReport: (companyId) => ipcRenderer.invoke(IPC_CHANNELS.getStandupReport, companyId), bootstrapOnboarding: (input) => ipcRenderer.invoke(IPC_CHANNELS.bootstrapOnboarding, input), + checkNodeInstalled: () => ipcRenderer.invoke(IPC_CHANNELS.checkNodeInstalled), + openTerminalCommand: (input) => ipcRenderer.invoke(IPC_CHANNELS.openTerminalCommand, input), saveSocialAccount: (input) => ipcRenderer.invoke(IPC_CHANNELS.saveSocialAccount, input), deleteSocialAccount: (input) => ipcRenderer.invoke(IPC_CHANNELS.deleteSocialAccount, input), listBrowserActions: (input) => ipcRenderer.invoke(IPC_CHANNELS.listBrowserActions, input), @@ -118,6 +120,11 @@ const api: DesktopApi = { ipcRenderer.removeListener(IPC_CHANNELS.rendererEvent, listener); }; }, + platform: process.platform as "win32" | "darwin" | "linux", + windowMinimize: () => ipcRenderer.invoke("window:minimize"), + windowMaximize: () => ipcRenderer.invoke("window:maximize"), + windowClose: () => ipcRenderer.invoke("window:close"), + windowIsMaximized: () => ipcRenderer.invoke("window:isMaximized") as Promise, }; contextBridge.exposeInMainWorld("agentCompany", api); diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index 4270da9b..48924b61 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -5,7 +5,6 @@ import { ChatCircle, Check, Command, - Cpu, FileText, FolderOpen, Gear, @@ -53,6 +52,7 @@ import { PendingReviewList, SecretCreator, SettingsPane, + ModelManagement, TaskCreator, TaskInspector, TaskQueue, @@ -81,6 +81,7 @@ import { HiringPipeline } from "./components/hiring"; import { SkillsSection } from "./components/skills"; import { DocumentCenter, KnowledgeBaseManager, MeetingsManager, SprintManager } from "./components/company-operations"; import { ActionButton, ErrorBoundary, ListFrame, ListRow, Modal, Panel, SectionButton, Select, StatusPill, useFocusTrap, useReducedMotion } from "./components/ui"; +import TitleBar from "./components/TitleBar"; import ToastContainer from "./components/Toast"; import { unwrap } from "./lib/desktop"; import { formatMoney, formatTime } from "./lib/formatters"; @@ -688,13 +689,18 @@ export function App() { } }, [refresh]); + const showCustomTitleBar = window.agentCompany.platform !== "darwin"; + if (!snapshot) { return ( -

- - {t("app.loading")} +
+ {showCustomTitleBar && } +
+ + {t("app.loading")} +
@@ -705,31 +711,40 @@ export function App() { return ( - 0 && !initialOnboardingLocked} - onCancel={() => { - setShowOnboarding(false); - setInitialOnboardingLocked(false); - setError(null); - }} - currentLocale={locale} - onLocaleChange={handleLocaleChange} - isFirstLaunch={snapshot.companies.length === 0} - /> +
+ {showCustomTitleBar && } +
+ 0 && !initialOnboardingLocked} + onCancel={() => { + setShowOnboarding(false); + setInitialOnboardingLocked(false); + setError(null); + }} + currentLocale={locale} + onLocaleChange={handleLocaleChange} + isFirstLaunch={snapshot.companies.length === 0} + /> +
+
); } + const isMac = !showCustomTitleBar; + return ( -
-